diff --git a/Ghidra/Extensions/SleighDevTools/pcodetest/pcode_defs.py b/Ghidra/Extensions/SleighDevTools/pcodetest/pcode_defs.py index 827aae690e..b15ac99879 100644 --- a/Ghidra/Extensions/SleighDevTools/pcodetest/pcode_defs.py +++ b/Ghidra/Extensions/SleighDevTools/pcodetest/pcode_defs.py @@ -689,3 +689,22 @@ PCodeTest({ 'has_double': 0, 'has_longlong': 0, }) + +PCodeTest({ + 'name': 'Xtensa_LE', + 'build_all': 1, + 'build_exe': 1, + 'toolchain': 'Xtensa/xtensa-esp32-elf', + 'language_id': 'Xtensa:LE:32:default', + 'gcc_version' : '8.4.0', + 'ccflags': '-L %(toolchain_dir)s/lib/gcc/xtensa-esp32-elf/%(gcc_version)s', +}) + +PCodeTest({ + 'name': 'Xtensa_BE', + 'build_all': 1, + 'build_exe': 1, + 'toolchain': 'Xtensa/xtensa-elf', + 'language_id': 'Xtensa:BE:32:default', + 'ccflags': '-L %(toolchain_dir)s/lib/gcc/xtensa-elf/%(gcc_version)s', +}) diff --git a/Ghidra/Processors/Xtensa/Module.manifest b/Ghidra/Processors/Xtensa/Module.manifest new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Ghidra/Processors/Xtensa/build.gradle b/Ghidra/Processors/Xtensa/build.gradle new file mode 100644 index 0000000000..b52d6e1866 --- /dev/null +++ b/Ghidra/Processors/Xtensa/build.gradle @@ -0,0 +1,29 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +apply from: "$rootProject.projectDir/gradle/distributableGhidraModule.gradle" +apply from: "$rootProject.projectDir/gradle/javaProject.gradle" +apply from: "$rootProject.projectDir/gradle/javaTestProject.gradle" +apply from: "$rootProject.projectDir/gradle/processorProject.gradle" +apply plugin: 'eclipse' +eclipse.project.name = 'Processors Xtensa' + +dependencies { + api project(':Base') +} + +sleighCompileOptions = [ + "-l" +] diff --git a/Ghidra/Processors/Xtensa/certification.manifest b/Ghidra/Processors/Xtensa/certification.manifest new file mode 100644 index 0000000000..11a527af56 --- /dev/null +++ b/Ghidra/Processors/Xtensa/certification.manifest @@ -0,0 +1,18 @@ +##VERSION: 2.0 +Module.manifest||GHIDRA||||END| +data/languages/cust.sinc||GHIDRA||||END| +data/languages/flix.sinc||GHIDRA||||END| +data/languages/xtensa.cspec||GHIDRA||||END| +data/languages/xtensa.dwarf||GHIDRA||||END| +data/languages/xtensa.ldefs||GHIDRA||||END| +data/languages/xtensa.opinion||GHIDRA||||END| +data/languages/xtensa.pspec||GHIDRA||||END| +data/languages/xtensaArch.sinc||GHIDRA||||END| +data/languages/xtensaInstructions.sinc||GHIDRA||||END| +data/languages/xtensaMain.sinc||GHIDRA||||END| +data/languages/xtensa_be.slaspec||GHIDRA||||END| +data/languages/xtensa_depbits.sinc||GHIDRA||||END| +data/languages/xtensa_le.slaspec||GHIDRA||||END| +data/manuals/xtensa.idx||GHIDRA||||END| +data/patterns/patternconstraints.xml||GHIDRA||||END| +data/patterns/xtensa_patterns.xml||GHIDRA||||END| diff --git a/Ghidra/Processors/Xtensa/data/languages/cust.sinc b/Ghidra/Processors/Xtensa/data/languages/cust.sinc new file mode 100644 index 0000000000..dc54f28bbe --- /dev/null +++ b/Ghidra/Processors/Xtensa/data/languages/cust.sinc @@ -0,0 +1,17 @@ +# Per the manual: +# CUST0 and CUST1 opcode encodings shown in Table 7–193 are permanently reserved +# for designer-defined opcodes. In the future, customers who use these spaces +# exclusively for their own designer-defined opcodes will be able to add new +# Tensilica-defined options without changing their opcodes or binary executables. + +define pcodeop cust0; + +:cust0 "{op2="^op2^", r="^ar^", s="^as^", t="^at^"}" is op0=0x0 & op1=0x6 & op2 & ar & as & at { + cust0(); +} + +define pcodeop cust1; + +:cust1 "{op2="^op2^", r="^ar^", s="^as^", t="^at^"}" is op0=0x0 & op1=0x7 & op2 & ar & as & at { + cust1(); +} \ No newline at end of file diff --git a/Ghidra/Processors/Xtensa/data/languages/flix.sinc b/Ghidra/Processors/Xtensa/data/languages/flix.sinc new file mode 100644 index 0000000000..f012f83992 --- /dev/null +++ b/Ghidra/Processors/Xtensa/data/languages/flix.sinc @@ -0,0 +1,9 @@ + +# FLIX (Flexible Length Instruction eXtension) is a Xtensa processor extension +# that allows for variable-length, multi-op instructions with support from 4 +# 16 bytes. Customizable, if found they should be flagged. + +define pcodeop flix; +:FLIX u_4_23 is op0=0xe & u_4_23 { + flix(); +} \ No newline at end of file diff --git a/Ghidra/Processors/Xtensa/data/languages/xtensa.cspec b/Ghidra/Processors/Xtensa/data/languages/xtensa.cspec new file mode 100644 index 0000000000..e4a40899e8 --- /dev/null +++ b/Ghidra/Processors/Xtensa/data/languages/xtensa.cspec @@ -0,0 +1,260 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Ghidra/Processors/Xtensa/data/languages/xtensa.dwarf b/Ghidra/Processors/Xtensa/data/languages/xtensa.dwarf new file mode 100644 index 0000000000..1790648cff --- /dev/null +++ b/Ghidra/Processors/Xtensa/data/languages/xtensa.dwarf @@ -0,0 +1,7 @@ + + + + + + + diff --git a/Ghidra/Processors/Xtensa/data/languages/xtensa.ldefs b/Ghidra/Processors/Xtensa/data/languages/xtensa.ldefs new file mode 100644 index 0000000000..295fea8ef0 --- /dev/null +++ b/Ghidra/Processors/Xtensa/data/languages/xtensa.ldefs @@ -0,0 +1,32 @@ + + + + + Tensilica Xtensa 32-bit little-endian + + + + + + Tensilica Xtensa 32-bit big-endian + + + + + diff --git a/Ghidra/Processors/Xtensa/data/languages/xtensa.opinion b/Ghidra/Processors/Xtensa/data/languages/xtensa.opinion new file mode 100644 index 0000000000..1e6ce11602 --- /dev/null +++ b/Ghidra/Processors/Xtensa/data/languages/xtensa.opinion @@ -0,0 +1,6 @@ + + + + + + diff --git a/Ghidra/Processors/Xtensa/data/languages/xtensa.pspec b/Ghidra/Processors/Xtensa/data/languages/xtensa.pspec new file mode 100644 index 0000000000..721b2e437a --- /dev/null +++ b/Ghidra/Processors/Xtensa/data/languages/xtensa.pspec @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/Ghidra/Processors/Xtensa/data/languages/xtensaArch.sinc b/Ghidra/Processors/Xtensa/data/languages/xtensaArch.sinc new file mode 100644 index 0000000000..526f5bc590 --- /dev/null +++ b/Ghidra/Processors/Xtensa/data/languages/xtensaArch.sinc @@ -0,0 +1,433 @@ +define endian=$(ENDIAN); +define alignment=1; + +define space ram type=ram_space size=4 default; +define space register type=register_space size=4; + +# Address registers (AR). +define register offset=0x0000 size=4 [ + a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 a14 a15 +]; + +# Temporary Address registers (facilitates simplified CALL register swapping used by decompiler) +define register offset=0x0080 size=4 [ + t0 t1 t2 t3 t4 t5 t6 t7 t8 t9 t10 t11 +]; + +# Floating Point registers +define register offset=0x0100 size=4 [ + f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 f10 f11 f12 f13 f14 f15 +]; + +# Boolean registers (BR) +define register offset=0x0200 size=1 [ + b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 b10 b11 b12 b13 b14 b15 +]; + +define register offset=0x0400 size=4 [ +user0 user1 user2 user3 user4 user5 user6 user7 user8 user9 user10 user11 user12 user13 user14 user15 +user16 user17 user18 user19 user20 user21 user22 user23 user24 user25 user26 user27 user28 user29 user30 user31 +user32 user33 user34 user35 user36 user37 user38 user39 user40 user41 user42 user43 user44 user45 user46 user47 +user48 user49 user50 user51 user52 user53 user54 user55 user56 user57 user58 user59 user60 user61 user62 user63 +user64 user65 user66 user67 user68 user69 user70 user71 user72 user73 user74 user75 user76 user77 user78 user79 +user80 user81 user82 user83 user84 user85 user86 user87 user88 user89 user90 user91 user92 user93 user94 user95 +user96 user97 user98 user99 user100 user101 user102 user103 user104 user105 user106 user107 user108 user109 user110 user111 +user112 user113 user114 user115 user116 user117 user118 user119 user120 user121 user122 user123 user124 user125 user126 user127 +user128 user129 user130 user131 user132 user133 user134 user135 user136 user137 user138 user139 user140 user141 user142 user143 +user144 user145 user146 user147 user148 user149 user150 user151 user152 user153 user154 user155 user156 user157 user158 user159 +user160 user161 user162 user163 user164 user165 user166 user167 user168 user169 user170 user171 user172 user173 user174 user175 +user176 user177 user178 user179 user180 user181 user182 user183 user184 user185 user186 user187 user188 user189 user190 user191 +user192 user193 user194 user195 user196 user197 user198 user199 user200 user201 user202 user203 user204 user205 user206 user207 +user208 user209 user210 user211 user212 user213 user214 user215 user216 user217 user218 user219 user220 user221 user222 user223 +user224 user225 user226 user227 user228 user229 user230 THREADPTR FCR FSR user234 user235 user236 user237 user238 user239 +user240 user241 user242 user243 user244 user245 user246 user247 user248 user249 user250 user251 user252 user253 user254 user255 +]; + +# Program counter. +define register offset=0x1000 size=4 [ pc ]; + +define register offset=0x2000 size=4 [ + LBEG LEND LCOUNT SAR BR LITBASE sr6 sr7 sr8 sr9 sr10 sr11 SCOMPARE1 sr13 sr14 sr15 +@if ENDIAN == "big" +ACCHI ACCLO +@else +ACCLO ACCHI +@endif + sr18 sr19 sr20 sr21 sr22 sr23 sr24 sr25 sr26 sr27 sr28 sr29 sr30 sr31 + M0 M1 M2 M3 sr36 sr37 sr38 sr39 sr40 sr41 sr42 sr43 sr44 sr45 sr46 sr47 + sr48 sr49 sr50 sr51 sr52 sr53 sr54 sr55 sr56 sr57 sr58 sr59 sr60 sr61 sr62 sr63 + sr64 sr65 sr66 sr67 sr68 sr69 sr70 sr71 WindowBase WindowStart sr74 sr75 sr76 sr77 sr78 sr79 + sr80 sr81 sr82 PTEVADDR sr84 sr85 sr86 sr87 sr88 MMID RASID ITLBCFG DTLBCFG sr93 sr94 sr95 + IBREAKENABLE MEMCTL CACHEATTR ATOMCTL sr100 sr101 sr102 sr103 DDR sr105 MEPC MEPS MESAVE MESR MECR MEVADDR + sr112 sr113 sr114 sr115 sr116 sr117 sr118 sr119 sr120 sr121 sr122 sr123 sr124 sr125 sr126 sr127 + IBREAKA0 IBREAKA1 sr130 sr131 sr132 sr133 sr134 sr135 sr136 sr137 sr138 sr139 sr140 sr141 sr142 sr143 + DBREAKA0 DBREAKA1 sr146 sr147 sr148 sr149 sr150 sr151 sr152 sr153 sr154 sr155 sr156 sr157 sr158 sr159 + DBREAKC0 DBREAKC1 sr162 sr163 sr164 sr165 sr166 sr167 sr168 sr169 sr170 sr171 sr172 sr173 sr174 sr175 + sr176 EPC1 EPC2 EPC3 EPC4 EPC5 EPC6 EPC7 sr184 sr185 sr186 sr187 sr188 sr189 sr190 sr191 + DEPC sr193 EPS2 EPS3 EPS4 EPS5 EPS6 EPS7 sr200 sr201 sr202 sr203 sr204 sr205 sr206 sr207 + sr208 EXCSAVE1 EXCSAVE2 EXCSAVE3 EXCSAVE4 EXCSAVE5 EXCSAVE6 EXCSAVE7 sr216 sr217 sr218 sr219 sr220 sr221 sr222 sr223 +#TODO: REVIEW NEEDED! - INTSET / INTERRUPT placement/address (also review related attach) + CPENABLE INTERRUPT INTSET INTCLEAR INTENABLE sr229 PS VECBASE EXCCAUSE DEBUGCAUSE CCOUNT PRID ICOUNT ICOUNTLEVEL EXCVADDR sr239 + CCOMPARE0 CCOMPARE1 CCOMPARE2 sr243 MISC0 MISC1 MISC2 MISC3 sr248 sr249 sr250 sr251 sr252 sr253 sr254 sr255 +]; + +define register offset=0x2040 size=8 [ ACC ]; + +@define EPC_BASE "0x22c0" #address of EPCn = $(EPC_BASE) + (n * 4) +@define EPS_BASE "0x2300" #address of EPSn = $(EPS_BASE) + (n * 4) + +@define PS_INTLEVEL "PS[0,4]" +@define PS_EXCM "PS[4,1]" +@define PS_UM "PS[5,1]" +@define PS_RING "PS[6,2]" +@define PS_OWB "PS[8,4]" +@define PS_CALLINC "PS[12,2]" +@define PS_WOE "PS[14,1]" + + +define register offset=0xf000 size=4 contextreg; +define context contextreg + loopMode=(0,0) + loopEnd=(1,1) noflow + + #transient bits + phase=(31,31) +; + +@if ENDIAN == "big" + +# little-endian -> big-endian 24-bit conversion chart +#|00|01|02|03|04|05|06|07|08|09|10|11|12|13|14|15|16|17|18|19|20|21|22|23| +#|23|22|21|20|19|18|17|16|15|14|13|12|11|10|09|08|07|06|05|04|03|02|01|00| + +# Regular 24-bit instruction. +define token insn(24) + # Named opcode/register fields. + op2 = (0,3) + op1 = (4,7) + ar = (8,11) + fr = (8,11) + br = (8,11) + as = (12,15) + fs = (12,15) + bs = (12,15) + sr = (8,15) + at = (16,19) + ft = (16,19) + bt = (16,19) + op0 = (20,23) + + # Signed and unsigned immediates. Named [us]N_L.M, where u and s denote signedness, L and M the + # least and most significant bit of the immediate in the instruction word, and N the length + # (i.e. M-L+1). + u3_21_23 = (0,2) + u4_20_23 = (0,3) + s8_16_23 = (0,7) signed + u8_16_23 = (0,7) + u12_12_23 = (0,11) + s12_12_23 = (0,11) signed + u16_8_23 = (0,15) + s8_6_23 = (0,17) signed + u1_20 = (3,3) + u2_18_19 = (4,5) + u3_17_19 = (4,6) + u2_16_17 = (6,7) + u1_16 = (7,7) + u1_15_15 = (8,8) + u2_14_15 = (8,9) + u3_13_15 = (8,10) + u4_12_15 = (8,11) + m0m1_14_14 = (9,9) + u2_12_13 = (10,11) + mw_12_13 = (10,11) + u1_12 = (11,11) + u4_8_11 = (12,15) + u8_4_11 = (12,19) + s4_8_11 = (12,15) signed + u1_7_7 = (16,16) + u2_6_7 = (16,17) + u3_5_7 = (16,18) + u4_4_7 = (16,19) + s4_4_7 = (16,19) + m2m3_6_6 = (17,17) + u_4_23 = (0,19) + u2_4_5 = (18,19) + u1_4 = (19,19) +; + +# little-endian -> big-endian 16-bit conversion chart +#|00|01|02|03|04|05|06|07|08|09|10|11|12|13|14|15| +#|15|14|13|12|11|10|09|08|07|06|05|04|03|02|01|00| + +# Narrow 16-bit instructions; fields are always prefixed with n_. +define token narrowinsn(16) + n_ar = (0,3) + n_as = (4,7) + n_at = (8,11) + n_op0 = (12,15) + + n_u4_12_15 = (0,3) + n_s4_12_15 = (0,3) signed + n_u4_8_11 = (4,7) + n_u1_7 = (8,8) + n_u2_6_7 = (8,9) + n_u4_4_7 = (8,11) + n_s3_4_6 = (9,11) + n_u2_4_5 = (10,11) +; + +@else +# Regular 24-bit instruction. +define token insn(24) + # Named opcode/register fields. + op2 = (20,23) + ar = (12,15) + fr = (12,15) + br = (12,15) + as = (8,11) + fs = (8,11) + bs = (8,11) + sr = (8,15) + at = (4,7) + ft = (4,7) + bt = (4,7) + op1 = (16,19) + op0 = (0,3) + + # Signed and unsigned immediates. Named [us]N_L_M, where u and s denote signedness, L and M the + # least and most significant bit of the immediate in the instruction word, and N the length + # (i.e. M-L+1). + u3_21_23 = (21,23) + u4_20_23 = (20,23) + s8_16_23 = (16,23) signed + u8_16_23 = (16,23) + u12_12_23 = (12,23) + s12_12_23 = (12,23) signed + u16_8_23 = (8,23) + s8_6_23 = (6,23) signed + u1_20 = (20,20) + u2_18_19 = (18,19) + u3_17_19 = (17,19) + u2_16_17 = (16,17) + u1_16 = (16,16) + u1_15_15 = (15,15) + u2_14_15 = (14,15) + u3_13_15 = (13,15) + u4_12_15 = (12,15) + m0m1_14_14 = (14,14) + u2_12_13 = (12,13) + mw_12_13 = (12,13) + u1_12 = (12,12) + u4_8_11 = (8,11) + u8_4_11 = (4,11) + s4_8_11 = (8,11) signed + u1_7_7 = (7,7) + u2_6_7 = (6,7) + u3_5_7 = (5,7) + u4_4_7 = (4,7) + s4_4_7 = (4,7) + m2m3_6_6 = (6,6) + u_4_23 = (4,23) + u2_4_5 = (4,5) + u1_4 = (4,4) +; + +# Narrow 16-bit instructions; fields are always prefixed with n_. +define token narrowinsn(16) + n_ar = (12,15) + n_as = (8,11) + n_at = (4,7) + n_op0 = (0, 3) + + n_u4_12_15 = (12,15) + n_s4_12_15 = (12,15) signed + n_u4_8_11 = (8,11) + n_u1_7 = (7,7) + n_u2_6_7 = (6,7) + n_u4_4_7 = (4,7) + n_s3_4_6 = (4,6) + n_u2_4_5 = (4,5) +; + +@endif + +attach variables [ sr ] [ +# 0x...0 0x...4 0x...8 0x...c + LBEG LEND LCOUNT SAR # 0x0_ + BR LITBASE _ _ # 0x1_ + _ _ _ _ # 0x2_ + SCOMPARE1 _ _ _ # 0x3_ + ACCLO ACCHI _ _ # 0x4_ + _ _ _ _ # 0x5_ + _ _ _ _ # 0x6_ + _ _ _ _ # 0x7_ + M0 M1 M2 M3 # 0x8_ + _ _ _ _ # 0x9_ + _ _ _ _ # 0xa_ + _ _ _ _ # 0xb_ + _ _ _ _ # 0xc_ + _ _ _ _ # 0xd_ + _ _ _ _ # 0xe_ + _ _ _ _ # 0xf_ +# 0x...0 0x...4 0x...8 0x...c + _ _ _ _ # 0x10_ + _ _ _ _ # 0x11_ + WindowBase WindowStart _ _ # 0x12_ + _ _ _ _ # 0x13_ + _ _ _ PTEVADDR # 0x14_ + _ _ _ _ # 0x15_ + _ MMID RASID ITLBCFG # 0x16_ + DTLBCFG _ _ _ # 0x17_ + IBREAKENABLE MEMCTL CACHEATTR ATOMCTL # 0x18_ + _ _ _ _ # 0x19_ + DDR _ MEPC MEPS # 0x1a_ + MESAVE MESR MECR MEVADDR # 0x1b_ + _ _ _ _ # 0x1c_ + _ _ _ _ # 0x1d_ + _ _ _ _ # 0x1e_ + _ _ _ _ # 0x1f_ +# 0x...0 0x...4 0x...8 0x...c + IBREAKA0 IBREAKA1 _ _ # 0x20_ + _ _ _ _ # 0x21_ + _ _ _ _ # 0x22_ + _ _ _ _ # 0x23_ + DBREAKA0 DBREAKA1 _ _ # 0x24_ + _ _ _ _ # 0x25_ + _ _ _ _ # 0x26_ + _ _ _ _ # 0x27_ + DBREAKC0 DBREAKC1 _ _ # 0x28_ + _ _ _ _ # 0x29_ + _ _ _ _ # 0x2a_ + _ _ _ _ # 0x2b_ + _ EPC1 EPC2 EPC3 # 0x2c_ + EPC4 EPC5 EPC6 EPC7 # 0x2d_ + _ _ _ _ # 0x2e_ + _ _ _ _ # 0x2f_ +# 0x...0 0x...4 0x...8 0x...c + DEPC _ EPS2 EPS3 # 0x30_ + EPS4 EPS5 EPS6 EPS7 # 0x31_ + _ _ _ _ # 0x32_ + _ _ _ _ # 0x33_ + _ EXCSAVE1 EXCSAVE2 EXCSAVE3 # 0x34_ + EXCSAVE4 EXCSAVE5 EXCSAVE6 EXCSAVE7 # 0x35_ + _ _ _ _ # 0x36_ + _ _ _ _ # 0x37_ + CPENABLE INTERRUPT INTSET INTCLEAR # 0x38_ + INTENABLE _ PS VECBASE # 0x39_ + EXCCAUSE DEBUGCAUSE CCOUNT PRID # 0x3a_ + ICOUNT ICOUNTLEVEL EXCVADDR _ # 0x3b_ + CCOMPARE0 CCOMPARE1 CCOMPARE2 _ # 0x3c_ + MISC0 MISC1 MISC2 MISC3 # 0x3d_ + _ _ _ _ # 0x3e_ + _ _ _ _ # 0x3f_ +# 0x...0 0x...4 0x...8 0x...c +]; + +attach variables [ ar as at n_ar n_as n_at ] [ + a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 a14 a15 +]; + +attach variables [ fr fs ft ] [ + f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 f10 f11 f12 f13 f14 f15 +]; + +attach variables [ br bs bt ] [ + b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 b10 b11 b12 b13 b14 b15 +]; + +# Various 32-bit pointers relative to PC. Any operands that are split across non-consecutive +# bits are named foo_LL.LM_ML.MM, where LL is the least significant bits of the least +# singificant operand half, LM the most significant bits of the least significant operand half, etc. + +attach variables [ mw_12_13 ] [ + M0 M1 M2 M3 +]; + +attach variables [ m2m3_6_6 ] [ + M2 M3 +]; + +attach variables [ m0m1_14_14 ] [ + M0 M1 +]; + + +#implemented pcodeops +define pcodeop breakpoint; +define pcodeop dhi; +define pcodeop dhu; +define pcodeop dhwb; +define pcodeop dhwbi; +define pcodeop dii; +define pcodeop diu; +define pcodeop diwb; +define pcodeop diwbi; +define pcodeop dpfl; +define pcodeop dpfr; +define pcodeop dpfro; +define pcodeop dpfw; +define pcodeop dpfwo; +define pcodeop dsync; +define pcodeop esync; +define pcodeop excw; +define pcodeop extw; +define pcodeop idtlb; +define pcodeop ihi; +define pcodeop ihu; +define pcodeop iii; +define pcodeop iitlb; +define pcodeop iiu; +define pcodeop ill; +define pcodeop ipf; +define pcodeop ipfl; +define pcodeop isync; +define pcodeop acquire; +define pcodeop ldct; +define pcodeop lict; +define pcodeop licw; +define pcodeop memw; +define pcodeop nsa; +define pcodeop nsau; +define pcodeop pdtlb; +define pcodeop pitlb; +define pcodeop rdtlb0; +define pcodeop rdtlb1; +define pcodeop rer; +define pcodeop restore4; +define pcodeop restore8; +define pcodeop restore12; +define pcodeop rfdd; +define pcodeop rfde; +define pcodeop rfdo; +define pcodeop rfe; +define pcodeop rfi; +define pcodeop rfme; +define pcodeop rfue; +define pcodeop rfwo; +define pcodeop rfwu; +define pcodeop ritlb0; +define pcodeop ritlb1; +define pcodeop rsil; +define pcodeop rsr; +define pcodeop rsync; +define pcodeop rur; +define pcodeop s32c1i; +define pcodeop release; +define pcodeop restoreRegWindow; +define pcodeop rotateRegWindow; +define pcodeop sdct; +define pcodeop sict; +define pcodeop sicw; +define pcodeop simcall; +define pcodeop syscall; +define pcodeop swap4; +define pcodeop swap8; +define pcodeop swap12; +define pcodeop waiti; +define pcodeop wdtlb; +define pcodeop wer; +define pcodeop witlb; +define pcodeop wsr; +define pcodeop wur; +define pcodeop xsr; + diff --git a/Ghidra/Processors/Xtensa/data/languages/xtensaInstructions.sinc b/Ghidra/Processors/Xtensa/data/languages/xtensaInstructions.sinc new file mode 100644 index 0000000000..1aa19cb0de --- /dev/null +++ b/Ghidra/Processors/Xtensa/data/languages/xtensaInstructions.sinc @@ -0,0 +1,1921 @@ + + +# ABS - Absolute Value (RRR), pg. 246. +:abs ar, at is op2 = 0b0110 & op1 = 0 & ar & as = 0b0001 & at & op0 = 0 { + ar = at; + if (ar s> 0) + goto inst_next; + ar = -ar; +} + +# ABS.S - Absolute Single Value (RRR), pg. 247. +:abs.s fr, fs is op2 = 0b1111 & op1 = 0b1010 & fr & fs & at = 0b0001 & op0 = 0b0000 { + fr = abs(fs); +} + +# ADD - Add (RRR), pg. 248. +:add ar, as, at is op2 = 0b1000 & op1 = 0 & ar & as & at & op0 = 0 { + ar = as + at; +} + +# ADD.N - Narrow Add (RRRN), pg. 249. +:add.n n_ar, n_as, n_at is n_ar & n_as & n_at & n_op0 = 0b1010 { + n_ar = n_as + n_at; +} + +# ADD.S - Add Single (RRR), pg. 250. +:add.s fr, fs, ft is op2 = 0 & op1 = 0b1010 & fr & fs & ft & op0 = 0 { + fr = fs f+ ft; +} + +# ADDI - Add Immediate (RRI8), pg. 251. +:addi at, as, s8_16_23 is s8_16_23 & ar = 0b1100 & as & at & op0 = 0b0010 { + at = as + s8_16_23; +} + +# ADDI.N - Narrow Add Immediate (RRRN), pg. 252. +:addi.n n_ar, n_as, n_s4_4_7_nozero is n_ar & n_as & n_s4_4_7_nozero & n_op0 = 0b1011 { + n_ar = n_as + n_s4_4_7_nozero; +} + +# ADDMI - Add Immediate with Shift by 8, pg. 253. +:addmi at, as, s16_16_23_sb8 is s16_16_23_sb8 & ar = 0b1101 & as & at & op0 = 0b0010 { + at = as + s16_16_23_sb8; +} + +# ADDX2 - Add with Shift by 1, pg. 254. +:addx2 ar, as, at is op2 = 0b1001 & op1 = 0 & ar & as & at & op0 = 0 { + ar = (as << 1) + at; +} + +# ADDX4 - Add with Shift by 2, pg. 255. +:addx4 ar, as, at is op2 = 0b1010 & op1 = 0 & ar & as & at & op0 = 0 { + ar = (as << 2) + at; +} + +# ADDX8 - Add with Shift by 4, pg. 256. +:addx8 ar, as, at is op2 = 0b1011 & op1 = 0 & ar & as & at & op0 = 0 { + ar = (as << 3) + at; +} + +# ALL4 - All 4 Booleans True, pg. 257. +:all4 bt, bs is op2 = 0 & op1 = 0 & ar = 0b1001 & bs & bt & op0 = 0 { + local b = *[register]:1 &:4 bs+1; + local c = *[register]:1 &:4 bs+2; + local d = *[register]:1 &:4 bs+3; + bt = bs && b && c && d; +} + +# ALL8 - All 8 Booleans True, pg. 258. +:all8 bt, bs is op2 = 0 & op1 = 0 & ar = 0b1011 & bs & bt & op0 = 0 { + local b = *[register]:1 &:4 bs+1; + local c = *[register]:1 &:4 bs+2; + local d = *[register]:1 &:4 bs+3; + local e = *[register]:1 &:4 bs+4; + local f = *[register]:1 &:4 bs+5; + local g = *[register]:1 &:4 bs+6; + local h = *[register]:1 &:4 bs+7; + bt = bs && b && c && d && e && f && g && h; +} + +# AND - Bitwise Logical And, pg. 259. +:and ar, as, at is op2 = 0b0001 & op1 = 0 & ar & as & at & op0 = 0 { + ar = as & at; +} + +# ANDB - Boolean And, pg. 260. +:andb br, bs, bt is op2 = 0 & op1 = 0b0010 & br & bs & bt & op0 = 0 { + br = bs && bt; +} + +# ANDBC - Boolean And with Complement, pg. 261. +:andbc br, bs, bt is op2 = 0b0001 & op1 = 0b0010 & br & bs & bt & op0 = 0 { + br = bs && !bt; +} + +# ANY4 - Any 4 Booleans True, pg. 262. +:any4 bt, bs is op2 = 0 & op1 = 0 & ar = 0b1000 & bs & bt & op0 = 0 { + local b = *[register]:1 &:4 bs+1; + local c = *[register]:1 &:4 bs+2; + local d = *[register]:1 &:4 bs+3; + bt = bs || b || c || d; +} + +# ANY8 - Any 8 Booleans True, pg. 263. +:any8 bt, bs is op2 = 0 & op1 = 0 & ar = 0b1010 & bs & bt & op0 = 0 { + local b = *[register]:1 &:4 bs+1; + local c = *[register]:1 &:4 bs+2; + local d = *[register]:1 &:4 bs+3; + local e = *[register]:1 &:4 bs+4; + local f = *[register]:1 &:4 bs+5; + local g = *[register]:1 &:4 bs+6; + local h = *[register]:1 &:4 bs+7; + bt = bs || b || c || d || e || f || g || h; +} + +# BALL - Branch if All Bits Set, pg. 264. +:ball srel_16_23, as, at is srel_16_23 & ar = 0b0100 & as & at & op0 = 0b0111 { + local test:4 = ~as & at; + if (test == 0) goto srel_16_23; +} + +# BANY - Branch if Any Bit Set, pg. 265. +:bany srel_16_23, as, at, is srel_16_23 & ar = 0b1000 & as & at & op0 = 0b0111 { + local test:4 = as & at; + if (test == 0) goto srel_16_23; +} + +macro extract_bit(bit, result) { +@if ENDIAN == "big" + result = 0x80000000 >> bit; +@else + result = 0x1 << bit; +@endif +} + +# BBC - Branch if Bit Clear, pg. 266. +:bbc as, at, srel_16_23 is srel_16_23 & ar = 0b0101 & as & at & op0 = 0b0111 { + local bval:4 = 0; + extract_bit(at[0,5], bval); + bval = as & bval; + if (bval == 0) + goto srel_16_23; +} + +# BBCI - Branch if Bit Clear immediate, pg. 267 +:bbci as, u5_4_7_12, srel_16_23 is srel_16_23 & u3_13_15 = 0b011 & as & u5_4_7_12 & op0 = 0b0111 { + local bval; + extract_bit(u5_4_7_12, bval); + bval = as & bval; + if (bval == 0) + goto srel_16_23; +} + +# BBS - Branch if Bit Set, pg. 269. +:bbs as, at, srel_16_23 is srel_16_23 & ar = 0b1101 & as & at & op0 = 0b0111 { + local bval; + extract_bit(at[0,5], bval); + bval = as & bval; + if (bval != 0) + goto srel_16_23; +} + +# BBSI - Branch if Bit Set immediate, pg. 270. +:bbsi as, u5_4_7_12, srel_16_23 is srel_16_23 & u3_13_15 = 0b111 & as & u5_4_7_12 & op0 = 0b0111 { + local bval; + extract_bit(u5_4_7_12, bval); + bval = as & bval; + if (bval != 0) + goto srel_16_23; +} + +# BEQ - Branch if Equal, pg. 272. +:beq as, at, srel_16_23 is srel_16_23 & ar = 0b0001 & as & at & op0 = 0b0111 { + if (as == at) + goto srel_16_23; +} + +# BEQI - Branch if Equal Immediate, pg. 273. +:beqi as, r_b4const, srel_16_23 is srel_16_23 & r_b4const & as & u2_6_7 = 0 & u2_4_5 = 0b10 & op0 = 0b0110 { + if (as == r_b4const) + goto srel_16_23; +} + +# BEQZ - Branch if Equal Zero, pg. 274. +:beqz as, srel_12_23 is srel_12_23 & as & u2_6_7 = 0 & u2_4_5 = 0b01 & op0 = 0b0110 { + if (as == 0) + goto srel_12_23; +} + +# BEQZ.N - Narrow Branch if Equal Zero, pg. 275. +:beqz.n n_as, urel_12_15_4_5 is urel_12_15_4_5 & n_as & n_u2_6_7 = 0b10 & n_op0 = 0b1100 { + if (n_as == 0) + goto urel_12_15_4_5; +} + +# BF - Branch if False, pg. 276. +:bf bs, srel_16_23 is srel_16_23 & ar = 0 & bs & at = 0b0111 & op0 = 0b0110 { + if (!bs) + goto srel_16_23; +} + +# BGE - Branch if Greater Than or Equal, pg. 277. +:bge as, at, srel_16_23 is srel_16_23 & ar = 0b1010 & as & at & op0 = 0b0111 { + if (as s>= at) + goto srel_16_23; +} + +# BGEI - Branch if Greater Than or Equal Immediate, pg. 278. +:bgei as, r_b4const, srel_16_23 is srel_16_23 & r_b4const & as & u2_6_7 = 0b11 & u2_4_5 = 0b10 & op0 = 0b0110 { + if (as s>= r_b4const) + goto srel_16_23; +} + +# BGEU - Branch if Greater Than or Equal Unsigned, pg. 279. +:bgeu as, at, srel_16_23 is srel_16_23 & ar = 0b1011 & as & at & op0 = 0b0111 { + if (as >= at) + goto srel_16_23; +} + +# BGEUI - Branch if Greater Than or Equal Unsigned Immediate, pg. 280. +:bgeui as, r_b4constu, srel_16_23 is srel_16_23 & r_b4constu & as & u2_6_7 = 0b11 & u2_4_5 = 0b11 & op0 = 0b0110 { + if (as >= r_b4constu) + goto srel_16_23; +} + +# BGEZ - Branch if Greater Than or Equal Zero, pg. 281. +:bgez as, srel_12_23 is srel_12_23 & as & u2_6_7 = 0b11 & u2_4_5 = 0b01 & op0 = 0b0110 { + if (as s>= 0) + goto srel_12_23; +} + +# BLT - Branch if Less Than, pg. 282. +:blt as, at, srel_16_23 is srel_16_23 & ar = 0b0010 & as & at & op0 = 0b0111 { + if (as s< at) + goto srel_16_23; +} + +# BLTI - Branch if Less Than Immediate, pg. 283. +:blti as, r_b4const, srel_16_23 is srel_16_23 & r_b4const & as & u2_6_7 = 0b10 & u2_4_5 = 0b10 & op0 = 0b0110 { + if (as s< r_b4const) + goto srel_16_23; +} + +# BLTU - Branch if Less Than Unsigned, pg. 284. +:bltu as, at, srel_16_23 is srel_16_23 & ar = 0b0011 & as & at & op0 = 0b0111 { + if (as < at) + goto srel_16_23; +} + +# BLTUI - Branch if Less Than Unsigned Immediate, pg. 285. +:bltui as, r_b4constu, srel_16_23 is srel_16_23 & r_b4constu & as & u2_6_7 = 0b10 & u2_4_5 = 0b11 & op0 = 0b0110 { + if (as < r_b4constu) + goto srel_16_23; +} + +# BLTZ - Branch if Less Than Zero, pg. 286. +:bltz as, srel_12_23 is srel_12_23 & as & u2_6_7 = 0b10 & u2_4_5 = 0b01 & op0 = 0b0110 { + if (as s< 0) + goto srel_12_23; +} + +# BNALL - Branch if Not-All Bits Set, pg. 287. +:bnall srel_16_23, as, at is srel_16_23 & ar = 0b1100 & as & at & op0 = 0b0111 { + if ((~as & at) != 0) + goto srel_16_23; +} + +# BNE - Branch if Not Equal, pg. 288. +:bne as, at, srel_16_23 is srel_16_23 & ar = 0b1001 & as & at & op0 = 0b0111 { + if (as != at) + goto srel_16_23; +} + +# BNEI - Branch if Not EquaL Immediate, pg. 289. +:bnei as, r_b4const, srel_16_23 is srel_16_23 & r_b4const & as & u2_6_7 = 0b01 & u2_4_5 = 0b10 & op0 = 0b0110 { + if (as != r_b4const) + goto srel_16_23; +} + +# BNEZ - Branch if Not Equal Zero, pg. 290. +:bnez as, srel_12_23 is srel_12_23 & as & u2_6_7 = 0b01 & u2_4_5 = 0b01 & op0 = 0b0110 { + if (as != 0) + goto srel_12_23; +} + +# BNEZ.N - Narrow Branch if Not Equal Zero, pg. 291. +:bnez.n n_as, urel_12_15_4_5 is urel_12_15_4_5 & n_as & n_u2_6_7 = 0b11 & n_op0 = 0b1100 { + if (n_as != 0) + goto urel_12_15_4_5; +} + +# BNONE - Branch if No Bit Set, pg. 292. +:bnone srel_16_23, as, at, is srel_16_23 & ar = 0 & as & at & op0 = 0b0111 { + if ((as & at) == 0) + goto srel_16_23; +} + +# BREAK - Breakpoint, pg. 293. +:break u4_8_11, u4_4_7 is op2 = 0 & op1 = 0 & ar = 0b0100 & u4_8_11 & u4_4_7 & op0 = 0 { + break_inst:4 = inst_start; + breakpoint(0x001000:4, break_inst, u4_8_11:1, u4_4_7:1); +} + +# BREAK.N - Narrow Breakpoint, pg. 295. +:break.n n_u4_8_11 is n_ar = 0b1111 & n_u4_8_11 & n_at = 0b0010 & n_op0 = 0b1101 { + break_inst:4 = inst_start; + breakpoint(0x010000:4, break_inst, n_u4_8_11:1, 0:1); +} + +# BT - Branch if True, pg. 296. +:bt bs, srel_16_23 is srel_16_23 & ar = 0b0001 & bs & at = 0b0111 & op0 = 0b0110 { + if (bs) + goto srel_16_23; +} + +# CALL0 - Non-windowed Call, pg. 297. +:call0 srel_6_23_sb2 is srel_6_23_sb2 & u2_4_5 = 0 & op0 = 0b0101 { + $(PS_CALLINC) = 0; + a0 = inst_next; + call srel_6_23_sb2; +} + +# CALL4 - Call PC-relative, Rotate Window by 4, pg. 298. +:call4 srel_6_23_sb2 is srel_6_23_sb2 & Ret4 & u2_4_5 = 0b01 & op0 = 0b0101 { + $(PS_CALLINC) = 1; + a4 = Ret4; + swap4(); + call srel_6_23_sb2; + restore4(); +} + +# CALL8 - Call PC-relative, Rotate Window by 8, pg. 300. +:call8 srel_6_23_sb2 is srel_6_23_sb2 & Ret8 & u2_4_5 = 0b10 & op0 = 0b0101 { + $(PS_CALLINC) = 2; + a8 = Ret8; + swap8(); + call srel_6_23_sb2; + restore8(); +} + +# CALL12 - Call PC-relative, Rotate Window by 12, pg. 302. +:call12 srel_6_23_sb2 is srel_6_23_sb2 & Ret12 & u2_4_5 = 0b11 & op0 = 0b0101 { + $(PS_CALLINC) = 3; + a12 = Ret12; + swap12(); + call srel_6_23_sb2; + restore12(); +} + +# CALLX0 - Non-windowed Call Register, pg. 304. +:callx0 as is op2 = 0 & op1 = 0 & ar = 0 & as & u2_6_7 = 0b11 & u2_4_5 = 0 & op0 = 0 { + $(PS_CALLINC) = 0; + local dst = as; + a0 = inst_next; + call [dst]; +} + +# CALLX4 - Call Register, Rotate Window by 4, pg. 305. +:callx4 as is op2 = 0 & op1 = 0 & ar = 0 & as & Ret4 & u2_6_7 = 0b11 & u2_4_5 = 0b01 & op0 = 0 { + $(PS_CALLINC) = 1; + dest:4 = as; + a4 = Ret4; + swap4(); + call [dest]; + restore4(); +} + +# CALLX8 - Call Register, Rotate Window by 8, pg. 307. +:callx8 as is op2 = 0 & op1 = 0 & ar = 0 & as & Ret8 & u2_6_7 = 0b11 & u2_4_5 = 0b10 & op0 = 0 { + $(PS_CALLINC) = 2; + dest:4 = as; + a8 = Ret8; + swap8(); + call [dest]; + restore8(); +} + +# CALLX12 - Call Register, Rotate Window by 12, pg. 308. +:callx12 as is op2 = 0 & op1 = 0 & ar = 0 & as & Ret12 & u2_6_7 = 0b11 & u2_4_5 = 0b11 & op0 = 0 { + $(PS_CALLINC) = 3; + dest:4 = as; + a12 = Ret12; + swap12(); + call [dest]; + restore12(); +} + +# CEIL.S - Ceiling Single to Fixed, pg. 311. +:ceil.s ar, fs, u4_4_7 is op2 = 0b1011 & op1 = 0b1010 & ar & fs & u4_4_7 & op0 = 0 { + local scale:4 = 1 << u4_4_7; + ar = ceil(fs f* int2float(scale)); +} + +# CLAMPS - Signed Clamp, pg. 312. +:clamps ar, as, u5_4_7_plus7 is op2 = 0b0011 & op1 = 0b0011 & ar & as & u5_4_7_plus7 & op0 = 0 { + # ar min(max(as, -2^{u5_4_7_plus7}), 2^{u5_4_7_plus7}-1) + local x:4 = as; + local clamp:4 = 1 << u5_4_7_plus7; + local mt:1 = (x s> (-clamp)); + local max:4 = (zext(mt) * x) + (zext(!mt) * (-clamp)); + mt = (x s< (clamp-1)); + local y = (zext(mt) * max) + (zext(!mt) * (clamp-1)); +} + +# DHI - Data Cache Hit Invalidate, pg. 313. +:dhi as, u10_16_23_sb2 is u10_16_23_sb2 & ar = 0b0111 & as & at = 0b0110 & op0 = 0b0010 { + dhi(as + u10_16_23_sb2); +} + +# DHU - Data Cache Hit Unlock, pg. 315. +:dhu as, u8_20_23_sb4 is u8_20_23_sb4 & op1 = 0b0010 & ar = 0b0111 & as & at = 0b1000 & op0 = 0b0010 { + dhu(as + u8_20_23_sb4); +} + +# DHWB - Data Cache Hit Writeback, pg. 317. +:dhwb as, u10_16_23_sb2 is u10_16_23_sb2 & ar = 0b0111 & as & at = 0b0100 & op0 = 0b0010 { + dhwb(as + u10_16_23_sb2); +} + +# DHWBI - Data Cache Hit Writeback Invalidate, pg. 319. +:dhwbi as, u10_16_23_sb2 is u10_16_23_sb2 & ar = 0b0111 & as & at = 0b0101 & op0 = 0b0010 { + dhwbi(as + u10_16_23_sb2); +} + +# DII - Data Cache Index Invalidate, pg. 321. +:dii as, u10_16_23_sb2 is u10_16_23_sb2 & ar = 0b0111 & as & at = 0b0111 & op0 = 0b0010 { + dii(as + u10_16_23_sb2); +} + +# DIU - Data Cache Index Unlock, pg. 323. +:diu as, u8_20_23_sb4 is u8_20_23_sb4 & op1 = 0b0011 & ar = 0b0111 & as & at = 0b1000 & op0 = 0b0010 { + diu(as + u8_20_23_sb4); +} + +# DIWB - Data Cache Index Write Back, pg. 325. +:diwb as, u8_20_23_sb4 is u8_20_23_sb4 & op1 = 0b0100 & ar = 0b0111 & as & at = 0b1000 & op0 = 0b0010 { + diwb(as + u8_20_23_sb4); +} + +# DIWBI - Data Cache Index Write Back Invalidate, pg. 327. +:diwbi as, u8_20_23_sb4 is u8_20_23_sb4 & op1 = 0b0101 & ar = 0b0111 & as & at = 0b1000 & op0 = 0b0010 { + diwbi(as + u8_20_23_sb4); +} + +# DPFL - Data Cache Prefetch and Lock, pg. 329. +:dpfl as, u8_20_23_sb4 is u8_20_23_sb4 & op1 = 0 & ar = 0b0111 & as & at = 0b1000 & op0 = 0b0010 { + dpfl(as + u8_20_23_sb4); +} + +# DPFR - Data Cache Prefetch for Read, pg. 331. +:dpfr as, u10_16_23_sb2 is u10_16_23_sb2 & ar = 0b0111 & as & at = 0 & op0 = 0b0010 { + dpfr(as + u10_16_23_sb2); +} + +# DPFRO - Data Cache Prefetch for Read Once, pg. 333. +:dpfro as, u10_16_23_sb2 is u10_16_23_sb2 & ar = 0b0111 & as & at = 0b0010 & op0 = 0b0010 { + dpfro(as + u10_16_23_sb2); +} + +# DPFW - Data Cache Prefetch for Write, pg. 335. +:dpfw as, u10_16_23_sb2 is u10_16_23_sb2 & ar = 0b0111 & as & at = 0b0001 & op0 = 0b0010 { + dpfw(as + u10_16_23_sb2); +} + +# DPFWO - Data Cache Prefetch for Write Once, pg. 337. +:dpfwo as, u10_16_23_sb2 is u10_16_23_sb2 & ar = 0b0111 & as & at = 0b0011 & op0 = 0b0010 { + dpfwo(as + u10_16_23_sb2); +} + +# DSYNC - Load/Store Synchronize, pg. 339. +:dsync is op2 = 0 & op1 = 0 & ar = 0b0010 & as = 0 & at = 0b0011 & op0 = 0 { + dsync(); +} + +# ENTRY - Subroutine Entry, pg. 340. +:entry as, u15_12_23_sb3 is u15_12_23_sb3 & as & u2_6_7 = 0b00 & u2_4_5 = 0b11 & op0 = 0b0110 { + local callSP = a1; + callinc:1 = $(PS_CALLINC); + rotateRegWindow(callinc); + as = callSP - zext(u15_12_23_sb3); +} + +# ESYNC - Execute Synchronize, pg. 342. +:esync is op2 = 0 & op1 = 0 & ar = 0b0010 & as = 0 & at = 0b0010 & op0 = 0 { + esync(); +} + +# EXCW - Exception Wait, pg. 343. +:excw is op2 = 0 & op1 = 0 & ar = 0b0010 & as = 0 & at = 0b1000 & op0 = 0 { + excw(); +} + +# EXTUI - Extract Unsigned Immediate, pg. 344. +:extui ar, at, u5_8_11_16, u5_20_23_plus1 is u5_20_23_plus1 & u3_17_19 = 0b010 & u5_8_11_16 & ar & at & op0 = 0 { + local shifted:4 = at >> u5_8_11_16; + local mask:4 = (1:4 << (u5_20_23_plus1))-1; + ar = shifted & mask; +} + +# EXTW - External Wait, pg. 345. +:extw is op2 = 0 & op1 = 0 & ar = 0b0010 & as = 0 & at = 0b1101 & op0 = 0 { + extw(); +} + +# FLOAT.S - Convert Fixed to Single, pg. 346. +:float.s fr, as, u4_4_7 is op2 = 0b1100 & op1 = 0b1010 & fr & as & u4_4_7 & op0 = 0 { + local scale:4 = 1 << u4_4_7; + fr = int2float(as) f/ int2float(scale); +} + +# FLOOR.S - Floor Single to Fixed, pg. 347. +:floor.s ar, fs, u4_4_7 is op2 = 0b1010 & op1 = 0b1010 & ar & fs & u4_4_7 & op0 = 0 { + local scale:4 = 1 << u4_4_7; + ar = floor(fs f* int2float(scale)); +} + +# IDTLB - Invalidate Data TLB Entry, pg. 348. +:idtlb as is op2 = 0b0101 & op1 = 0 & ar = 0b1100 & as & at = 0 & op0 = 0 { + idtlb(); +} + +# IHI - Instruction Cache Hit Invalidate, pg. 349. +:ihi as, u10_16_23_sb2 is u10_16_23_sb2 & ar = 0b0111 & as & at = 0b1110 & op0 = 0b0010 { + ihi(as + u10_16_23_sb2); +} + +# IHU - Instruction Cache Hit Unlock, pg. 351. +:ihu as, u8_20_23_sb4 is u8_20_23_sb4 & op1 = 0b0010 & ar = 0b0111 & as & at = 0b1101 & op0 = 0b0010 { + ihu(as + u8_20_23_sb4); +} + +# III - Instruction Cache Index Invalidate, pg. 353. +:iii as, u10_16_23_sb2 is u10_16_23_sb2 & ar = 0b0111 & as & at = 0b1111 & op0 = 0b0010 { + iii(as + u10_16_23_sb2); +} + +# IITLB - Invalidate Instruction TLB Entry, pg. 355. +:iitlb as is op2 = 0b0101 & op1 = 0 & ar = 0b0100 & as & at = 0 & op0 = 0 { + iitlb(as); +} + +# IIU - Instruction Cache Index Unlock, pg. 356. +:iiu as, u8_20_23_sb4 is u8_20_23_sb4 & op1 = 0b0011 & ar = 0b0111 & as & at = 0b1101 & op0 = 0b0010 { + iiu(as + u8_20_23_sb4); +} + +# ILL - Illegal Instruction, pg. 358. +:ill is op2 = 0 & op1 = 0 & ar = 0 & as = 0 & at = 0 & op0 = 0 { + ill(); + goto inst_start; +} + +# ILL.N - Narrow Illegal Instruction, pg. 359. +:ill.n is n_ar = 0b1111 & n_as = 0 & n_at = 0b0110 & n_op0 = 0b1101 { + ill(); + goto inst_start; +} + +# IPF - Instruction Cache Prefetch, pg. 360. +:ipf as, u10_16_23_sb2 is u10_16_23_sb2 & ar = 0b0111 & as & at = 0b1100 & op0 = 0b0010 { + ipf(as + u10_16_23_sb2); +} + +# IPFL - Instruction Cache Prefetch and Lock, pg. 362. +:ipfl as, u8_20_23_sb4 is u8_20_23_sb4 & op1 = 0 & ar = 0b0111 & as & at = 0b1101 & op0 = 0b0010 { + ipfl(as + u8_20_23_sb4); +} + +# ISYNC - Instruction Fetch Synchronize, pg. 364. +:isync is op2 = 0 & op1 = 0 & ar = 0b0010 & as = 0 & at = 0 & op0 = 0 { + isync(); +} + +# J - Unconditional Jump, pg. 366. +:j srel_6_23 is srel_6_23 & u2_4_5 = 0 & op0 = 0b0110 { + goto srel_6_23; +} + +# J.L is a macro. + +# RET (JX A0) - Non-Windowed Return, pg. 478. +:ret is op2 = 0 & op1 = 0 & ar = 0 & as = 0 & u2_6_7 = 0b10 & u2_4_5 = 0b10 & op0 = 0 { + return [a0]; +} + +# The manual suggests that RET is equivalent to JX A0, yet RET has bit 5 unset, JX doesn’t. +:ret is op2 = 0 & op1 = 0 & ar = 0 & as = 0 & u2_6_7 = 0b10 & u2_4_5 = 0b00 & op0 = 0 { + return [a0]; +} + +# JX - Uncoditional Jump Register, pg. 368. +:jx as is op2 = 0 & op1 = 0 & ar = 0 & as & u2_6_7 = 0b10 & u2_4_5 = 0b10 & op0 = 0 { + goto [as]; +} + +# L8UI - Load 8-bit Unsigned, pg. 369. +:l8ui at, as, u8_16_23 is u8_16_23 & ar = 0 & as & at & op0 = 0b0010 { + local addr:4 = as + zext(u8_16_23:1); + at = zext(*:1 addr); +} + +# L16SI - Load 16-bit Signed, pg. 370. +:l16si at, as, u9_16_23_sb1 is u9_16_23_sb1 & ar = 0b1001 & as & at & op0 = 0b0010 { + local addr:4 = as + u9_16_23_sb1; + at = sext(*:2 addr); +} + +# L16UI - Load 16-bit Unsigned, pg. 372. +:l16ui at, as, u9_16_23_sb1 is u9_16_23_sb1 & ar = 0b001 & as & at & op0 = 0b0010 { + local addr:4 = as + u9_16_23_sb1; + at = zext(*:2 addr); +} + +# L32AI - Load 32-bit Acquire, pg. 374. +:l32ai at, as, u10_16_23_sb2 is u10_16_23_sb2 & ar = 0b1011 & as & at & op0 = 0b0010 { + local addr:4 = as + u10_16_23_sb2; + at = *:4 addr; + acquire(addr); +} + +# L32E - Load 32-bit for Window Exceptions, pg. 376. +:l32e at, as, s5_12_15_oex is op2 = 0 & op1 = 0b1001 & s5_12_15_oex & as & at & op0 = 0 { + ptr:4 = as + sext(s5_12_15_oex); + at = *:4 ptr; +} + +# L32I - Load 32-bit, pg. 378. +:l32i at, as, u10_16_23_sb2 is u10_16_23_sb2 & ar = 0b0010 & as & at & op0 = 0b0010 { + local addr:4 = as + u10_16_23_sb2; + at = *:4 addr; +} + +# L32I.N - Narrow Load 32-bit, pg. 380. +:l32i.n n_at, n_as, n_u6_12_15_sb2 is n_u6_12_15_sb2 & n_as & n_at & n_op0 = 0b1000 { + local addr:4 = n_as + n_u6_12_15_sb2; + n_at = *:4 addr; +} + +# L32R - Load 32-bit PC-relative, pg. 382. +:l32r at, srel_8_23_oex_sb2 is srel_8_23_oex_sb2 & at & op0 = 0b0001 { + at = srel_8_23_oex_sb2; +} + +# LDCT - Load Data Cache Tag, pg. 384. +:ldct at, as is op2 = 0b1111 & op1 = 0b0001 & ar = 0b1000 & as & at & op0 = 0 { + at = ldct(as); +} + +# LICT - Load Instruction Cache Tag, pg. 388. +:lict at, as is op2 = 0b1111 & op1 = 0b0001 & ar = 0 & as & at & op0 = 0 { + at = lict(as); +} + +# LICW - Load Instruction Cache Word, pg. 390. +:licw at, as is op2 = 0b1111 & op1 = 0b0010 & ar = 0 & as & at & op0 = 0 { + at = licw(as); +} + +# LSI - Load Single Immediate, pg. 398. +:lsi ft, as, u10_16_23_sb2 is u10_16_23_sb2 & ar = 0 & as & ft & op0 = 0b0011 { + local addr:4 = as + u10_16_23_sb2; + ft = *:4 addr; +} + +# LSIU - Load Single Immediate with Update, pg. 400. +:lsiu ft, as, u10_16_23_sb2 is u10_16_23_sb2 & ar = 0b1000 & as & ft & op0 = 0b0011 { + local addr:4 = as + u10_16_23_sb2; + ft = *:4 addr; + as = addr; +} + +# LSX - Load Single Indexed, pg. 402. +:lsx fr, as, at is op2 = 0 & op1 = 0b1000 & fr & as & at & op0 = 0 { + local addr:4 = as+at; + fr = *:4 addr; +} + +# LSXU - Load Single Indexed with Update, pg. 404. +:lsxu fr, as, at is op2 = 0b0001 & op1 = 0b1000 & fr & as & at & op0 = 0 { + local addr:4 = as+at; + fr = *:4 addr; + as = addr; +} + +# MADD.S - Multiply and Add Single, pg. 406. +:madd.s fr, fs, ft is op2 = 0b0100 & op1 = 0b1010 & fr & fs & ft & op0 = 0 { + fr = fr f+ (fs f* ft); +} + +# MAX - Maximum Value, pg. 407. +:max ar, as, at is op2 = 0b0101 & op1 = 0b0011 & ar & as & at & op0 = 0 { + test:1 = as s< at; + ar = (zext(test) * at) + (zext(!test) * as); +} + +# MAXU - Maximum Value Unsigned, pg. 408. +:maxu ar, as, at is op2 = 0b0111 & op1 = 0b0011 & ar & as & at & op0 = 0 { + test:1 = as < at; + ar = (zext(test) * at) + (zext(!test) * as); +} + +# MEMW - Memory Wait, pg. 409. +:memw is op2 = 0 & op1 = 0 & ar = 0b0010 & as = 0 & at = 0b1100 & op0 = 0 { + memw(); +} + +# MIN - Minimum Value, pg. 410. +:min ar, as, at is op2 = 0b0100 & op1 = 0b0011 & ar & as & at & op0 = 0 { + test:1 = as s< at; + ar = (zext(test) * as) + (zext(!test) * at); +} + +# MINU - Minimum Value Unsigned, pg. 411. +:minu ar, as, at is op2 = 0b0110 & op1 = 0b0011 & ar & as & at & op0 = 0 { + test:1 = as < at; + ar = (zext(test) * as) + (zext(!test) * at); +} + +# MOV.N - Narrow Move, pg. 413. +:mov.n n_at, n_as is n_ar = 0 & n_as & n_at & n_op0 = 0b1101 { + n_at = n_as; +} + +# MOV.S - Move Single, pg. 414. +:mov.s fr, fs is op2 = 0b1111 & op1 = 0b1010 & fr & fs & at = 0 & op0 = 0 { + fr = fs; +} + +# MOVEQZ - Move if Equal to Zero, pg. 415. +:moveqz ar, as, at is op2 = 0b1000 & op1 = 0b0011 & ar & as & at & op0 = 0 { + if (at != 0) goto ; + ar = as; + +} + +# MOVEQZ.S - Move Single if Equal to Zero, pg. 416. +:moveqz.s fr, fs, at is op2 = 0b1000 & op1 = 0b1011 & fr & fs & at & op0 = 0 { + if (at != 0) goto ; + fr = fs; + +} + +# MOVF - Move if False, pg. 417. +:movf ar, as, bt is op2 = 0b1100 & op1 = 0b0011 & ar & as & bt & op0 = 0 { + if (bt) goto ; + ar = as; + +} + +# MOVF.S - Move Single if False, pg. 418. +:movf.s fr, fs, bt is op2 = 0b1100 & op1 = 0b1011 & fr & fs & bt & op0 = 0 { + if (bt)goto ; + fr = fs; + +} + +# MOVGEZ - Move if Greater Than or Equal to Zero, pg. 419. +:movgez ar, as, at is op2 = 0b1011 & op1 = 0b0011 & ar & as & at & op0 = 0 { + if (at s< 0) goto ; + ar = as; + +} + +# MOVGEZ.S - Move Single if Greater Than or Equal to Zero, pg. 420. +:movgez.s fr, fs, at is op2 = 0b1011 & op1 = 0b1011 & fr & fs & at & op0 = 0 { + if (at s< 0) goto ; + fr = fs; + +} + +# MOVI - Move Immediate, pg. 421. +:movi at, s16_16_23_8_11 is s16_16_23_8_11 & ar = 0b1010 & at & op0 = 0b0010 { + local val:4 = sext(s16_16_23_8_11); + at = val; +} + +# MOVI.N - Narrow Move Immediate, pg. 422. +:movi.n n_as, n_s8_12_15_4_6_asymm is n_s8_12_15_4_6_asymm & n_as & n_u1_7 = 0 & n_op0 = 0b1100 { + local val:4 = sext(n_s8_12_15_4_6_asymm); + n_as = val; +} + +# MOVLTZ - Move if Less Than Zero, pg. 423. +:movltz ar, as, at is op2 = 0b1010 & op1 = 0b0011 & ar & as & at & op0 = 0 { + if (at s>= 0) goto ; + ar = as; + +} + +# MOVLTZ.S - Move Single if Less Than Zero, pg. 424. +:movltz.s fr, fs, at is op2 = 0b1010 & op1 = 0b1011 & fr & fs & at & op0 = 0 { + if (at s>= 0) goto ; + fr = fs; + +} + +# MOVNEZ - Move if Not Equal to Zero, pg. 425. +:movnez ar, as, at is op2 = 0b1001 & op1 = 0b0011 & ar & as & at & op0 = 0 { + if (at == 0) goto ; + ar = as; + +} + +# MOVNEZ.S - Move Single if Not Equal to Zero, pg. 426. +:movnez.s fr, fs, at is op2 = 0b1001 & op1 = 0b1011 & fr & fs & at & op0 = 0 { + if (at == 0) goto ; + fr = fs; + +} + +# MOVSP - Move to Stack Pointer, pg. 427. +:movsp at, as is op2 = 0 & op1 = 0 & ar = 0b0001 & as & at & op0 = 0 { + at = (zext(WindowStart == 0) * at) + (zext(WindowStart != 0) * as); +} + +# MOVT - Move if True, pg. 428. +:movt ar, as, bt is op2 = 0b1101 & op1 = 0b0011 & ar & as & bt & op0 = 0 { + if (!bt) goto ; + ar = as; + +} + +# MOVT.S - Move Single if True, pg. 429. +:movt.s fr, fs, bt is op2 = 0b1101 & op1 = 0b1011 & fr & fs & bt & op0 = 0 { + if (!bt) goto ; + fr = fs; + +} + +# MSUB.S - Multiply and Subtract Single, pg. 430. +:msub.s fr, fs, ft is op2 = 0b0101 & op1 = 0b1010 & fr & fs & ft & op0 = 0 { + fr = fr f- (fs f* ft); +} + +# MUL.S - Multiply Single, pg. 435. +:mul.s fr, fs, ft is op2 = 0b0010 & op1 = 0b1010 & fr & fs & ft & op0 = 0 { + fr = fs f* ft; +} + +# MUL16S - Multiply 16-bit Signed, pg. 436. +:mul16s ar, as, at is op2 = 0b1101 & op1 = 0b0001 & ar & as & at & op0 = 0 { + ar = sext(as:2) * sext(at:2); +} + +# MUL16U - Multiply 16-bit Unsigned, pg. 437. +:mul16u ar, as, at is op2 = 0b1100 & op1 = 0b0001 & ar & as & at & op0 = 0 { + ar = zext(as:2) * zext(at:2); +} + +# MULL - Multiply Low, pg. 450. +:mull ar, as, at is op2 = 0b1000 & op1 = 0b0010 & ar & as & at & op0 = 0 { + ar = as * at; +} + +# MULSH - Multiply Signed High, pg. 455. +:mulsh ar, as, at is op2 = 0b1011 & op1 = 0b0010 & ar & as & at & op0 = 0 { + local s64:8 = sext(as); + local t64:8 = sext(at); + local p:8 = (s64 * t64); + ar = p(4); +} + +# MULUH - Multiply Unsigned High, pg. 456. +:muluh ar, as, at is op2 = 0b1010 & op1 = 0b0010 & ar & as & at & op0 = 0 { + local s64:8 = zext(as); + local t64:8 = zext(at); + local p:8 = (s64 * t64); + ar = p(4); +} + +# NEG - Negate, pg. 457. +:neg ar, at is op2 = 0b0110 & op1 = 0 & ar & as = 0 & at & op0 = 0 { + ar = -at; +} + +# NEG.S - Negate Single, pg. 458. +:neg.s fr, fs is op2 = 0b1111 & op1 = 0b1010 & fr & fs & at = 0b0110 & op0 = 0 { + fr = 0 f- fs; +} + +# NOP - No Operation, pg. 459. +:nop is op2 = 0 & op1 = 0 & ar = 0b0010 & as = 0 & at = 0b1111 & op0 = 0 { } + +# NOP.N - Narrow No Operation, pg. 460. +:nop.n is n_ar = 0b1111 & n_as = 0 & n_at = 0b0011 & n_op0 = 0b1101 { } + +# NSA - Normalization Shift Amount, pg. 461. +:nsa at, as is op2 = 0b0100 & op1 = 0 & ar = 0b1110 & as & at & op0 = 0 { + at = lzcount(~as); +} + +# NSAU - Normalization Shift Amount Unsigned, pg. 462. (Count leading zeros) +:nsau at, as is op2 = 0b0100 & op1 = 0 & ar = 0b1111 & as & at & op0 = 0 { + at = lzcount(as); +} + +# OEQ.S - Compare Single Equal, pg. 463. +:oeq.s br, fs, ft is op2 = 0b0010 & op1 = 0b1011 & br & fs & ft & op0 = 0 { + br = !nan(fs) && !nan(ft) && fs f== ft; +} + +# OLE.S - Compare Single Ordered and Less Than or Equal, pg. 464 +:ole.s br, fs, ft is op2 = 0b0110 & op1 = 0b1011 & br & fs & ft & op0 = 0 { + br = !nan(fs) && !nan(ft) && fs f<= ft; +} + +# OLT.S - Compare Single Ordered and Less Than, pg. 465. +:olt.s br, fs, ft is op2 = 0b0100 & op1 = 0b1011 & br & fs & ft & op0 = 0 { + br = !nan(fs) && !nan(ft) && fs f< ft; +} + +# MOV - Move, pg. 412. Special case of OR as, at, at. +:mov ar, as is op2 = 0b0010 & op1 = 0 & ar & as & as = at & op0 = 0 { + ar = as; +} + +# OR - Bitwise Logical Or, pg. 466. +:or ar, as, at is op2 = 0b0010 & op1 = 0 & ar & as & at & op0 = 0 { + ar = as | at; +} + +# ORB - Boolean Or, pg. 467. +:orb br, bs, bt is op2 = 0b0010 & op1 = 0b0010 & br & bs & bt & op0 = 0 { + br = bs || bt; +} + +# ORBC - Boolean Or with Complement, pg. 468. +:orbc br, bs, bt is op2 = 0b0011 & op1 = 0b0010 & br & bs & bt & op0 = 0 { + br = bs || !bt; +} + +# PDTLB - Probe Data TLB, pg. 469. +:pdtlb at, as is op2 = 0b0101 & op1 = 0 & ar = 0b1101 & as & at & op0 = 0 { + at = pdtlb(as); +} + +# PITLB - Probe Instruction TLB, pg. 470. +:pitlb at, as is op2 = 0b0101 & op1 = 0 & ar = 0b0101 & as & at & op0 = 0 { + at = pitlb(as); +} + +# QUOS - Quotient Signed, pg. 471. +:quos ar, as, at is op2 = 0b1101 & op1 = 0b0010 & ar & as & at & op0 = 0 { + ar = as s/ at; +} + +# QUOU - Quotient Unsigned, pg. 472. +:quou ar, as, at is op2 = 0b1100 & op1 = 0b0010 & ar & as & at & op0 = 0 { + ar = as / at; +} + +# RDTLB0 - Read Data TLB Virtual Entry, pg. 473. +:rdtlb0 at, as is op2 = 0b0101 & op1 = 0 & ar = 0b1011 & as & at & op0 = 0 { + at = rdtlb0(as); +} + +# RDTLB1 - Read Data TLB Entry Translation, pg. 474. +:rdtlb1 at, as is op2 = 0b0101 & op1 = 0 & ar = 0b1111 & as & at & op0 = 0 { + at = rdtlb1(as); +} + +# REMS - Remainder Signed, pg. 475. +:rems ar, as, at, is op2 = 0b1111 & op1 = 0b0010 & ar & as & at & op0 = 0 { + ar = as s% at; +} + +# REMU - Remainder Unsigned, pg. 476. +:remu ar, as, at, is op2 = 0b1110 & op1 = 0b0010 & ar & as & at & op0 = 0 { + ar = as % at; +} + +# RER - Read External Register, pg. 477. +:rer as, at is op2 = 0b0100 & op1 = 0 & ar = 0b0110 & as & at & op0 = 0 { + as = rer(at); +} + +# RET.N - Narrow Non-Windowed Return, pg. 479. +:ret.n is n_ar = 0b1111 & n_as = 0 & n_at = 0 & n_op0 = 0b1101 { + return [a0]; +} + +# RETW - Windowed Return, pg. 480. +:retw is op2 = 0 & op1 = 0 & ar = 0 & as = 0 & u2_6_7 = 0b10 & u2_4_5 = 0b01 & op0 = 0 { + local addr:4 = (a0 & 0x3fffffff) | (inst_start & 0xc0000000); + restoreRegWindow(); + return [addr]; +} + +# RETW.N - Narrow Windowed Return, pg. 482. +:retw.n is n_ar = 0b1111 & n_as = 0 & n_at = 0b0001 & n_op0 = 0b1101 { + local addr:4 = (a0 & 0x3fffffff) | (inst_start & 0xc0000000); + restoreRegWindow(); + return [addr]; +} + +# RFDD - Return from Debug and Dispatch, pg. 484. +:rfdd is op2 = 0b1111 & op1 = 0b0001 & ar = 0b1110 & (as = 0b0000 | as = 0b0001) & at = 0b0001 & op0 = 0 { + local tmp:4 = rfdd(); + return [tmp]; +} + +# RFDE _ Return From Double Exception, pg. 485. +:rfde is op2 = 0 & op1 = 0 & ar = 0b0011 & as =0b0010 & at = 0 & op0 = 0 { + local tmp:4 = rfde(); + return [tmp]; +} + +# RFDO - Return from Debug Operation, pg. 486. +:rfdo is op2 = 0b1111 & op1 = 0b0001 & ar = 0b1110 & as = 0 & at = 0 & op0 = 0 { + local tmp:4 = rfdo(); + return [tmp]; +} + +# RFE - Return From Exception, pg. 487. +:rfe is op2 = 0 & op1 = 0 & ar = 0b0011 & as = 0 & at = 0 & op0 = 0 { + local tmp:4 = rfe(); + return [tmp]; +} + +rfi_epc: ptr is u4_8_11 [ ptr = $(EPC_BASE) + (4 * u4_8_11); ] { export *[register]:4 ptr; } +rfi_eps: ptr is u4_8_11 [ ptr = $(EPS_BASE) + (4 * u4_8_11); ] { export *[register]:4 ptr; } + +# RFI - Return from High-Priority Interrupt, pg. 488. +:rfi u4_8_11 is op2 = 0 & op1 = 0 & ar = 0b0011 & u4_8_11 & at = 0b0001 & op0 = 0 & rfi_epc & rfi_eps { + PS = rfi_eps; + return [rfi_epc]; +} + +# RFME - Return from Memory Error, pg. 489. +:rfme is op2 = 0 & op1 = 0 & ar = 0b0011 & as = 0 & at = 0b0010 & op0 = 0 { + PS = MEPS; + MESR[0,1] = 0; + return [MEPC]; +} + +# RFR - Move FR to AR, pg. 490. +:rfr ar, fs is op2 = 0b1111 & op1 = 0b1010 & ar & fs & at = 0b0100 & op0 = 0 { + ar = fs; +} + +# RFUE - Return from User-Mode Exception, pg. 491. +:rfue is op2 = 0 & op1 = 0 & ar = 0b0011 & as = 0b0001 & at = 0 & op0 = 0 { + local tmp:4 = rfue(); + return [tmp]; +} + +# RFWO - Return from Window Overflow, pg. 492. +:rfwo is op2 = 0 & op1 = 0 & ar = 0b0011 & as = 0b0100 & at = 0 & op0 = 0 { + $(PS_EXCM) = 0; + rfwo(); + return [EPC1]; +} + +# RFWU - Return from Window Underflow, pg. 493. +:rfwu is op2 = 0 & op1 = 0 & ar = 0b0011 & as = 0b0101 & at = 0 & op0 = 0 { + $(PS_EXCM) = 0; + rfwu(); + return [EPC1]; +} + +# RITLB0 - Read Instruction TLB Virtual Entry, pg. 494. +:ritlb0 at, as is op2 = 0b0101 & op1 = 0 & ar = 0b0011 & as & at & op0 = 0 { + at = ritlb0(as); +} + +# RITLB1 - Read Instruction TLB Entry Translation, pg. 495. +:ritlb1 at, as is op2 = 0b0101 & op1 = 0 & ar = 0b0111 & as & at & op0 = 0 { + at = ritlb1(as); +} + +# ROTW - Rotate Window, pg. 496. +:rotw s4_4_7 is op2 = 0b0100 & op1 = 0 & ar = 0b1000 & as = 0 & s4_4_7 & op0 = 0 { + WindowBase = WindowBase + s4_4_7; +} + +# ROUND.S - Round Single to Fixed, pg. 497. +:round.s ar, fs, u4_4_7 is op2 = 0b1000 & op1 = 0b1010 & ar & fs & u4_4_7 & op0 = 0 { + local scale:4 = 1 << u4_4_7; + local result = fs f* int2float(scale); + isNan:1 = nan(result); + if (isNan) goto ; + ar = round(fs f* scale); + goto ; + + ar = 0x80000000; + if (fs f< 0) goto ; + ar = 0x7fffffff; + +} + +# RSIL - Read and Set Interrupt Level, pg. 498. +:rsil at, u4_8_11 is op2 = 0 & op1 = 0 & ar = 0b0110 & u4_8_11 & at & op0 = 0 { + at = rsil(u4_8_11:1); +} + +# RSR - Read Special Register, pg. 500. +:rsr at, sr is op0 = 0 & op1 = 0b0011 & sr & at & op0 = 0 { + at = rsr(sr:1); +} + +# RSYNC - Register Read Synchronize, pg. 502. +:rsync is op2 = 0 & op1 = 0 & ar = 0b0010 & as = 0 & at = 0b0001 & op0 = 0 { + rsync(); +} + + +# RUR - Read User Register, pg. 503. +:rur ar, u8_4_11 is op2 = 0b1110 & op1 = 0b0011 & ar & u8_4_11 & op0 = 0 { + ar = rur(u8_4_11:1); +} +# S8I - Store 8-bit, pg. 504. +:s8i at, as, u8_16_23 is u8_16_23 & ar = 0b0100 & as & at & op0 = 0b0010 { + local addr:4 = as + zext(u8_16_23:1); + *:1 addr = at:1; +} + +# S16I - Store 16-bit, pg. 505. +:s16i at, as, u9_16_23_sb1 is u9_16_23_sb1 & ar = 0b0101 & as & at & op0 = 0b0010 { + local addr:4 = as + u9_16_23_sb1; + *:2 addr = at:2; +} + +# S32C1I - Store 32-bit Compare Conditional, pg. 506 +:s32c1i at, as, u10_16_23_sb2 is u10_16_23_sb2 & ar = 0b1110 & as & at & op0 = 0b0010 { + local addr:4 = as + u10_16_23_sb2; + old:4 = *:4 addr; + if (old != SCOMPARE1) goto ; + *:4 addr = at; + + at = old; +} + +# S32E - Store 32-bit for Window Exceptions, pg. 508. +:s32e at, as, s5_12_15_oex is op2 = 0b0100 & op1 = 0b1001 & s5_12_15_oex & as & at & op0 = 0 { + ptr:4 = as + sext(s5_12_15_oex); + *:4 ptr = at; +} + +# S32I - Store 32-bit, pg. 510. +:s32i at, as, u10_16_23_sb2 is u10_16_23_sb2 & ar = 0b0110 & as & at & op0 = 0b0010 { + local addr:4 = as + u10_16_23_sb2; + *:4 addr = at; +} + +# S32I.N - Narrow Store 32-bit, pg. 512. +:s32i.n n_at, n_as, n_u6_12_15_sb2 is n_u6_12_15_sb2 & n_as & n_at & n_op0 = 0b1001 { + local addr:4 = n_as + n_u6_12_15_sb2; + *:4 addr = n_at; +} + +# S32RI - Store 32-bit Release, pg. 514. +:s32ri at, as, u10_16_23_sb2 is u10_16_23_sb2 & ar = 0b1111 & as & at & op0 = 0b0010 { + local addr:4 = as + u10_16_23_sb2; + release(addr); + *:4 addr = at; +} + +# SDCT - Store Data Cache Tag, pg. 516. +:sdct at, as is op2 = 0b1111 & op1 = 0b0001 & ar = 0b1001 & as & at & op0 = 0 { + sdct(as, at); +} + +# SEXT - Sign Extend, pg. 518. +:sext ar, as, u5_4_7_plus7 is op2 = 0b0010 & op1 = 0b0011 & ar & as & u5_4_7_plus7 & op0 = 0 { + local shift:4 = 31 - u5_4_7_plus7; + local tmp:4 = as << shift; + ar = tmp s>> shift; +} + +# SICT - Store Instruction Cache Tag, pg. 519. +:sict at, as is op2 = 0b1111 & op1 = 0b0001 & ar = 0b0001 & as & at & op0 = 0 { + sict(as, at); +} + +# SICW - Store Instruction Cache word, pg. 521. +:sicw at, as is op2 = 0b1111 & op1 = 0b0001 & ar = 0b0011 & as & at & op0 = 0 { + sicw(as, at); +} + +# SIMCALL - Simulator Call, pg. 523. +:simcall is op2 = 0 & op1 = 0 & ar = 0b0101 & as = 0b0001 & at = 0 & op0 = 0 { + simcall(); +} + +# SLL - Shift Left Logical, pg. 524. +:sll ar, as is op2 = 0b1010 & op1 = 0b0001 & ar & as & at = 0 & op0 = 0 { + local sa:4 = 32 - SAR; + ar = as << sa; +} + +# SLLI - Shift Left Logical Immediate, pg. 525. +:slli ar, as, u5_4_7_20 is u3_21_23 = 0 & u5_4_7_20 & op1 = 0b0001 & ar & as & op0 = 0 { + ar = as << u5_4_7_20; +} + +# SRA - Shift Right Arithmetic, pg. 526. +:sra ar, at is op2 = 0b1011 & op1 = 0b0001 & ar & as = 0 & at & op0 = 0 { + ar = at s>> SAR; +} + +# SRAI - Shift Right Arithmetic Immediate, pg. 527. +:srai ar, at, u5_8_11_20 is u3_21_23 = 0b001 & u5_8_11_20 & op1 = 0b0001 & ar & at & op0 = 0 { + ar = at s>> u5_8_11_20; +} + +# SRC - Shift Right Combined, pg. 528. +:src ar, as, at is op2 = 0b1000 & op1 = 0b0001 & ar & as & at & op0 = 0 { + local s64:8 = zext(as); + local t64:8 = zext(at); + local combined:8 = (s64 << 32) | t64; + local shifted:8 = combined >> SAR; + ar = shifted:4; +} + +# SRL - Shift Right Logical, pg. 529. +:srl ar, at is op2 = 0b1001 & op1 = 0b0001 & ar & as = 0 & at & op0 = 0 { + ar = at >> SAR; +} + +# SRLI - Shift Right Logical Immediate, pg. 530. +:srli ar, at, u4_8_11 is op2 = 0b0100 & op1 = 0b0001 & ar & u4_8_11 & at & op0 = 0 { + ar = at >> u4_8_11; +} + +# SSA8B - Set Shift Amount for BE Byte Shift, pg. 531. +:ssa8b as is op2 = 0b0100 & op1 = 0 & ar = 0b0011 & as & at = 0 & op0 = 0 { + local lsa:4 = (as&3)*8; + SAR = 32 - lsa; +} + +# SSA8L - Set Shift Amount for LE Byte Shift, pg. 532. +:ssa8l as is op2 = 0b0100 & op1 = 0 & ar = 0b0010 & as & at = 0 & op0 = 0 { + local rsa:4 = (as & 3)*8; + SAR = rsa; +} + +# SSAI - Set Shift Amount Immediate, pg. 533. +:ssai u5_8_11_4 is op2 = 0b0100 & op1 = 0 & ar = 0b0100 & u5_8_11_4 & u3_5_7 = 0 & op0 = 0 { + SAR = u5_8_11_4; +} + +# SSI - Store Single Immediate, pg. 534. +:ssi ft, as, u10_16_23_sb2 is u10_16_23_sb2 & ar = 0b0100 & as & ft & op0 = 0b0011 { + local addr:4 = as + u10_16_23_sb2; + *:4 addr = ft; +} + +# SSIU - Store Single Immediate with Update, pg. 536. +:ssiu ft, as, u10_16_23_sb2 is u10_16_23_sb2 & ar = 0b1100 & as & ft & op0 = 0b0011 { + local addr:4 = as + u10_16_23_sb2; + *:4 addr = ft; + as = addr; +} + +# SSL - Set Shift Amount for Left Shift, pg. 538. +:ssl as is op2 = 0b0100 & op1 = 0 & ar = 0b0001 & as & at = 0 & op0 = 0 { + SAR = 32 - (as & 0x1f); +} + +# SSR - Set Shift Amount for Right Shift, pg. 539. +:ssr as is op2 = 0b0100 & op1 = 0 & ar = 0 & as & at = 0 & op0 = 0 { + SAR = (as & 0x1f); +} + +# SSX - Store Single Indexed, pg. 540. +:ssx fr, as, at is op2 = 0b0100 & op1 = 0b1000 & fr & as & at & op0 = 0 { + local addr:4 = as+at; + *:4 addr = fr; +} + +# SSXU - Store Single Indexed with Update, pg. 541. +:ssxu fr, as, at is op2 = 0b0101 & op1 = 0b1000 & fr & as & at & op0 = 0 { + local addr:4 = as+at; + *:4 addr = fr; + as = addr; +} + +# SUB - Subtract, pg. 542. +:sub ar, as, at is op2 = 0b1100 & op1 = 0 & ar & as & at & op0 = 0 { + ar = as - at; +} + +# SUB.S - Subtract Single, pg. 543. +:sub.s fr, fs, ft is op2 = 0b0001 & op1 = 0b1010 & fr & fs & ft & op0 = 0 { + fr = fs f- ft; +} + +# SUBX2 - Subtract with Shift by 1, pg. 544. +:subx2 ar, as, at is op2 = 0b1101 & op1 = 0 & ar & as & at & op0 = 0 { + ar = (as << 1) - at; +} + +# SUBX4 - Subtract with Shift by 2, pg. 545. +:subx4 ar, as, at is op2 = 0b1110 & op1 = 0 & ar & as & at & op0 = 0 { + ar = (as << 2) - at; +} + +# SUBX8 - Subtract with Shift by 3, pg. 546. +:subx8 ar, as, at is op2 = 0b1111 & op1 = 0 & ar & as & at & op0 = 0 { + ar = (as << 3) - at; +} + +# SYSCALL - System Call, pg. 547. +:syscall is op2 = 0 & op1 = 0 & ar = 0b0101 & as = 0 & at = 0 & op0 = 0 { + syscall(); +} + +# TRUNC.S - Truncate Single to Fixed, pg. 548 +:trunc.s ar, fs, u4_4_7 is op2 = 0b1001 & op1 = 0b1010 & ar & fs & u4_4_7 & op0 = 0 { + local scale:4 = 1 << u4_4_7; + local result = fs f* int2float(scale); + isNan:1 = nan(result); + if (isNan) goto ; + ar = trunc(fs f* scale); + goto ; + + ar = 0x80000000; + if (fs f< 0) goto ; + ar = 0x7fffffff; + +} + +# UEQ.S - Compare Single Unordered or Equal, pg. 549. +:ueq.s br, fs, ft is op2 = 0b0011 & op1 = 0b1011 & br & fs & ft & op0 = 0 { + br = nan(fs) || nan(ft) || fs f== ft; +} + +# UFLOAT.S - Convert Unsigned Fixed to Single, pg. 550. +:ufloat.s fr, as, u4_4_7 is op2 = 0b1101 & op1 = 0b1010 & fr & as & u4_4_7 & op0 = 0 { + local tmp:8 = zext(as); + local scale:4 = 1 << u4_4_7; + fr = int2float(tmp) f/ int2float(scale); +} + +# ULE.S - Compare Single Unordered or Less Than or Equal, pg. 551. +:ule.s br, fs, ft is op2 = 0b0111 & op1 = 0b1011 & br & fs & ft & op0 = 0 { + br = nan(fs) || nan(ft) || fs f<= ft; +} + +# ULT.S - Compare Single Unordered or Less Than, pg. 552. +:ult.s br, fs, ft is op2 = 0b0101 & op1 = 0b1011 & br & fs & ft & op0 = 0 { + br = nan(fs) || nan(ft) || fs f< ft; +} + +# UN.S - Compare Single Unordered, pg. 554. +:un.s br, fs, ft is op2 = 0b0001 & op1 = 0b1011 & br & fs & ft & op0 = 0 { + br = nan(fs) || nan(ft); +} + +# UTRUNC.S - Truncate Single to Fixed Unsigned, pg. 555. +:utrunc.s ar, fs, u4_4_7 is op2 = 0b1110 & op1 = 0b1010 & ar & fs & u4_4_7 & op0 = 0 { + local scale:4 = int2float(1:2 << u4_4_7:2); + local tmp:8 = trunc(fs f* scale); + local posof = nan(fs) || (tmp >> 16) != 0; + local negof = tmp s< 0; + local noof = !posof && !negof; + ar = zext(posof)*0xffffffff + zext(negof)*0x80000000 + zext(noof)*tmp:4; +} + +# WAITI - Wait Interrupt, pg. 556. +:waiti u4_8_11 is op2 = 0 & op1 = 0 & ar = 0b0111 & u4_8_11 & at = 0 & op0 = 0 { + waiti(u4_8_11:4); +} + +# WDTLB - Write Data TLB Entry, pg. 557. +:wdtlb at, as is op2 = 0b0101 & op1 = 0 & ar = 0b1110 & as & at & op0 = 0 { + wdtlb(as, at); +} + +# WER - Write External Register, pg. 558. +:wer as, at is op2 = 0b0100 & op1 = 0 & ar = 0b0111 & as & at & op0 = 0 { + wer(as, at); +} + +# WFR - Move AR to FR, pg. 559. +:wfr fr, as is op2 = 0b1111 & op1 = 0b1010 & fr & as & at = 0b0101 & op0 = 0 { + fr = as; +} + +# WITLB - Write Instruction TLB Entry, pg. 560. +:witlb at, as is op2 = 0b0101 & op1 = 0 & ar = 0b0110 & as & at & op0 = 0 { + witlb(as, at); +} + +# WSR - Write Special Register, pg. 561. +:wsr at, sr is op2 = 0b0001 & op1 = 0b0011 & sr & at & op0 = 0 { + wsr(sr:1, at); +} + +# WUR - Write User Register, pg. 563. +:wur at, sr is op2 = 0b1111 & op1 = 0b0011 & sr & at & op0 = 0 { + wur(sr:1, at); +} + +# XOR - Bitwise Exclusive Or, pg. 564. +:xor ar, as, at is op2 = 0b0011 & op1 = 0 & ar & as & at & op0 = 0 { + ar = as ^ at; +} + +# XORB - Boolean Exclusive Or, pg. 565. +:xorb br, bs, bt is op2 = 0b0100 & op1 = 0b0010 & br & bs & bt & op0 = 0 { + br = bs ^^ bt; +} + +# XSR - Exchange Special Register, pg. 566. +:xsr at, sr is op2 = 0b0110 & op1 = 0b0001 & sr & at & op0 = 0 { + at = xsr(sr:1, at); +} + +## MAC16 option ## + +# LDDEC - Load with Autodecrement, pg. 386. +:lddec "MAC16_REGS[" mw_12_13 "]", as is op2 = 0b1001 & op1 = 0 & u2_14_15 = 0 & mw_12_13 & as & at = 0 & op0 = 0b0100 { + local ptr:4 = as - 4; + mw_12_13 = *:4 ptr; + as = ptr; +} + +# LDINC - Load with Autoincrement, pg. 387. +:ldinc "MAC16_REGS[" mw_12_13 "]", as is op2 = 0b1000 & op1 = 0 & u2_14_15 = 0 & mw_12_13 & as & at = 0 & op0 = 0b0100 { + local ptr:4 = as + 4; + mw_12_13 = *:4 ptr; + as = ptr; +} + +# MUL.AA.* - Signed Multiply, pg. 431. +:mul.aa.ll as, at is op2 = 0x7 & op1 = 0x4 & ar = 0 & as & at & op0 = 0x4 { + tm1:2 = as:2; + tm2:2 = at:2; + M1 = zext(tm1); + M2 = zext(tm2); + ACC = sext(M1:2) * sext(M2:2); +} +:mul.aa.hl as, at is op2 = 0x7 & op1 = 0x5 & ar = 0 & as & at & op0 = 0x4 { + tm1:2 = as(2); + tm2:2 = at:2; + M1 = zext(tm1); + M2 = zext(tm2); + ACC = sext(M1:2) * sext(M2:2); +} + +:mul.aa.lh as, at is op2 = 0x7 & op1 = 0x6 & ar = 0 & as & at & op0 = 0x4 { + tm1:2 = as:2; + tm2:2 = at(2); + M1 = zext(tm1); + M2 = zext(tm2); + ACC = sext(M1:2) * sext(M2:2); +} + +:mul.aa.hh as, at is op2 = 0x7 & op1 = 0x7 & ar = 0 & as & at & op0 = 0x4 { + tm1:2 = as(2); + tm2:2 = at(2); + M1 = zext(tm1); + M2 = zext(tm2); + ACC = sext(M1:2) * sext(M2:2); +} + +# MUL.AD.* - Signed Multiply, pg. 432. +:mul.ad.ll as, m2m3_6_6 is op2 = 0x3 & op1 = 0x4 & ar = 0 & as & u1_7_7 = 0 & u2_4_5 = 0 & m2m3_6_6 & op0 = 0x4 { + tm1:2 = as:2; + tm2:2 = m2m3_6_6:2; + M1 = zext(tm1); + M2 = zext(tm2); + ACC = sext(M1:2) * sext(M2:2); +} + +:mul.ad.hl as, m2m3_6_6 is op2 = 0x3 & op1 = 0x5 & ar = 0 & as & u1_7_7 = 0 & u2_4_5 = 0 & m2m3_6_6 & op0 = 0x4 { + tm1:2 = as(2); + tm2:2 = m2m3_6_6:2; + M1 = zext(tm1); + M2 = zext(tm2); + ACC = sext(M1:2) * sext(M2:2); +} +:mul.ad.lh as, m2m3_6_6 is op2 = 0x3 & op1 = 0x6 & ar = 0 & as & u1_7_7 = 0 & u2_4_5 = 0 & m2m3_6_6 & op0 = 0x4 { + tm1:2 = as:2; + tm2:2 = m2m3_6_6(2); + M1 = zext(tm1); + M2 = zext(tm2); + ACC = sext(M1:2) * sext(M2:2); +} +:mul.ad.hh as, m2m3_6_6 is op2 = 0x3 & op1 = 0x7 & ar = 0 & as & u1_7_7 = 0 & u2_4_5 = 0 & m2m3_6_6 & op0 = 0x4 { + tm1:2 = as(2); + tm2:2 = m2m3_6_6(2); + M1 = zext(tm1); + M2 = zext(tm2); + ACC = sext(M1:2) * sext(M2:2); +} + +# MUL.AD.* - Signed Multiply, pg. 433. +:mul.da.ll m0m1_14_14, at is op2 = 0x6 & at & op1 = 0x4 & as = 0 & u1_15_15 = 0 & u2_12_13 = 0 & m0m1_14_14 & op0 = 0x4 { + tm1:2 = m0m1_14_14:2; + tm2:2 = at:2; + M1 = zext(tm1); + M2 = zext(tm2); + ACC = sext(M1:2) * sext(M2:2); +} + +:mul.da.hl m0m1_14_14, at is op2 = 0x6 & op1 = 0x5 & as = 0 & u1_15_15 = 0 & u2_12_13 = 0 & m0m1_14_14 & at & op0 = 0x4 { + tm1:2 = m0m1_14_14:2; + tm2:2 = at(2); + M1 = zext(tm1); + M2 = zext(tm2); + ACC = sext(M1:2) * sext(M2:2); +} + +:mul.da.lh m0m1_14_14, at is op2 = 0x6 & op1 = 0x6 & as = 0 & u1_15_15 = 0 & u2_12_13 = 0 & m0m1_14_14 & at & op0 = 0x4 { + tm1:2 = m0m1_14_14(2); + tm2:2 = at:2; + M1 = zext(tm1); + M2 = zext(tm2); + ACC = sext(M1:2) * sext(M2:2); +} + +:mul.da.hh m0m1_14_14, at is op2 = 0x6 & op1 = 0x7 & as = 0 & u1_15_15 = 0 & u2_12_13 = 0 & m0m1_14_14 & at & op0 = 0x4 { + tm1:2 = m0m1_14_14(2); + tm2:2 = at(2); + M1 = zext(tm1); + M2 = zext(tm2); + ACC = sext(M1:2) * sext(M2:2); +} + +# MUL.AD.* - Signed Multiply, pg. 434. +:mul.dd.ll m0m1_14_14, m2m3_6_6 is op2 = 0x2 & op1 = 0x4 & ar = 0 & u1_15_15 = 0 & u2_12_13 = 0 & m0m1_14_14 & u1_7_7 = 0 & u2_4_5 = 0 & m2m3_6_6 & op0 = 0x4 { + tm1:2 = m0m1_14_14:2; + tm2:2 = m2m3_6_6:2; + M1 = zext(tm1); + M2 = zext(tm2); + ACC = sext(M1:2) * sext(M2:2); +} + +:mul.dd.hl m0m1_14_14, m2m3_6_6 is op2 = 0x2 & op1 = 0x5 & ar = 0 & u1_15_15 = 0 & u2_12_13 = 0 & m0m1_14_14 & u1_7_7 = 0 & u2_4_5 = 0 & m2m3_6_6 & op0 = 0x4 { + tm1:2 = m0m1_14_14(2); + tm2:2 = m2m3_6_6:2; + M1 = zext(tm1); + M2 = zext(tm2); + ACC = sext(M1:2) * sext(M2:2); +} + +:mul.dd.lh m0m1_14_14, m2m3_6_6 is op2 = 0x2 & op1 = 0x6 & ar = 0 & u1_15_15 = 0 & u2_12_13 = 0 & m0m1_14_14 & u1_7_7 = 0 & u2_4_5 = 0 & m2m3_6_6 & op0 = 0x4 { + tm1:2 = m0m1_14_14:2; + tm2:2 = m2m3_6_6(2); + M1 = zext(tm1); + M2 = zext(tm2); + ACC = sext(M1:2) * sext(M2:2); +} + +:mul.dd.hh m0m1_14_14, m2m3_6_6 is op2 = 0x2 & op1 = 0x7 & ar = 0 & u1_15_15 = 0 & u2_12_13 = 0 & m0m1_14_14 & u1_7_7 = 0 & u2_4_5 = 0 & m2m3_6_6 & op0 = 0x4 { + tm1:2 = m0m1_14_14(2); + tm2:2 = m2m3_6_6(2); + M1 = zext(tm1); + M2 = zext(tm2); + ACC = sext(M1:2) * sext(M2:2); +} + +# MULA.AA.* - Signed Multiply, pg. 431. +:mula.aa.ll as, at is op2 = 0x7 & op1 = 0x8 & ar = 0 & as & at & op0 = 0x4 { + tm1:2 = as:2; + tm2:2 = at:2; + M1 = zext(tm1); + M2 = zext(tm2); + ACC = ACC + (sext(M1:2) * sext(M2:2)); +} +:mula.aa.hl as, at is op2 = 0x7 & op1 = 0x9 & ar = 0 & as & at & op0 = 0x4 { + tm1:2 = as(2); + tm2:2 = at:2; + M1 = zext(tm1); + M2 = zext(tm2); + ACC = ACC + (sext(M1:2) * sext(M2:2)); +} + +:mula.aa.lh as, at is op2 = 0x7 & op1 = 0xa & ar = 0 & as & at & op0 = 0x4 { + tm1:2 = as:2; + tm2:2 = at(2); + M1 = zext(tm1); + M2 = zext(tm2); + ACC = ACC + (sext(M1:2) * sext(M2:2)); +} + +:mula.aa.hh as, at is op2 = 0x7 & op1 = 0xb & ar = 0 & as & at & op0 = 0x4 { + tm1:2 = as(2); + tm2:2 = at(2); + M1 = zext(tm1); + M2 = zext(tm2); + ACC = ACC + (sext(M1:2) * sext(M2:2)); +} + +:mula.ad.ll as, m2m3_6_6 is op2 = 0x3 & op1 = 0x8 & ar = 0 & as & u1_7_7 = 0 & u2_4_5 = 0 & m2m3_6_6 & op0 = 0x4 { + tm1:2 = as:2; + tm2:2 = m2m3_6_6:2; + M1 = zext(tm1); + M2 = zext(tm2); + ACC = ACC + (sext(M1:2) * sext(M2:2)); +} + +:mula.ad.hl as, m2m3_6_6 is op2 = 0x3 & op1 = 0x9 & ar = 0 & as & u1_7_7 = 0 & u2_4_5 = 0 & m2m3_6_6 & op0 = 0x4 { + tm1:2 = as(2); + tm2:2 = m2m3_6_6:2; + M1 = zext(tm1); + M2 = zext(tm2); + ACC = ACC + (sext(M1:2) * sext(M2:2)); +} +:mula.ad.lh as, m2m3_6_6 is op2 = 0x3 & op1 = 0xa & ar = 0 & as & u1_7_7 = 0 & u2_4_5 = 0 & m2m3_6_6 & op0 = 0x4 { + tm1:2 = as:2; + tm2:2 = m2m3_6_6(2); + M1 = zext(tm1); + M2 = zext(tm2); + ACC = ACC + (sext(M1:2) * sext(M2:2)); +} +:mula.ad.hh as, m2m3_6_6 is op2 = 0x3 & op1 = 0xb & ar = 0 & as & u1_7_7 = 0 & u2_4_5 = 0 & m2m3_6_6 & op0 = 0x4 { + tm1:2 = as(2); + tm2:2 = m2m3_6_6(2); + M1 = zext(tm1); + M2 = zext(tm2); + ACC = ACC + (sext(M1:2) * sext(M2:2)); +} + +:mula.da.ll m0m1_14_14, at is op2 = 0x6 & at & op1 = 0x8 & as = 0 & u1_15_15 = 0 & u2_12_13 = 0 & m0m1_14_14 & op0 = 0x4 { + tm1:2 = m0m1_14_14:2; + tm2:2 = at:2; + M1 = zext(tm1); + M2 = zext(tm2); + ACC = ACC + (sext(M1:2) * sext(M2:2)); +} + +:mula.da.hl m0m1_14_14, at is op2 = 0x6 & op1 = 0x9 & as = 0 & u1_15_15 = 0 & u2_12_13 = 0 & m0m1_14_14 & at & op0 = 0x4 { + tm1:2 = m0m1_14_14:2; + tm2:2 = at(2); + M1 = zext(tm1); + M2 = zext(tm2); + ACC = ACC + (sext(M1:2) * sext(M2:2)); +} + +:mula.da.lh m0m1_14_14, at is op2 = 0x6 & op1 = 0xa & as = 0 & u1_15_15 = 0 & u2_12_13 = 0 & m0m1_14_14 & at & op0 = 0x4 { + tm1:2 = m0m1_14_14(2); + tm2:2 = at:2; + M1 = zext(tm1); + M2 = zext(tm2); + ACC = ACC + (sext(M1:2) * sext(M2:2)); +} + +:mula.da.hh m0m1_14_14, at is op2 = 0x6 & op1 = 0xb & as = 0 & u1_15_15 = 0 & u2_12_13 = 0 & m0m1_14_14 & at & op0 = 0x4 { + tm1:2 = m0m1_14_14(2); + tm2:2 = at(2); + M1 = zext(tm1); + M2 = zext(tm2); + ACC = ACC + (sext(M1:2) * sext(M2:2)); +} + +:mula.dd.ll m0m1_14_14, m2m3_6_6 is op2 = 0x2 & op1 = 0x8 & ar = 0 & u1_15_15 = 0 & u2_12_13 = 0 & m0m1_14_14 & u1_7_7 = 0 & u2_4_5 = 0 & m2m3_6_6 & op0 = 0x4 { + tm1:2 = m0m1_14_14:2; + tm2:2 = m2m3_6_6:2; + M1 = zext(tm1); + M2 = zext(tm2); + ACC = ACC + (sext(M1:2) * sext(M2:2)); +} + +:mula.dd.hl m0m1_14_14, m2m3_6_6 is op2 = 0x2 & op1 = 0x9 & ar = 0 & u1_15_15 = 0 & u2_12_13 = 0 & m0m1_14_14 & u1_7_7 = 0 & u2_4_5 = 0 & m2m3_6_6 & op0 = 0x4 { + tm1:2 = m0m1_14_14(2); + tm2:2 = m2m3_6_6:2; + M1 = zext(tm1); + M2 = zext(tm2); + ACC = ACC + (sext(M1:2) * sext(M2:2)); +} + +:mula.dd.lh m0m1_14_14, m2m3_6_6 is op2 = 0x2 & op1 = 0xa & ar = 0 & u1_15_15 = 0 & u2_12_13 = 0 & m0m1_14_14 & u1_7_7 = 0 & u2_4_5 = 0 & m2m3_6_6 & op0 = 0x4 { + tm1:2 = m0m1_14_14:2; + tm2:2 = m2m3_6_6(2); + M1 = zext(tm1); + M2 = zext(tm2); + ACC = ACC + (sext(M1:2) * sext(M2:2)); +} + +:mula.dd.hh m0m1_14_14, m2m3_6_6 is op2 = 0x2 & op1 = 0xb & ar = 0 & u1_15_15 = 0 & u2_12_13 = 0 & m0m1_14_14 & u1_7_7 = 0 & u2_4_5 = 0 & m2m3_6_6 & op0 = 0x4 { + tm1:2 = m0m1_14_14(2); + tm2:2 = m2m3_6_6(2); + M1 = zext(tm1); + M2 = zext(tm2); + ACC = ACC + (sext(M1:2) * sext(M2:2)); +} + +# Signed Mult/Accum, Ld/Autodec MULA.DA.*.LDDEC, pg. 441. +:mula.da.ll.lddec mw_12_13, as, m0m1_14_14, at is op2 = 0x5 & at & op1 = 0x8 & as & u1_15_15 = 0 & mw_12_13 & m0m1_14_14 & op0 = 0x4 { + local vaddr:4 = as - 4; + tm1:2 = m0m1_14_14:2; + tm2:2 = at:2; + M1 = zext(tm1); + M2 = zext(tm2); + ACC = ACC + (sext(M1:2) * sext(M2:2)); + as = vaddr; + mw_12_13 = *:4 vaddr; +} + +:mula.da.hl.lddec mw_12_13, as, m0m1_14_14, at is op2 = 0x5 & op1 = 0x9 & as & u1_15_15 = 0 & mw_12_13 & m0m1_14_14 & at & op0 = 0x4 { + local vaddr:4 = as - 4; + tm1:2 = m0m1_14_14:2; + tm2:2 = at(2); + M1 = zext(tm1); + M2 = zext(tm2); + ACC = ACC + (sext(M1:2) * sext(M2:2)); + as = vaddr; + mw_12_13 = *:4 vaddr; +} + +:mula.da.lh.lddec mw_12_13, as, m0m1_14_14, at is op2 = 0x5 & op1 = 0xa & as & u1_15_15 = 0 & mw_12_13 & m0m1_14_14 & at & op0 = 0x4 { + local vaddr:4 = as - 4; + tm1:2 = m0m1_14_14(2); + tm2:2 = at:2; + M1 = zext(tm1); + M2 = zext(tm2); + ACC = ACC + (sext(M1:2) * sext(M2:2)); + as = vaddr; + mw_12_13 = *:4 vaddr; +} + +:mula.da.hh.lddec mw_12_13, as, m0m1_14_14, at is op2 = 0x5 & op1 = 0xb & as & u1_15_15 = 0 & mw_12_13 & m0m1_14_14 & at & op0 = 0x4 { + local vaddr:4 = as - 4; + tm1:2 = m0m1_14_14(2); + tm2:2 = at(2); + M1 = zext(tm1); + M2 = zext(tm2); + ACC = ACC + (sext(M1:2) * sext(M2:2)); + as = vaddr; + mw_12_13 = *:4 vaddr; +} + +# Signed Mult/Accum, Ld/Autoinc MULA.DA.*.LDINC, pg. 443. +:mula.da.ll.ldinc mw_12_13, as, m0m1_14_14, at is op2 = 0x4 & at & op1 = 0x8 & as & u1_15_15 = 0 & mw_12_13 & m0m1_14_14 & op0 = 0x4 { + local vaddr:4 = as + 4; + tm1:2 = m0m1_14_14:2; + tm2:2 = at:2; + M1 = zext(tm1); + M2 = zext(tm2); + ACC = ACC + (sext(M1:2) * sext(M2:2)); + as = vaddr; + mw_12_13 = *:4 vaddr; +} + +:mula.da.hl.ldinc mw_12_13, as, m0m1_14_14, at is op2 = 0x4 & op1 = 0x9 & as & u1_15_15 = 0 & mw_12_13 & m0m1_14_14 & at & op0 = 0x4 { + local vaddr:4 = as + 4; + tm1:2 = m0m1_14_14:2; + tm2:2 = at(2); + M1 = zext(tm1); + M2 = zext(tm2); + ACC = ACC + (sext(M1:2) * sext(M2:2)); + as = vaddr; + mw_12_13 = *:4 vaddr; +} + +:mula.da.lh.ldinc mw_12_13, as, m0m1_14_14, at is op2 = 0x4 & op1 = 0xa & as & u1_15_15 = 0 & mw_12_13 & m0m1_14_14 & at & op0 = 0x4 { + local vaddr:4 = as + 4; + tm1:2 = m0m1_14_14(2); + tm2:2 = at:2; + M1 = zext(tm1); + M2 = zext(tm2); + ACC = ACC + (sext(M1:2) * sext(M2:2)); + as = vaddr; + mw_12_13 = *:4 vaddr; +} + +:mula.da.hh.ldinc mw_12_13, as, m0m1_14_14, at is op2 = 0x4 & op1 = 0xb & as & u1_15_15 = 0 & mw_12_13 & m0m1_14_14 & at & op0 = 0x4 { + local vaddr:4 = as + 4; + tm1:2 = m0m1_14_14(2); + tm2:2 = at(2); + M1 = zext(tm1); + M2 = zext(tm2); + ACC = ACC + (sext(M1:2) * sext(M2:2)); + as = vaddr; + mw_12_13 = *:4 vaddr; +} + +# Signed Mult/Accum, Ld/Autodec MULA.DD.*.LDDEC, pg. 446. +:mula.dd.ll.lddec mw_12_13, as, m0m1_14_14, m2m3_6_6 is op2 = 0x1 & u1_7_7 = 0 & u2_4_5 = 0 & m2m3_6_6 & op1 = 0x8 & as & u1_15_15 = 0 & mw_12_13 & m0m1_14_14 & op0 = 0x4 { + local vaddr:4 = as - 4; + tm1:2 = m0m1_14_14:2; + tm2:2 = m2m3_6_6:2; + M1 = zext(tm1); + M2 = zext(tm2); + ACC = ACC + (sext(M1:2) * sext(M2:2)); + as = vaddr; + mw_12_13 = *:4 vaddr; +} + +:mula.dd.hl.lddec mw_12_13, as, m0m1_14_14, m2m3_6_6 is op2 = 0x1 & op1 = 0x9 & as & u1_15_15 = 0 & mw_12_13 & m0m1_14_14 & u1_7_7 = 0 & u2_4_5 = 0 & m2m3_6_6 & op0 = 0x4 { + local vaddr:4 = as - 4; + tm1:2 = m0m1_14_14:2; + tm2:2 = m2m3_6_6(2); + M1 = zext(tm1); + M2 = zext(tm2); + ACC = ACC + (sext(M1:2) * sext(M2:2)); + as = vaddr; + mw_12_13 = *:4 vaddr; +} + +:mula.dd.lh.lddec mw_12_13, as, m0m1_14_14, m2m3_6_6 is op2 = 0x1 & op1 = 0xa & as & u1_15_15 = 0 & mw_12_13 & m0m1_14_14 & u1_7_7 = 0 & u2_4_5 = 0 & m2m3_6_6 & op0 = 0x4 { + local vaddr:4 = as - 4; + tm1:2 = m0m1_14_14(2); + tm2:2 = m2m3_6_6:2; + M1 = zext(tm1); + M2 = zext(tm2); + ACC = ACC + (sext(M1:2) * sext(M2:2)); + as = vaddr; + mw_12_13 = *:4 vaddr; +} + +:mula.dd.hh.lddec mw_12_13, as, m0m1_14_14, m2m3_6_6 is op2 = 0x1 & op1 = 0xb & as & u1_15_15 = 0 & mw_12_13 & m0m1_14_14 & u1_7_7 = 0 & u2_4_5 = 0 & m2m3_6_6 & op0 = 0x4 { + local vaddr:4 = as - 4; + tm1:2 = m0m1_14_14(2); + tm2:2 = m2m3_6_6(2); + M1 = zext(tm1); + M2 = zext(tm2); + ACC = ACC + (sext(M1:2) * sext(M2:2)); + as = vaddr; + mw_12_13 = *:4 vaddr; +} + +# Signed Mult/Accum, Ld/Autoinc MULA.DD.*.LDINC, pg. 448. +:mula.da.ll.ldinc mw_12_13, as, m0m1_14_14, m2m3_6_6 is op2 = 0x0 & op1 = 0x8 & as & u1_15_15 = 0 & mw_12_13 & m0m1_14_14 & u1_7_7 = 0 & u2_4_5 = 0 & m2m3_6_6 & op0 = 0x4 { + local vaddr:4 = as + 4; + tm1:2 = m0m1_14_14:2; + tm2:2 = m2m3_6_6:2; + M1 = zext(tm1); + M2 = zext(tm2); + ACC = ACC + (sext(M1:2) * sext(M2:2)); + as = vaddr; + mw_12_13 = *:4 vaddr; +} + +:mula.da.hl.ldinc mw_12_13, as, m0m1_14_14, m2m3_6_6 is op2 = 0x0 & op1 = 0x9 & as & u1_15_15 = 0 & mw_12_13 & m0m1_14_14 & u1_7_7 = 0 & u2_4_5 = 0 & m2m3_6_6 & op0 = 0x4 { + local vaddr:4 = as + 4; + tm1:2 = m0m1_14_14:2; + tm2:2 = m2m3_6_6(2); + M1 = zext(tm1); + M2 = zext(tm2); + ACC = ACC + (sext(M1:2) * sext(M2:2)); + as = vaddr; + mw_12_13 = *:4 vaddr; +} + +:mula.da.lh.ldinc mw_12_13, as, m0m1_14_14, m2m3_6_6 is op2 = 0x0 & op1 = 0xa & as & u1_15_15 = 0 & mw_12_13 & m0m1_14_14 & u1_7_7 = 0 & u2_4_5 = 0 & m2m3_6_6 & op0 = 0x4 { + local vaddr:4 = as + 4; + tm1:2 = m0m1_14_14(2); + tm2:2 = m2m3_6_6:2; + M1 = zext(tm1); + M2 = zext(tm2); + ACC = ACC + (sext(M1:2) * sext(M2:2)); + as = vaddr; + mw_12_13 = *:4 vaddr; +} + +:mula.da.hh.ldinc mw_12_13, as, m0m1_14_14, m2m3_6_6 is op2 = 0x0 & op1 = 0xb & as & u1_15_15 = 0 & mw_12_13 & m0m1_14_14 & u1_7_7 = 0 & u2_4_5 = 0 & m2m3_6_6 & op0 = 0x4 { + local vaddr:4 = as + 4; + tm1:2 = m0m1_14_14(2); + tm2:2 = m2m3_6_6(2); + M1 = zext(tm1); + M2 = zext(tm2); + ACC = ACC + (sext(M1:2) * sext(M2:2)); + as = vaddr; + mw_12_13 = *:4 vaddr; +} + +# UMUL.AA.* - Unsigned Multiply, pg. 553. +:umul.aa.ll as, at is op2 = 0x7 & op1 = 0x0 & ar = 0 & as & at & op0 = 0x4 { + tm1:2 = as:2; + tm2:2 = at:2; + M1 = zext(tm1); + M2 = zext(tm2); + ACC = zext(M1:2) * zext(M2:2); +} +:umul.aa.hl as, at is op2 = 0x7 & op1 = 0x1 & ar = 0 & as & at & op0 = 0x4 { + tm1:2 = as(2); + tm2:2 = at:2; + M1 = zext(tm1); + M2 = zext(tm2); + ACC = zext(M1:2) * zext(M2:2); +} + +:umul.aa.lh as, at is op2 = 0x7 & op1 = 0x2 & ar = 0 & as & at & op0 = 0x4 { + tm1:2 = as:2; + tm2:2 = at(2); + M1 = zext(tm1); + M2 = zext(tm2); + ACC = zext(M1:2) * zext(M2:2); +} + +:umul.aa.hh as, at is op2 = 0x7 & op1 = 0x3 & ar = 0 & as & at & op0 = 0x4 { + tm1:2 = as(2); + tm2:2 = at(2); + M1 = zext(tm1); + M2 = zext(tm2); + ACC = zext(M1:2) * zext(M2:2); +} + +## Loop Option ## + +LoopOffset8: loc is u8_16_23 [ loc = inst_start + u8_16_23 + 4; ] { export *:4 loc; } + +# LOOP - Loop, pg. 392. +:loop as, LoopOffset8 is LoopOffset8 & ar = 8 & as & at = 0b0111 & op0 = 6 + [ loopMode=1; loopEnd = 1; globalset(LoopOffset8, loopEnd); ] { + LCOUNT = as - 1; + LBEG = inst_next; + LEND = &LoopOffset8; +} + +# LOOPGTZ - Loop if Greater Than Zero, pg. 394. +:loopgtz as, LoopOffset8 is LoopOffset8 & ar = 0b1010 & as & at = 0b0111 & op0 = 0b0110 + [ loopMode=1; loopEnd = 1; globalset(LoopOffset8, loopEnd); ] { + LCOUNT = as - 1; + LBEG = inst_next; + LEND = &LoopOffset8; + if (as s<= 0) goto LoopOffset8; +} + +# LOOPNEZ - Loop if Not Equal Zero, pg. 396. +:loopnez as, LoopOffset8 is LoopOffset8 & ar = 0b1001 & as & at = 0b0111 & op0 = 0b0110 + [ loopMode=1; loopEnd = 1; globalset(LoopOffset8, loopEnd); ] { + LCOUNT = as - 1; + LBEG = inst_next; + LEND = &LoopOffset8; + if (as == 0) goto LoopOffset8; +} diff --git a/Ghidra/Processors/Xtensa/data/languages/xtensaMain.sinc b/Ghidra/Processors/Xtensa/data/languages/xtensaMain.sinc new file mode 100644 index 0000000000..dd13ae72fb --- /dev/null +++ b/Ghidra/Processors/Xtensa/data/languages/xtensaMain.sinc @@ -0,0 +1,116 @@ +# Various 32-bit pointers relative to PC. Any operands that are split across non-consecutive +# bits are named foo_LL_LM_ML_MM, where LL is the least significant bits of the least +# singificant operand half, LM the most significant bits of the least significant operand half, etc. + +srel_16_23: rel is s8_16_23 [ rel = inst_start + s8_16_23 + 4; ] { export *:4 rel; } + +srel_12_23: rel is s12_12_23 [ rel = inst_start + s12_12_23 + 4; ] { export *:4 rel; } + +srel_6_23: rel is s8_6_23 [ rel = inst_start + s8_6_23 + 4; ] { export *:4 rel; } + +urel_12_15_4_5: rel is n_u2_4_5 & n_u4_12_15 [ + rel = inst_start + ((n_u2_4_5 << 4) | n_u4_12_15) + 4; +] { export *:4 rel; } + +srel_6_23_sb2: rel is s8_6_23 [ + rel = (inst_start & ~3) + ( s8_6_23 << 2 ) + 4; +] { export *:4 rel; } + +srel_8_23_oex_sb2: rel is u16_8_23 [ + rel = ((inst_start + 3) & ~3) + ((u16_8_23 | 0xffff0000) << 2); +] { export *:4 rel; } + +# Immediates split across the instruction. +u5_8_11_20: tmp is u1_20 & u4_8_11 [ tmp = (u1_20 << 4) | u4_8_11; ] { export *[const]:4 tmp; } +u5_4_7_20: tmp is u1_20 & u4_4_7 [ tmp = 32 - ((u1_20 << 4) | u4_4_7); ] { export *[const]:4 tmp; } +u5_8_11_16: tmp is u1_16 & u4_8_11 [ tmp = (u1_16 << 4) | u4_8_11; ] { export *[const]:4 tmp; } +u5_4_7_12: tmp is u1_12 & u4_4_7 [ tmp = (u1_12 << 4) | u4_4_7; ] { export *[const]:4 tmp; } +u5_8_11_4: tmp is u1_4 & u4_8_11 [ tmp = (u1_4 << 4) | u4_8_11; ] { export *[const]:4 tmp; } + +# Signed 12-bit (extended to 16) immediate, used by MOVI. +s16_16_23_8_11: tmp is s4_8_11 & u8_16_23 [ + tmp = (s4_8_11 << 8) | u8_16_23; +] { export *[const]:2 tmp; } + +# An “asymmetric” immediate from -32..95, used by MOVI.N. +n_s8_12_15_4_6_asymm: tmp is n_s3_4_6 & n_s4_12_15 [ + tmp = ((((n_s3_4_6 & 7) << 4) | (n_s4_12_15 & 15)) | + ((((n_s3_4_6 >> 2) & 1) & ((n_s3_4_6 >> 1) & 1)) << 7)); +] { export *[const]:1 tmp; } + +# Immediates shifted or with offset. +s16_16_23_sb8: tmp is s8_16_23 [ tmp = s8_16_23 << 8; ] { export *[const]:4 tmp; } +u15_12_23_sb3: tmp is u12_12_23 [ tmp = u12_12_23 << 3; ] { export *[const]:4 tmp; } +u10_16_23_sb2: tmp is u8_16_23 [ tmp = u8_16_23 << 2; ] { export *[const]:4 tmp; } +u9_16_23_sb1: tmp is u8_16_23 [ tmp = u8_16_23 << 1; ] { export *[const]:4 tmp; } +u5_20_23_plus1: tmp is u4_20_23 [ tmp = u4_20_23 + 1; ] { export *[const]:4 tmp; } +u8_20_23_sb4: tmp is u4_20_23 [ tmp = u4_20_23 << 4; ] { export *[const]:4 tmp; } +u5_4_7_plus7: tmp is u4_4_7 [ tmp = u4_4_7 + 7; ] { export *[const]:4 tmp; } + +n_u6_12_15_sb2: tmp is n_u4_12_15 [ tmp = n_u4_12_15 << 2; ] { export *[const]:4 tmp; } + +# One-extended. FIXME: Verify this. Only used by [LS]32E (window extension), which aren’t yet +# implemented. +s5_12_15_oex: tmp is u4_12_15 [ tmp = (u4_12_15 << 2) - 64; ] { export *[const]:2 tmp; } + +# Some 4-bit immediates with mappings that can’t be (easily) expressed in a single disassembly action. + +# n_u4_4_7 with 0 being -1, used by ADDI.N. +n_s4_4_7_nozero: tmp is n_u4_4_7 = 0 [ tmp = -1; ] { export *[const]:4 tmp; } +n_s4_4_7_nozero: tmp is n_u4_4_7 [ tmp = n_u4_4_7+0; ] { export *[const]:4 tmp; } + +# B4CONST(ar) (Branch Immediate) encodings, pg. 41 f. +r_b4const: tmp is ar = 0 [ tmp = 0xffffffff; ] { export *[const]:4 tmp; } +r_b4const: tmp is ar = 1 [ tmp = 0x1; ] { export *[const]:4 tmp; } +r_b4const: tmp is ar = 2 [ tmp = 0x2; ] { export *[const]:4 tmp; } +r_b4const: tmp is ar = 3 [ tmp = 0x3; ] { export *[const]:4 tmp; } +r_b4const: tmp is ar = 4 [ tmp = 0x4; ] { export *[const]:4 tmp; } +r_b4const: tmp is ar = 5 [ tmp = 0x5; ] { export *[const]:4 tmp; } +r_b4const: tmp is ar = 6 [ tmp = 0x6; ] { export *[const]:4 tmp; } +r_b4const: tmp is ar = 7 [ tmp = 0x7; ] { export *[const]:4 tmp; } +r_b4const: tmp is ar = 8 [ tmp = 0x8; ] { export *[const]:4 tmp; } +r_b4const: tmp is ar = 9 [ tmp = 0xa; ] { export *[const]:4 tmp; } +r_b4const: tmp is ar = 10 [ tmp = 0xc; ] { export *[const]:4 tmp; } +r_b4const: tmp is ar = 11 [ tmp = 0x10; ] { export *[const]:4 tmp; } +r_b4const: tmp is ar = 12 [ tmp = 0x20; ] { export *[const]:4 tmp; } +r_b4const: tmp is ar = 13 [ tmp = 0x40; ] { export *[const]:4 tmp; } +r_b4const: tmp is ar = 14 [ tmp = 0x80; ] { export *[const]:4 tmp; } +r_b4const: tmp is ar = 15 [ tmp = 0x100; ] { export *[const]:4 tmp; } + +# B4CONSTU(ar) (Branch Unsigned Immediate) encodings, pg. 42. +r_b4constu: tmp is ar = 0 [ tmp = 0x8000; ] { export *[const]:4 tmp; } +r_b4constu: tmp is ar = 1 [ tmp = 0x1000; ] { export *[const]:4 tmp; } +r_b4constu: tmp is ar = 2 [ tmp = 0x2; ] { export *[const]:4 tmp; } +r_b4constu: tmp is ar = 3 [ tmp = 0x3; ] { export *[const]:4 tmp; } +r_b4constu: tmp is ar = 4 [ tmp = 0x4; ] { export *[const]:4 tmp; } +r_b4constu: tmp is ar = 5 [ tmp = 0x5; ] { export *[const]:4 tmp; } +r_b4constu: tmp is ar = 6 [ tmp = 0x6; ] { export *[const]:4 tmp; } +r_b4constu: tmp is ar = 7 [ tmp = 0x7; ] { export *[const]:4 tmp; } +r_b4constu: tmp is ar = 8 [ tmp = 0x8; ] { export *[const]:4 tmp; } +r_b4constu: tmp is ar = 9 [ tmp = 0xa; ] { export *[const]:4 tmp; } +r_b4constu: tmp is ar = 10 [ tmp = 0xc; ] { export *[const]:4 tmp; } +r_b4constu: tmp is ar = 11 [ tmp = 0x10; ] { export *[const]:4 tmp; } +r_b4constu: tmp is ar = 12 [ tmp = 0x20; ] { export *[const]:4 tmp; } +r_b4constu: tmp is ar = 13 [ tmp = 0x40; ] { export *[const]:4 tmp; } +r_b4constu: tmp is ar = 14 [ tmp = 0x80; ] { export *[const]:4 tmp; } +r_b4constu: tmp is ar = 15 [ tmp = 0x100; ] { export *[const]:4 tmp; } + +Ret4: loc is epsilon [loc = ((inst_start + 3) & 0x0fffffff) | 0x40000000; ] { ret:4 = loc; export ret; } +Ret8: loc is epsilon [loc = ((inst_start + 3) & 0x0fffffff) | 0x80000000; ] { ret:4 = loc; export ret; } +Ret12: loc is epsilon [loc = ((inst_start + 3) & 0x0fffffff) | 0xc0000000; ] { ret:4 = loc; export ret; } + +:^instruction is phase=0 & loopMode=1 & instruction [ phase=1; ] { + build instruction; + if (LCOUNT == 0 || $(PS_EXCM)) goto inst_next; + LCOUNT = LCOUNT - 1; + goto [LBEG]; +} +:^instruction is phase=0 & loopMode=1 & loopEnd=1 & instruction + [ loopMode=0; phase=1; ] { + build instruction; +} + +:^instruction is phase=0 & loopMode=0 & instruction + [ phase=1; ] { + build instruction; +} diff --git a/Ghidra/Processors/Xtensa/data/languages/xtensa_be.slaspec b/Ghidra/Processors/Xtensa/data/languages/xtensa_be.slaspec new file mode 100644 index 0000000000..ba7d290dfb --- /dev/null +++ b/Ghidra/Processors/Xtensa/data/languages/xtensa_be.slaspec @@ -0,0 +1,12 @@ +@define ENDIAN "big" +@include "xtensaArch.sinc" +@include "xtensaMain.sinc" + +with : phase=1 { + +@include "xtensaInstructions.sinc" +#@include "xtensa_depbits.sinc" #uncomment this to use depbits instruction, collides with floating point +@include "cust.sinc" +@include "flix.sinc" + +} \ No newline at end of file diff --git a/Ghidra/Processors/Xtensa/data/languages/xtensa_depbits.sinc b/Ghidra/Processors/Xtensa/data/languages/xtensa_depbits.sinc new file mode 100644 index 0000000000..ccf799116e --- /dev/null +++ b/Ghidra/Processors/Xtensa/data/languages/xtensa_depbits.sinc @@ -0,0 +1,11 @@ +# Xtensa Deposit Bits instruction +# This is broken out because it collides with the floating point instructions. It is not included by default + +# DEPBITS - Add (RRR), pg. 394. +shiftimm: simm is u4_20_23 & u1_16 [ simm = u1_16 << 4 + u4_20_23; ] { export *[const]:4 simm; } +:depbits as, at, shiftimm, u4_12_15 is u3_17_19=0x5 & u4_12_15 & as & at & op0 = 0 & shiftimm { + mask:4 = (1 << u4_12_15) - 1; + bits:4 = (as & mask) << shiftimm; + mask = mask << shiftimm; + at = (~mask & at) | bits; +} diff --git a/Ghidra/Processors/Xtensa/data/languages/xtensa_le.slaspec b/Ghidra/Processors/Xtensa/data/languages/xtensa_le.slaspec new file mode 100644 index 0000000000..fb9a8373f6 --- /dev/null +++ b/Ghidra/Processors/Xtensa/data/languages/xtensa_le.slaspec @@ -0,0 +1,12 @@ +@define ENDIAN "little" +@include "xtensaArch.sinc" +@include "xtensaMain.sinc" + +with : phase=1 { + +@include "xtensaInstructions.sinc" +#@include "xtensa_depbits.sinc" #uncomment this to use depbits instruction, collides with floating point +@include "cust.sinc" +@include "flix.sinc" + +} diff --git a/Ghidra/Processors/Xtensa/data/manuals/xtensa.idx b/Ghidra/Processors/Xtensa/data/manuals/xtensa.idx new file mode 100644 index 0000000000..d8025054d8 --- /dev/null +++ b/Ghidra/Processors/Xtensa/data/manuals/xtensa.idx @@ -0,0 +1,354 @@ +@isa_summary.pdf[Xtensa® Instruction Set Architecture Summary, For all Xtensa LX Processors April 2022] + +ABS, 324 +ABS.D, 324 +ABS.S, 325 +ADD, 326 +ADD.N, 326 +ADD.D, 327 +ADD.S, 328 +ADDEXP.D, 329 +ADDEXP.S, 329 +ADDEXPM.D, 330 +ADDEXPM.S, 331 +ADDI, 332 +ADDI.N, 333 +ADDMI, 334 +ADDX2, 335 +ADDX4, 336 +ADDX8, 336 +ALL4, 337 +ALL8, 338 +AND, 339 +ANDB, 339 +ANDBC, 340 +ANY4, 341 +ANY8, 341 +BALL, 342 +BANY, 343 +BBC, 344 +BBCI, 345 +BBCI.L, 346 +BBS, 347 +BBSI, 348 +BBSI.L, 349 +BEQ, 349 +BEQI, 350 +BEQZ, 351 +BEQZ.N, 352 +BF, 353 +BGE, 354 +BGEI, 355 +ixBGEU, 356 +BGEUI, 357 +BGEZ, 358 +BLT, 359 +BLTI, 360 +BLTU, 361 +BLTUI, 361 +BLTZ, 362 +BNALL, 363 +BNE, 364 +BNEI, 365 +BNEZ, 366 +BNEZ.N, 367 +BNONE, 368 +BREAK, 369 +BREAK.N, 370 +BT, 371 +CALL0, 372 +CALL4 373 +CALL8, 375 +CALL12, 376 +CALLX0, 377 +CALLX4, 378 +CALLX8, 379 +CALLX12, 380 +CEIL.D, 382 +CEIL.S, 383 +CLAMPS, 383 +CLREX, 384 +CONST.D, 385 +CONST.S, 386 +CONST16, 387 +CVTD.S, 388 +CVTS.D, 389 +DCI, 389 +DCWB, 391 +DCWBI, 392 +DEPBITS, 394 +DHI, 395 +DHI.B, 396 +DHU, 397 +DHWB, 398 +DHWB.B, 400 +DHWBI, 400 +DHWBI.B, 402 +xDII, 403 +DIU, 404 +DIV0.D, 406 +DIV0.S, 406 +DIVN.D, 407 +DIVN.S, 408 +DIWB, 409 +DIWBI, 410 +DIWBUI.P, 412 +DPFL, 413 +DPFM.B, 415 +DPFM.BF, 416 +DPFR, 416 +DPFR.B, 418 +DPFR.BF, 419 +DPFRO, 419 +DPFW, 421 +DPFW.B, 422 +DPFW.BF, 423 +DPFWO, 424 +DSYNC, 425 +ENTRY, 426 +ESYNC, 427 +EXCW, 428 +EXTUI, 429 +EXTW, 430 +FLOAT.D, 431 +FLOAT.S, 431 +FLOOR.D, 432 +FLOOR.S, 433 +FSYNC, 434 +GETEX, 434 +IDTLB, 435 +IHI, 436 +IHU, 438 +III, 439 +IITLB, 441 +IIU, 442 +ILL, 443 +ILL.N, 444 +IPF, 444 +IPFL, 446 +ISYNC, 447 +J, 449 +J.L, 449 +JX, 450 +L8UI, 450 +L16SI, 451 +L16UI, 453 +L32AI, 454 +L32E, 455 +L32EX, 457 +L32I, 458 +L32I.N, 459 +L32R, 461 +LDCT, 463 +LDCW, 464 +LDDEC, 465 +LDDR32.P, 467 +LDI, 467 +LDINC, 468 +LDIP, 469 +LDX, 471 +LDXP, 472 +LOOP, 473 +LOOPGTZ, 475 +LOOPNEZ, 476 +LSI, 478 +LSIP, 480 +LSIU, 481 +LSX, 482 +LSXP, 483 +LSXU, 484 +MADD.D, 486 +MADD.S, 486 +MADDN.D, 487 +MADDN.S, 488 +MAX, 489 +MAXU, 489 +MEMW, 490 +MIN, 491 +MINU, 491 +MKDADJ.D, 492 +MKDADJ.S, 493 +MKSADJ.D, 494 +MKSADJ.S, 494 +MOV, 495 +MOV.D, 496 +MOV.N, 497 +MOV.S, 498 +MOVEQZ, 499 +MOVEQZ.D, 499 +MOVEQZ.S, 500 +MOVF, 501 +MOVF.D, 502 +MOVF.S, 503 +MOVGEZ, 504 +MOVGEZ.D, 504 +MOVGEZ.S, 505 +MOVI, 506 +MOVI.N, 507 +MOVLTZ, 508 +MOVLTZ.D, 509 +MOVLTZ.S, 510 +MOVNEZ, 510 +MOVNEZ.D, 511 +MOVNEZ.S, 512 +MOVSP, 513 +MOVT, 514 +MOVT.D, 515 +MOVT.S, 516 +MSUB.D, 517 +MSUB.S, 517 +MUL.AA.*, 518 +MUL.AD.*, 519 +MUL.DA.*, 520 +MUL.DD.*, 521 +MUL.D, 522 +MUL.S, 522 +MUL16S, 523 +MUL16U, 524 +MULA.AA.*, 524 +MULA.AD.*, 525 +MULA.DA.*, 526 +MULA.DA.*.LDDEC, 527 +MULA.DA.*.LDINC, 528 +MULA.DD.*, 530 +MULA.DD.*.LDDEC 531 +MULA.DD.*.LDINC 532 +MULL, 534 +MULS.AA.*, 535 +MULS.AD.*, 535 +MULS.DA.*, 536 +MULS.DD.*, 537 +MULSH, 538 +MULUH, 539 +NEG, 540 +NEG.D, 540 +NEG.S, 541 +NEXP01.D, 541 +NEXP01.S, 542 +NOP, 543 +NOP.N, 544 +NSA, 545 +NSAU, 546 +OEQ.D, 547 +OEQ.S, 547 +OLE.D, 548 +OLE.S, 549 +OLT.D, 550 +OLT.S, 551 +OR, 551 +ORB, 552 +ORBC, 553 +TLB, 553 +PITLB, 554 +PPTLB, 555 +QUOS, 556 +QUOU, 557 +RDTLB0, 558 +RDTLB1, 559 +RECIP0.D, 560 +RECIP0.S, 560 +REMS, 561 +REMU, 562 +RER, 563 +RET, 564 +RET.N, 564 +RETW, 565 +RETW.N, 567 +RFDD, 568 +RFDE, 569 +RFDO, 570 +RFE, 570 +RFI, 571 +RFME, 572 +RFR, 573 +RFRD, 573 +RFUE, 574 +RFWO, 575 +RFWU, 576 +RITLB0, 576 +RITLB1, 577 +ROTW, 578 +ROUND.D, 579 +ROUND.S, 580 +RPTLB0, 580 +RPTLB1, 581 +RSIL, 582 +RSQRT0.D, 583 +RSQRT0.S, 584 +RSR.*, 585 +RSYNC, 586 +RUR.*, 586 +S8I, 587 +S16I, 588 +S32C1I, 589 +S32E, 591 +S32EX, 592 +S32I, 594 +S32I.N, 595 +S32NB, 596 +S32RI, 597 +SALT, 599 +SALTU, 600 +SDDR32.P, 600 +SDI, 601 +SDIP, 602 +SDX, 603 +SDXP, 604 +SEXT, 605 +SICT, 606 +SICW, 607 +SIMCALL, 609 +SLL, 609 +SLLI, 610 +SQRT0.D, 611 +SQRT0.S, 612 +SRA, 613 +SRAI, 613 +SRC, 614 +SRL, 615 +SRLI, 616 +SSA8B, 616 +SSA8L, 617 +SSAI, 618 +SSI, 619 +SSIP, 620 +SSIU, 621 +SSL, 622 +SSR, 623 +SSX, 624 +SSXP, 625 +SSXU, 626 +SUB, 627 +SUB.D, 627 +SUB.S, 628 +SUBX2, 629 +SUBX4, 629 +SUBX8, 630 +SYSCALL, 631 +TRUNC.D, 632 +TRUNC.S, 632 +UEQ.D, 633 +UEQ.S, 634 +UFLOAT.D, 635 +UFLOAT.S, 636 +ULE.D, 636 +ULE.S, 637 +ULT.D, 638 +ULT.S, 639 +UMUL.AA.*, 639 +UN.D, 640 +UN.S, 641 +UTRUNC.D, 642 +UTRUNC.S, 642 +WAITI, 643 +WDTLB, 644 +WER, 645 +WFR, 646 +WFRD, 647 +WITLB, 648 +WPTLB, 649 +WSR.*, 650 +WUR.*, 651 +XOR, 652 +XORB, 652 +XSR.*, 653 diff --git a/Ghidra/Processors/Xtensa/data/patterns/patternconstraints.xml b/Ghidra/Processors/Xtensa/data/patterns/patternconstraints.xml new file mode 100644 index 0000000000..9372bd55fe --- /dev/null +++ b/Ghidra/Processors/Xtensa/data/patterns/patternconstraints.xml @@ -0,0 +1,7 @@ + + + + xtensa_patterns.xml + + + \ No newline at end of file diff --git a/Ghidra/Processors/Xtensa/data/patterns/xtensa_patterns.xml b/Ghidra/Processors/Xtensa/data/patterns/xtensa_patterns.xml new file mode 100644 index 0000000000..25c06c2fe7 --- /dev/null +++ b/Ghidra/Processors/Xtensa/data/patterns/xtensa_patterns.xml @@ -0,0 +1,98 @@ + + + + + + 0x0d 0xf0 + 0x0d 0xf0 0x00 + 0x0d 0xf0 0x00 0x00 + 0x0d 0xf0 0x00 0x00 0x00 + + 0x80 0x00 0x00 + 0x80 0x00 0x00 0x00 + 0x80 0x00 0x00 0x00 0x00 + 0x80 0x00 0x00 0x00 0x00 0x00 + + + 00010010 11000001 1...0000 + ....0010 10100... ........ ....0000 00010001 11000000 + + + + + + + + 0x1d 0xf0 + 0x1d 0xf0 0x00 + 0x1d 0xf0 0x00 0x00 + 0x1d 0xf0 0x00 0x00 0x00 + + + 0x36 ...00001 0x00 + + + + + + + 00010010 11000001 0...0000 00001101 11110000 + 00010010 11000001 0...0000 00001101 11110000 00000000 + 00010010 11000001 0...0000 00001101 11110000 00000000 00000000 + 00010010 11000001 0...0000 00001101 11110000 00000000 00000000 00000000 + + ....1010 00010001 00001101 11110000 + ....1010 00010001 00001101 11110000 00000000 + ....1010 00010001 00001101 11110000 00000000 00000000 + ....1010 00010001 00001101 11110000 00000000 00000000 00000000 + + + 00010010 11000001 1...0000 + ....0010 10100... ........ ....0000 00010001 11000000 + + + + + + + + ..000110 ........ 1....... + ..000110 ........ 1....... 00000000 + ..000110 ........ 1....... 00000000 00000000 + ..000110 ........ 1....... 00000000 00000000 00000000 + + + ....0010 10100... ........ ....0000 00010001 11000000 + 00010010 11000001 1...0000 + + + + + + + ....0010 10100... ........ ....0000 00010001 11000000 + + + + + + 00010010 11000001 1...0000 + + + + + + 0x12 0xc1 0xf0 0x09 0x01 ..000101 ........ ........ 0x08 0x01 0x12 0xc1 0x10 0x0d 0xf0 + + + + + + diff --git a/Ghidra/Processors/Xtensa/src/main/java/ghidra/app/util/bin/format/elf/relocation/Xtensa_ElfRelocationConstants.java b/Ghidra/Processors/Xtensa/src/main/java/ghidra/app/util/bin/format/elf/relocation/Xtensa_ElfRelocationConstants.java new file mode 100644 index 0000000000..e5b9598490 --- /dev/null +++ b/Ghidra/Processors/Xtensa/src/main/java/ghidra/app/util/bin/format/elf/relocation/Xtensa_ElfRelocationConstants.java @@ -0,0 +1,73 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.bin.format.elf.relocation; + +public class Xtensa_ElfRelocationConstants { + /* Xtensa processor ELF architecture-magic number */ + + // EM_XTENSA is already definded + public static final int EM_XTENSA_OLD = 0xABC7; + + /* Xtensa relocations defined by the ABIs */ + + public static final int R_XTENSA_NONE = 0; + public static final int R_XTENSA_32 = 1; + public static final int R_XTENSA_RTLD = 2; + public static final int R_XTENSA_GLOB_DAT = 3; + public static final int R_XTENSA_JMP_SLOT = 4; + public static final int R_XTENSA_RELATIVE = 5; + public static final int R_XTENSA_PLT = 6; + public static final int R_XTENSA_OP0 = 8; + public static final int R_XTENSA_OP1 = 9; + public static final int R_XTENSA_OP2 = 10; + public static final int R_XTENSA_ASM_EXPAND = 11; + public static final int R_XTENSA_ASM_SIMPLIFY = 12; + public static final int R_XTENSA_GNU_VTINHERIT = 15; + public static final int R_XTENSA_GNU_VTENTRY = 16; + public static final int R_XTENSA_DIFF8 = 17; + public static final int R_XTENSA_DIFF16 = 18; + public static final int R_XTENSA_DIFF32 = 19; + public static final int R_XTENSA_SLOT0_OP = 20; + public static final int R_XTENSA_SLOT1_OP = 21; + public static final int R_XTENSA_SLOT2_OP = 22; + public static final int R_XTENSA_SLOT3_OP = 23; + public static final int R_XTENSA_SLOT4_OP = 24; + public static final int R_XTENSA_SLOT5_OP = 25; + public static final int R_XTENSA_SLOT6_OP = 26; + public static final int R_XTENSA_SLOT7_OP = 27; + public static final int R_XTENSA_SLOT8_OP = 28; + public static final int R_XTENSA_SLOT9_OP = 29; + public static final int R_XTENSA_SLOT10_OP = 30; + public static final int R_XTENSA_SLOT11_OP = 31; + public static final int R_XTENSA_SLOT12_OP = 32; + public static final int R_XTENSA_SLOT13_OP = 33; + public static final int R_XTENSA_SLOT14_OP = 34; + public static final int R_XTENSA_SLOT0_ALT = 35; + public static final int R_XTENSA_SLOT1_ALT = 36; + public static final int R_XTENSA_SLOT2_ALT = 37; + public static final int R_XTENSA_SLOT3_ALT = 38; + public static final int R_XTENSA_SLOT4_ALT = 39; + public static final int R_XTENSA_SLOT5_ALT = 40; + public static final int R_XTENSA_SLOT6_ALT = 41; + public static final int R_XTENSA_SLOT7_ALT = 42; + public static final int R_XTENSA_SLOT8_ALT = 43; + public static final int R_XTENSA_SLOT9_ALT = 44; + public static final int R_XTENSA_SLOT10_ALT = 45; + public static final int R_XTENSA_SLOT11_ALT = 46; + public static final int R_XTENSA_SLOT12_ALT = 47; + public static final int R_XTENSA_SLOT13_ALT = 48; + public static final int R_XTENSA_SLOT14_ALT = 49; +} diff --git a/Ghidra/Processors/Xtensa/src/main/java/ghidra/app/util/bin/format/elf/relocation/Xtensa_ElfRelocationHandler.java b/Ghidra/Processors/Xtensa/src/main/java/ghidra/app/util/bin/format/elf/relocation/Xtensa_ElfRelocationHandler.java new file mode 100644 index 0000000000..279ebe4e1c --- /dev/null +++ b/Ghidra/Processors/Xtensa/src/main/java/ghidra/app/util/bin/format/elf/relocation/Xtensa_ElfRelocationHandler.java @@ -0,0 +1,209 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.bin.format.elf.relocation; + +import ghidra.app.util.bin.format.elf.*; +import ghidra.program.model.address.Address; +import ghidra.program.model.listing.Program; +import ghidra.program.model.mem.MemoryAccessException; +import ghidra.program.model.reloc.RelocationResult; +import ghidra.util.exception.NotFoundException; + +public class Xtensa_ElfRelocationHandler extends ElfRelocationHandler { + + @Override + public boolean canRelocate(ElfHeader elf) { + return elf.e_machine() == ElfConstants.EM_XTENSA || + elf.e_machine() == Xtensa_ElfRelocationConstants.EM_XTENSA_OLD; + } + + @Override + public RelocationResult relocate(ElfRelocationContext elfRelocationContext, + ElfRelocation relocation, Address relocationAddress) + throws MemoryAccessException, NotFoundException { + ElfHeader elf = elfRelocationContext.getElfHeader(); + if (!canRelocate(elf)) { + return RelocationResult.FAILURE; + } + + int type = relocation.getType(); + if (Xtensa_ElfRelocationConstants.R_XTENSA_NONE == type) { + return RelocationResult.SKIPPED; + } + + Program program = elfRelocationContext.getProgram(); + + ElfSymbol sym = null; + String symbolName = null; + + int symbolIndex = relocation.getSymbolIndex(); + if (symbolIndex != 0) { + sym = elfRelocationContext.getSymbol(symbolIndex); + } + + if (null != sym) { + symbolName = sym.getNameAsString(); + } + + //int byteLength = 4; // most relocations affect 4-bytes (change if different) + + switch (type) { + case Xtensa_ElfRelocationConstants.R_XTENSA_32: + markAsWarning(program, relocationAddress, "R_XTENSA_32", symbolName, symbolIndex, + "TODO, needs support ", elfRelocationContext.getLog()); + case Xtensa_ElfRelocationConstants.R_XTENSA_RTLD: + markAsWarning(program, relocationAddress, "R_XTENSA_RTLD", symbolName, symbolIndex, + "TODO, needs support ", elfRelocationContext.getLog()); + case Xtensa_ElfRelocationConstants.R_XTENSA_GLOB_DAT: + markAsWarning(program, relocationAddress, "R_XTENSA_GLOB_DAT", symbolName, + symbolIndex, "TODO, needs support ", elfRelocationContext.getLog()); + case Xtensa_ElfRelocationConstants.R_XTENSA_JMP_SLOT: + markAsWarning(program, relocationAddress, "R_XTENSA_JMP_SLOT", symbolName, + symbolIndex, "TODO, needs support ", elfRelocationContext.getLog()); + case Xtensa_ElfRelocationConstants.R_XTENSA_RELATIVE: + markAsWarning(program, relocationAddress, "R_XTENSA_RELATIVE", symbolName, + symbolIndex, "TODO, needs support ", elfRelocationContext.getLog()); + case Xtensa_ElfRelocationConstants.R_XTENSA_PLT: + markAsWarning(program, relocationAddress, "R_XTENSA_PLT", symbolName, symbolIndex, + "TODO, needs support ", elfRelocationContext.getLog()); + case Xtensa_ElfRelocationConstants.R_XTENSA_OP0: + markAsWarning(program, relocationAddress, "R_XTENSA_OP0", symbolName, symbolIndex, + "TODO, needs support ", elfRelocationContext.getLog()); + case Xtensa_ElfRelocationConstants.R_XTENSA_OP1: + markAsWarning(program, relocationAddress, "R_XTENSA_OP1", symbolName, symbolIndex, + "TODO, needs support ", elfRelocationContext.getLog()); + case Xtensa_ElfRelocationConstants.R_XTENSA_OP2: + markAsWarning(program, relocationAddress, "R_XTENSA_OP2", symbolName, symbolIndex, + "TODO, needs support ", elfRelocationContext.getLog()); + case Xtensa_ElfRelocationConstants.R_XTENSA_ASM_EXPAND: + markAsWarning(program, relocationAddress, "R_XTENSA_ASM_EXPAND", symbolName, + symbolIndex, "TODO, needs support ", elfRelocationContext.getLog()); + case Xtensa_ElfRelocationConstants.R_XTENSA_ASM_SIMPLIFY: + markAsWarning(program, relocationAddress, "R_XTENSA_ASM_SIMPLIFY", symbolName, + symbolIndex, "TODO, needs support ", elfRelocationContext.getLog()); + case Xtensa_ElfRelocationConstants.R_XTENSA_GNU_VTINHERIT: + markAsWarning(program, relocationAddress, "R_XTENSA_GNU_VTINHERIT", symbolName, + symbolIndex, "TODO, needs support ", elfRelocationContext.getLog()); + case Xtensa_ElfRelocationConstants.R_XTENSA_GNU_VTENTRY: + markAsWarning(program, relocationAddress, "R_XTENSA_GNU_VTENTRY", symbolName, + symbolIndex, "TODO, needs support ", elfRelocationContext.getLog()); + case Xtensa_ElfRelocationConstants.R_XTENSA_DIFF8: + markAsWarning(program, relocationAddress, "R_XTENSA_DIFF8", symbolName, symbolIndex, + "TODO, needs support ", elfRelocationContext.getLog()); + case Xtensa_ElfRelocationConstants.R_XTENSA_DIFF16: + markAsWarning(program, relocationAddress, "R_XTENSA_DIFF16", symbolName, + symbolIndex, "TODO, needs support ", elfRelocationContext.getLog()); + case Xtensa_ElfRelocationConstants.R_XTENSA_DIFF32: + markAsWarning(program, relocationAddress, "R_XTENSA_DIFF32", symbolName, + symbolIndex, "TODO, needs support ", elfRelocationContext.getLog()); + case Xtensa_ElfRelocationConstants.R_XTENSA_SLOT0_OP: + markAsWarning(program, relocationAddress, "R_XTENSA_SLOT0_OP", symbolName, + symbolIndex, "TODO, needs support ", elfRelocationContext.getLog()); + case Xtensa_ElfRelocationConstants.R_XTENSA_SLOT1_OP: + markAsWarning(program, relocationAddress, "R_XTENSA_SLOT1_OP", symbolName, + symbolIndex, "TODO, needs support ", elfRelocationContext.getLog()); + case Xtensa_ElfRelocationConstants.R_XTENSA_SLOT2_OP: + markAsWarning(program, relocationAddress, "R_XTENSA_SLOT2_OP", symbolName, + symbolIndex, "TODO, needs support ", elfRelocationContext.getLog()); + case Xtensa_ElfRelocationConstants.R_XTENSA_SLOT3_OP: + markAsWarning(program, relocationAddress, "R_XTENSA_SLOT3_OP", symbolName, + symbolIndex, "TODO, needs support ", elfRelocationContext.getLog()); + case Xtensa_ElfRelocationConstants.R_XTENSA_SLOT4_OP: + markAsWarning(program, relocationAddress, "R_XTENSA_SLOT4_OP", symbolName, + symbolIndex, "TODO, needs support ", elfRelocationContext.getLog()); + case Xtensa_ElfRelocationConstants.R_XTENSA_SLOT5_OP: + markAsWarning(program, relocationAddress, "R_XTENSA_SLOT5_OP", symbolName, + symbolIndex, "TODO, needs support ", elfRelocationContext.getLog()); + case Xtensa_ElfRelocationConstants.R_XTENSA_SLOT6_OP: + markAsWarning(program, relocationAddress, "R_XTENSA_SLOT6_OP", symbolName, + symbolIndex, "TODO, needs support ", elfRelocationContext.getLog()); + case Xtensa_ElfRelocationConstants.R_XTENSA_SLOT7_OP: + markAsWarning(program, relocationAddress, "R_XTENSA_SLOT7_OP", symbolName, + symbolIndex, "TODO, needs support ", elfRelocationContext.getLog()); + case Xtensa_ElfRelocationConstants.R_XTENSA_SLOT8_OP: + markAsWarning(program, relocationAddress, "R_XTENSA_SLOT8_OP", symbolName, + symbolIndex, "TODO, needs support ", elfRelocationContext.getLog()); + case Xtensa_ElfRelocationConstants.R_XTENSA_SLOT9_OP: + markAsWarning(program, relocationAddress, "R_XTENSA_SLOT9_OP", symbolName, + symbolIndex, "TODO, needs support ", elfRelocationContext.getLog()); + case Xtensa_ElfRelocationConstants.R_XTENSA_SLOT10_OP: + markAsWarning(program, relocationAddress, "R_XTENSA_SLOT10_OP", symbolName, + symbolIndex, "TODO, needs support ", elfRelocationContext.getLog()); + case Xtensa_ElfRelocationConstants.R_XTENSA_SLOT11_OP: + markAsWarning(program, relocationAddress, "R_XTENSA_SLOT11_OP", symbolName, + symbolIndex, "TODO, needs support ", elfRelocationContext.getLog()); + case Xtensa_ElfRelocationConstants.R_XTENSA_SLOT12_OP: + markAsWarning(program, relocationAddress, "R_XTENSA_SLOT12_OP", symbolName, + symbolIndex, "TODO, needs support ", elfRelocationContext.getLog()); + case Xtensa_ElfRelocationConstants.R_XTENSA_SLOT13_OP: + markAsWarning(program, relocationAddress, "R_XTENSA_SLOT13_OP", symbolName, + symbolIndex, "TODO, needs support ", elfRelocationContext.getLog()); + case Xtensa_ElfRelocationConstants.R_XTENSA_SLOT14_OP: + markAsWarning(program, relocationAddress, "R_XTENSA_SLOT14_OP", symbolName, + symbolIndex, "TODO, needs support ", elfRelocationContext.getLog()); + case Xtensa_ElfRelocationConstants.R_XTENSA_SLOT0_ALT: + markAsWarning(program, relocationAddress, "R_XTENSA_SLOT0_ALT", symbolName, + symbolIndex, "TODO, needs support ", elfRelocationContext.getLog()); + case Xtensa_ElfRelocationConstants.R_XTENSA_SLOT1_ALT: + markAsWarning(program, relocationAddress, "R_XTENSA_SLOT1_ALT", symbolName, + symbolIndex, "TODO, needs support ", elfRelocationContext.getLog()); + case Xtensa_ElfRelocationConstants.R_XTENSA_SLOT2_ALT: + markAsWarning(program, relocationAddress, "R_XTENSA_SLOT2_ALT", symbolName, + symbolIndex, "TODO, needs support ", elfRelocationContext.getLog()); + case Xtensa_ElfRelocationConstants.R_XTENSA_SLOT3_ALT: + markAsWarning(program, relocationAddress, "R_XTENSA_SLOT3_ALT", symbolName, + symbolIndex, "TODO, needs support ", elfRelocationContext.getLog()); + case Xtensa_ElfRelocationConstants.R_XTENSA_SLOT4_ALT: + markAsWarning(program, relocationAddress, "R_XTENSA_SLOT4_ALT", symbolName, + symbolIndex, "TODO, needs support ", elfRelocationContext.getLog()); + case Xtensa_ElfRelocationConstants.R_XTENSA_SLOT5_ALT: + markAsWarning(program, relocationAddress, "R_XTENSA_SLOT5_ALT", symbolName, + symbolIndex, "TODO, needs support ", elfRelocationContext.getLog()); + case Xtensa_ElfRelocationConstants.R_XTENSA_SLOT6_ALT: + markAsWarning(program, relocationAddress, "R_XTENSA_SLOT6_ALT", symbolName, + symbolIndex, "TODO, needs support ", elfRelocationContext.getLog()); + case Xtensa_ElfRelocationConstants.R_XTENSA_SLOT7_ALT: + markAsWarning(program, relocationAddress, "R_XTENSA_SLOT7_ALT", symbolName, + symbolIndex, "TODO, needs support ", elfRelocationContext.getLog()); + case Xtensa_ElfRelocationConstants.R_XTENSA_SLOT8_ALT: + markAsWarning(program, relocationAddress, "R_XTENSA_SLOT8_ALT", symbolName, + symbolIndex, "TODO, needs support ", elfRelocationContext.getLog()); + case Xtensa_ElfRelocationConstants.R_XTENSA_SLOT9_ALT: + markAsWarning(program, relocationAddress, "R_XTENSA_SLOT9_ALT", symbolName, + symbolIndex, "TODO, needs support ", elfRelocationContext.getLog()); + case Xtensa_ElfRelocationConstants.R_XTENSA_SLOT10_ALT: + markAsWarning(program, relocationAddress, "R_XTENSA_SLOT10_ALT", symbolName, + symbolIndex, "TODO, needs support ", elfRelocationContext.getLog()); + case Xtensa_ElfRelocationConstants.R_XTENSA_SLOT11_ALT: + markAsWarning(program, relocationAddress, "R_XTENSA_SLOT11_ALT", symbolName, + symbolIndex, "TODO, needs support ", elfRelocationContext.getLog()); + case Xtensa_ElfRelocationConstants.R_XTENSA_SLOT12_ALT: + markAsWarning(program, relocationAddress, "R_XTENSA_SLOT12_ALT", symbolName, + symbolIndex, "TODO, needs support ", elfRelocationContext.getLog()); + case Xtensa_ElfRelocationConstants.R_XTENSA_SLOT13_ALT: + markAsWarning(program, relocationAddress, "R_XTENSA_SLOT13_ALT", symbolName, + symbolIndex, "TODO, needs support ", elfRelocationContext.getLog()); + case Xtensa_ElfRelocationConstants.R_XTENSA_SLOT14_ALT: + markAsWarning(program, relocationAddress, "R_XTENSA_SLOT14_ALT", symbolName, + symbolIndex, "TODO, needs support ", elfRelocationContext.getLog()); + default: + markAsUnhandled(program, relocationAddress, type, symbolIndex, symbolName, + elfRelocationContext.getLog()); + } + return RelocationResult.UNSUPPORTED; + } + +} diff --git a/Ghidra/Processors/Xtensa/src/main/java/ghidra/program/emulation/XtensaEmulateInstructionStateModifier.java b/Ghidra/Processors/Xtensa/src/main/java/ghidra/program/emulation/XtensaEmulateInstructionStateModifier.java new file mode 100644 index 0000000000..ecd6264872 --- /dev/null +++ b/Ghidra/Processors/Xtensa/src/main/java/ghidra/program/emulation/XtensaEmulateInstructionStateModifier.java @@ -0,0 +1,159 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.program.emulation; + +import java.util.Stack; + +import ghidra.pcode.emulate.Emulate; +import ghidra.pcode.emulate.EmulateInstructionStateModifier; +import ghidra.pcode.emulate.callother.OpBehaviorOther; +import ghidra.pcode.emulate.callother.OpBehaviorOtherNOP; +import ghidra.pcode.error.LowlevelError; +import ghidra.pcode.memstate.MemoryState; +import ghidra.program.model.address.Address; +import ghidra.program.model.lang.Register; +import ghidra.program.model.pcode.Varnode; + +public class XtensaEmulateInstructionStateModifier extends EmulateInstructionStateModifier { + + private Stack stashStack = new Stack(); + public XtensaEmulateInstructionStateModifier(Emulate emu) { + super(emu); + + registerPcodeOpBehavior("rotateRegWindow", new RotateRegWindow()); + registerPcodeOpBehavior("restoreRegWindow", new RestoreRegWindow()); + + registerPcodeOpBehavior("swap4", new OpBehaviorOtherNOP()); + registerPcodeOpBehavior("swap8", new OpBehaviorOtherNOP()); + registerPcodeOpBehavior("swap12", new OpBehaviorOtherNOP()); + registerPcodeOpBehavior("restore4", new OpBehaviorOtherNOP()); + registerPcodeOpBehavior("restore8", new OpBehaviorOtherNOP()); + registerPcodeOpBehavior("restore12", new OpBehaviorOtherNOP()); + } + + private class RotateRegWindow implements OpBehaviorOther { + + @Override + public void evaluate(Emulate emu, Varnode out, Varnode[] inputs) { + if (inputs.length != 2) { + throw new LowlevelError("rotateRegWindow: missing required CALLINC input"); + } + + MemoryState memoryState = emu.getMemoryState(); + Varnode in = inputs[1]; + long callinc = memoryState.getValue(in); + if (callinc == 0) { + return; + } + if (callinc < 0 || callinc > 3) { + throw new LowlevelError("rotateRegWindow: invalid value for CALLINC (0x" + + Long.toHexString(callinc) + ")"); + } + + // push window onto stack + stashStack.push(new RegisterStash((int) callinc)); + + //rotate registers + Address baseARegAddr = language.getRegister("a0").getAddress(); + int count = (int) callinc << 2; // windowSize + long windowRegOffset = count * 4; + count = 16 - count; + + for (int i = 0; i < count; i++) { + Varnode fromRegVarnode = + new Varnode(baseARegAddr.add(windowRegOffset + (i * 4)), 4); + Varnode toRegVarnode = new Varnode(baseARegAddr.add(i * 4), 4); + long value = memoryState.getValue(fromRegVarnode); + memoryState.setValue(toRegVarnode, value); + } + } + } + + private class RestoreRegWindow implements OpBehaviorOther { + + @Override + public void evaluate(Emulate emu, Varnode out, Varnode[] inputs) { + if (inputs.length != 1) { + throw new LowlevelError("restoreRegWindow: unexpected input varnodes"); + } + + MemoryState memoryState = emu.getMemoryState(); + + Register a0Reg = language.getRegister("a0"); + long callinc = (memoryState.getValue(a0Reg) >> 30) & 0x3; + if (callinc == 0) { + return; + } + + if (stashStack.isEmpty()) { + throw new LowlevelError("restoreRegWindow: window register stash is empty"); + } + + RegisterStash stash = stashStack.peek(); + if (callinc != stash.callinc) { + throw new LowlevelError("restoreRegWindow: return address CALLINC (" + callinc + + ") does not match last entry CALLINC value (" + stash.callinc + ")"); + } + + //rotate registers + Address baseARegAddr = language.getRegister("a0").getAddress(); + int count = (int) callinc << 2; // windowSize + long windowRegOffset = count * 4; + count = 16 - count; + + for (int i = 0; i < count; i++) { + Varnode fromRegVarnode = new Varnode(baseARegAddr.add(i * 4), 4); + Varnode toRegVarnode = new Varnode(baseARegAddr.add(windowRegOffset + (i * 4)), 4); + long value = memoryState.getValue(fromRegVarnode); + memoryState.setValue(toRegVarnode, value); + } + + // remove from stack and restore + stashStack.pop(); + stash.restore(); + } + } + + private class RegisterStash { + private int callinc; + private int[] values; + + RegisterStash(int callinc) { + this.callinc = callinc; + + MemoryState memoryState = emu.getMemoryState(); + Address baseARegAddr = language.getRegister("a0").getAddress(); + + int count = callinc << 2; + values = new int[count]; + + for (int i = 0; i < count; i++) { + Varnode regVarnode = new Varnode(baseARegAddr.add(4 * i), 4); + values[i] = (int) memoryState.getValue(regVarnode); + } + } + + public void restore() { + MemoryState memoryState = emu.getMemoryState(); + Address baseARegAddr = language.getRegister("a0").getAddress(); + + for (int i = 0; i < values.length; i++) { + Varnode regVarnode = new Varnode(baseARegAddr.add(4 * i), 4); + memoryState.setValue(regVarnode, values[i]); + } + } + } +} diff --git a/Ghidra/Processors/Xtensa/src/test.processors/java/ghidra/test/processors/Xtensa_O0_EmulatorTest.java b/Ghidra/Processors/Xtensa/src/test.processors/java/ghidra/test/processors/Xtensa_O0_EmulatorTest.java new file mode 100644 index 0000000000..628919694d --- /dev/null +++ b/Ghidra/Processors/Xtensa/src/test.processors/java/ghidra/test/processors/Xtensa_O0_EmulatorTest.java @@ -0,0 +1,40 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.test.processors; + +import ghidra.test.processors.support.ProcessorEmulatorTestAdapter; +import junit.framework.Test; + +public class Xtensa_O0_EmulatorTest extends ProcessorEmulatorTestAdapter { + + private static final String LANGUAGE_ID = "Xtensa:LE:32:default"; + private static final String COMPILER_SPEC_ID = "default"; + + private static final String[] REG_DUMP_SET = new String[] {}; + + public Xtensa_O0_EmulatorTest(String name) throws Exception { + super(name, LANGUAGE_ID, COMPILER_SPEC_ID, REG_DUMP_SET); + } + + @Override + protected String getProcessorDesignator() { + return "Xtensa_GCC_O0"; + } + + public static Test suite() { + return ProcessorEmulatorTestAdapter.buildEmulatorTestSuite(Xtensa_O0_EmulatorTest.class); + } +} diff --git a/Ghidra/Processors/Xtensa/src/test.processors/java/ghidra/test/processors/Xtensa_O3_EmulatorTest.java b/Ghidra/Processors/Xtensa/src/test.processors/java/ghidra/test/processors/Xtensa_O3_EmulatorTest.java new file mode 100644 index 0000000000..b0b7962368 --- /dev/null +++ b/Ghidra/Processors/Xtensa/src/test.processors/java/ghidra/test/processors/Xtensa_O3_EmulatorTest.java @@ -0,0 +1,40 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.test.processors; + +import ghidra.test.processors.support.ProcessorEmulatorTestAdapter; +import junit.framework.Test; + +public class Xtensa_O3_EmulatorTest extends ProcessorEmulatorTestAdapter { + + private static final String LANGUAGE_ID = "Xtensa:LE:32:default"; + private static final String COMPILER_SPEC_ID = "default"; + + private static final String[] REG_DUMP_SET = new String[] {}; + + public Xtensa_O3_EmulatorTest(String name) throws Exception { + super(name, LANGUAGE_ID, COMPILER_SPEC_ID, REG_DUMP_SET); + } + + @Override + protected String getProcessorDesignator() { + return "Xtensa_GCC_O3"; + } + + public static Test suite() { + return ProcessorEmulatorTestAdapter.buildEmulatorTestSuite(Xtensa_O3_EmulatorTest.class); + } +}