]>
Commit | Line | Data |
---|---|---|
b738c106 HC |
1 | /* SPDX-License-Identifier: GPL-2.0 */ |
2 | /* | |
3 | * Copyright (C) 2020-2022 Loongson Technology Corporation Limited | |
4 | */ | |
5 | #ifndef _ASM_INST_H | |
6 | #define _ASM_INST_H | |
7 | ||
0d03e9dc | 8 | #include <linux/bitops.h> |
b738c106 HC |
9 | #include <linux/types.h> |
10 | #include <asm/asm.h> | |
9b3441a6 | 11 | #include <asm/ptrace.h> |
b738c106 | 12 | |
19e5eb15 | 13 | #define INSN_NOP 0x03400000 |
4e59e5a4 TY |
14 | #define INSN_BREAK 0x002a0000 |
15 | ||
b738c106 HC |
16 | #define ADDR_IMMMASK_LU52ID 0xFFF0000000000000 |
17 | #define ADDR_IMMMASK_LU32ID 0x000FFFFF00000000 | |
28ac0a9e | 18 | #define ADDR_IMMMASK_LU12IW 0x00000000FFFFF000 |
0d03e9dc | 19 | #define ADDR_IMMMASK_ORI 0x0000000000000FFF |
b738c106 HC |
20 | #define ADDR_IMMMASK_ADDU16ID 0x00000000FFFF0000 |
21 | ||
22 | #define ADDR_IMMSHIFT_LU52ID 52 | |
0d03e9dc | 23 | #define ADDR_IMMSBIDX_LU52ID 11 |
b738c106 | 24 | #define ADDR_IMMSHIFT_LU32ID 32 |
0d03e9dc | 25 | #define ADDR_IMMSBIDX_LU32ID 19 |
28ac0a9e | 26 | #define ADDR_IMMSHIFT_LU12IW 12 |
0d03e9dc WR |
27 | #define ADDR_IMMSBIDX_LU12IW 19 |
28 | #define ADDR_IMMSHIFT_ORI 0 | |
29 | #define ADDR_IMMSBIDX_ORI 63 | |
b738c106 | 30 | #define ADDR_IMMSHIFT_ADDU16ID 16 |
0d03e9dc | 31 | #define ADDR_IMMSBIDX_ADDU16ID 15 |
b738c106 | 32 | |
0d03e9dc WR |
33 | #define ADDR_IMM(addr, INSN) \ |
34 | (sign_extend64(((addr & ADDR_IMMMASK_##INSN) >> ADDR_IMMSHIFT_##INSN), ADDR_IMMSBIDX_##INSN)) | |
b738c106 | 35 | |
6d4cc40f TY |
36 | enum reg0i15_op { |
37 | break_op = 0x54, | |
38 | }; | |
39 | ||
4e59e5a4 TY |
40 | enum reg0i26_op { |
41 | b_op = 0x14, | |
42 | bl_op = 0x15, | |
43 | }; | |
44 | ||
b738c106 HC |
45 | enum reg1i20_op { |
46 | lu12iw_op = 0x0a, | |
47 | lu32id_op = 0x0b, | |
19e5eb15 | 48 | pcaddi_op = 0x0c, |
9b3441a6 | 49 | pcalau12i_op = 0x0d, |
4e59e5a4 TY |
50 | pcaddu12i_op = 0x0e, |
51 | pcaddu18i_op = 0x0f, | |
b738c106 HC |
52 | }; |
53 | ||
49aef111 QZ |
54 | enum reg1i21_op { |
55 | beqz_op = 0x10, | |
56 | bnez_op = 0x11, | |
19e5eb15 HC |
57 | bceqz_op = 0x12, /* bits[9:8] = 0x00 */ |
58 | bcnez_op = 0x12, /* bits[9:8] = 0x01 */ | |
49aef111 QZ |
59 | }; |
60 | ||
4e59e5a4 TY |
61 | enum reg2_op { |
62 | revb2h_op = 0x0c, | |
63 | revb4h_op = 0x0d, | |
64 | revb2w_op = 0x0e, | |
65 | revbd_op = 0x0f, | |
66 | revh2w_op = 0x10, | |
67 | revhd_op = 0x11, | |
81efe043 TZ |
68 | iocsrrdb_op = 0x19200, |
69 | iocsrrdh_op = 0x19201, | |
70 | iocsrrdw_op = 0x19202, | |
71 | iocsrrdd_op = 0x19203, | |
72 | iocsrwrb_op = 0x19204, | |
73 | iocsrwrh_op = 0x19205, | |
74 | iocsrwrw_op = 0x19206, | |
75 | iocsrwrd_op = 0x19207, | |
4e59e5a4 TY |
76 | }; |
77 | ||
78 | enum reg2i5_op { | |
79 | slliw_op = 0x81, | |
80 | srliw_op = 0x89, | |
81 | sraiw_op = 0x91, | |
82 | }; | |
83 | ||
84 | enum reg2i6_op { | |
85 | sllid_op = 0x41, | |
86 | srlid_op = 0x45, | |
87 | sraid_op = 0x49, | |
88 | }; | |
89 | ||
b738c106 | 90 | enum reg2i12_op { |
49aef111 QZ |
91 | addiw_op = 0x0a, |
92 | addid_op = 0x0b, | |
b738c106 | 93 | lu52id_op = 0x0c, |
4e59e5a4 TY |
94 | andi_op = 0x0d, |
95 | ori_op = 0x0e, | |
96 | xori_op = 0x0f, | |
49aef111 QZ |
97 | ldb_op = 0xa0, |
98 | ldh_op = 0xa1, | |
99 | ldw_op = 0xa2, | |
100 | ldd_op = 0xa3, | |
101 | stb_op = 0xa4, | |
102 | sth_op = 0xa5, | |
103 | stw_op = 0xa6, | |
104 | std_op = 0xa7, | |
4e59e5a4 TY |
105 | ldbu_op = 0xa8, |
106 | ldhu_op = 0xa9, | |
107 | ldwu_op = 0xaa, | |
61a6fccc HC |
108 | flds_op = 0xac, |
109 | fsts_op = 0xad, | |
110 | fldd_op = 0xae, | |
111 | fstd_op = 0xaf, | |
4e59e5a4 TY |
112 | }; |
113 | ||
114 | enum reg2i14_op { | |
115 | llw_op = 0x20, | |
116 | scw_op = 0x21, | |
117 | lld_op = 0x22, | |
118 | scd_op = 0x23, | |
119 | ldptrw_op = 0x24, | |
120 | stptrw_op = 0x25, | |
121 | ldptrd_op = 0x26, | |
122 | stptrd_op = 0x27, | |
b738c106 HC |
123 | }; |
124 | ||
125 | enum reg2i16_op { | |
126 | jirl_op = 0x13, | |
49aef111 QZ |
127 | beq_op = 0x16, |
128 | bne_op = 0x17, | |
129 | blt_op = 0x18, | |
130 | bge_op = 0x19, | |
131 | bltu_op = 0x1a, | |
132 | bgeu_op = 0x1b, | |
b738c106 HC |
133 | }; |
134 | ||
4e59e5a4 TY |
135 | enum reg2bstrd_op { |
136 | bstrinsd_op = 0x2, | |
137 | bstrpickd_op = 0x3, | |
138 | }; | |
139 | ||
140 | enum reg3_op { | |
c23e7f01 WX |
141 | asrtle_op = 0x02, |
142 | asrtgt_op = 0x03, | |
4e59e5a4 TY |
143 | addw_op = 0x20, |
144 | addd_op = 0x21, | |
145 | subw_op = 0x22, | |
146 | subd_op = 0x23, | |
147 | nor_op = 0x28, | |
148 | and_op = 0x29, | |
149 | or_op = 0x2a, | |
150 | xor_op = 0x2b, | |
151 | orn_op = 0x2c, | |
152 | andn_op = 0x2d, | |
153 | sllw_op = 0x2e, | |
154 | srlw_op = 0x2f, | |
155 | sraw_op = 0x30, | |
156 | slld_op = 0x31, | |
157 | srld_op = 0x32, | |
158 | srad_op = 0x33, | |
159 | mulw_op = 0x38, | |
160 | mulhw_op = 0x39, | |
161 | mulhwu_op = 0x3a, | |
162 | muld_op = 0x3b, | |
163 | mulhd_op = 0x3c, | |
164 | mulhdu_op = 0x3d, | |
165 | divw_op = 0x40, | |
166 | modw_op = 0x41, | |
167 | divwu_op = 0x42, | |
168 | modwu_op = 0x43, | |
169 | divd_op = 0x44, | |
170 | modd_op = 0x45, | |
171 | divdu_op = 0x46, | |
172 | moddu_op = 0x47, | |
173 | ldxb_op = 0x7000, | |
174 | ldxh_op = 0x7008, | |
175 | ldxw_op = 0x7010, | |
176 | ldxd_op = 0x7018, | |
177 | stxb_op = 0x7020, | |
178 | stxh_op = 0x7028, | |
179 | stxw_op = 0x7030, | |
180 | stxd_op = 0x7038, | |
181 | ldxbu_op = 0x7040, | |
182 | ldxhu_op = 0x7048, | |
183 | ldxwu_op = 0x7050, | |
61a6fccc HC |
184 | fldxs_op = 0x7060, |
185 | fldxd_op = 0x7068, | |
186 | fstxs_op = 0x7070, | |
187 | fstxd_op = 0x7078, | |
4e59e5a4 TY |
188 | amswapw_op = 0x70c0, |
189 | amswapd_op = 0x70c1, | |
190 | amaddw_op = 0x70c2, | |
191 | amaddd_op = 0x70c3, | |
192 | amandw_op = 0x70c4, | |
193 | amandd_op = 0x70c5, | |
194 | amorw_op = 0x70c6, | |
195 | amord_op = 0x70c7, | |
196 | amxorw_op = 0x70c8, | |
197 | amxord_op = 0x70c9, | |
b82fad4d TY |
198 | ammaxw_op = 0x70ca, |
199 | ammaxd_op = 0x70cb, | |
200 | amminw_op = 0x70cc, | |
201 | ammind_op = 0x70cd, | |
202 | ammaxwu_op = 0x70ce, | |
203 | ammaxdu_op = 0x70cf, | |
204 | amminwu_op = 0x70d0, | |
205 | ammindu_op = 0x70d1, | |
206 | amswapdbw_op = 0x70d2, | |
207 | amswapdbd_op = 0x70d3, | |
208 | amadddbw_op = 0x70d4, | |
209 | amadddbd_op = 0x70d5, | |
210 | amanddbw_op = 0x70d6, | |
211 | amanddbd_op = 0x70d7, | |
212 | amordbw_op = 0x70d8, | |
213 | amordbd_op = 0x70d9, | |
214 | amxordbw_op = 0x70da, | |
215 | amxordbd_op = 0x70db, | |
216 | ammaxdbw_op = 0x70dc, | |
217 | ammaxdbd_op = 0x70dd, | |
218 | ammindbw_op = 0x70de, | |
219 | ammindbd_op = 0x70df, | |
220 | ammaxdbwu_op = 0x70e0, | |
221 | ammaxdbdu_op = 0x70e1, | |
222 | ammindbwu_op = 0x70e2, | |
223 | ammindbdu_op = 0x70e3, | |
c23e7f01 WX |
224 | fldgts_op = 0x70e8, |
225 | fldgtd_op = 0x70e9, | |
226 | fldles_op = 0x70ea, | |
227 | fldled_op = 0x70eb, | |
228 | fstgts_op = 0x70ec, | |
229 | fstgtd_op = 0x70ed, | |
230 | fstles_op = 0x70ee, | |
231 | fstled_op = 0x70ef, | |
232 | ldgtb_op = 0x70f0, | |
233 | ldgth_op = 0x70f1, | |
234 | ldgtw_op = 0x70f2, | |
235 | ldgtd_op = 0x70f3, | |
236 | ldleb_op = 0x70f4, | |
237 | ldleh_op = 0x70f5, | |
238 | ldlew_op = 0x70f6, | |
239 | ldled_op = 0x70f7, | |
240 | stgtb_op = 0x70f8, | |
241 | stgth_op = 0x70f9, | |
242 | stgtw_op = 0x70fa, | |
243 | stgtd_op = 0x70fb, | |
244 | stleb_op = 0x70fc, | |
245 | stleh_op = 0x70fd, | |
246 | stlew_op = 0x70fe, | |
247 | stled_op = 0x70ff, | |
4e59e5a4 TY |
248 | }; |
249 | ||
250 | enum reg3sa2_op { | |
251 | alslw_op = 0x02, | |
252 | alslwu_op = 0x03, | |
253 | alsld_op = 0x16, | |
254 | }; | |
255 | ||
6d4cc40f TY |
256 | struct reg0i15_format { |
257 | unsigned int immediate : 15; | |
258 | unsigned int opcode : 17; | |
259 | }; | |
260 | ||
b738c106 HC |
261 | struct reg0i26_format { |
262 | unsigned int immediate_h : 10; | |
263 | unsigned int immediate_l : 16; | |
264 | unsigned int opcode : 6; | |
265 | }; | |
266 | ||
267 | struct reg1i20_format { | |
268 | unsigned int rd : 5; | |
269 | unsigned int immediate : 20; | |
270 | unsigned int opcode : 7; | |
271 | }; | |
272 | ||
273 | struct reg1i21_format { | |
274 | unsigned int immediate_h : 5; | |
275 | unsigned int rj : 5; | |
276 | unsigned int immediate_l : 16; | |
277 | unsigned int opcode : 6; | |
278 | }; | |
279 | ||
4e59e5a4 TY |
280 | struct reg2_format { |
281 | unsigned int rd : 5; | |
282 | unsigned int rj : 5; | |
283 | unsigned int opcode : 22; | |
284 | }; | |
285 | ||
286 | struct reg2i5_format { | |
287 | unsigned int rd : 5; | |
288 | unsigned int rj : 5; | |
289 | unsigned int immediate : 5; | |
290 | unsigned int opcode : 17; | |
291 | }; | |
292 | ||
293 | struct reg2i6_format { | |
294 | unsigned int rd : 5; | |
295 | unsigned int rj : 5; | |
296 | unsigned int immediate : 6; | |
297 | unsigned int opcode : 16; | |
298 | }; | |
299 | ||
b738c106 HC |
300 | struct reg2i12_format { |
301 | unsigned int rd : 5; | |
302 | unsigned int rj : 5; | |
303 | unsigned int immediate : 12; | |
304 | unsigned int opcode : 10; | |
305 | }; | |
306 | ||
4e59e5a4 TY |
307 | struct reg2i14_format { |
308 | unsigned int rd : 5; | |
309 | unsigned int rj : 5; | |
310 | unsigned int immediate : 14; | |
311 | unsigned int opcode : 8; | |
312 | }; | |
313 | ||
b738c106 HC |
314 | struct reg2i16_format { |
315 | unsigned int rd : 5; | |
316 | unsigned int rj : 5; | |
317 | unsigned int immediate : 16; | |
318 | unsigned int opcode : 6; | |
319 | }; | |
320 | ||
4e59e5a4 TY |
321 | struct reg2bstrd_format { |
322 | unsigned int rd : 5; | |
323 | unsigned int rj : 5; | |
324 | unsigned int lsbd : 6; | |
325 | unsigned int msbd : 6; | |
326 | unsigned int opcode : 10; | |
327 | }; | |
328 | ||
81efe043 TZ |
329 | struct reg2csr_format { |
330 | unsigned int rd : 5; | |
331 | unsigned int rj : 5; | |
332 | unsigned int csr : 14; | |
333 | unsigned int opcode : 8; | |
334 | }; | |
335 | ||
4e59e5a4 TY |
336 | struct reg3_format { |
337 | unsigned int rd : 5; | |
338 | unsigned int rj : 5; | |
339 | unsigned int rk : 5; | |
340 | unsigned int opcode : 17; | |
341 | }; | |
342 | ||
343 | struct reg3sa2_format { | |
344 | unsigned int rd : 5; | |
345 | unsigned int rj : 5; | |
346 | unsigned int rk : 5; | |
347 | unsigned int immediate : 2; | |
348 | unsigned int opcode : 15; | |
349 | }; | |
350 | ||
b738c106 HC |
351 | union loongarch_instruction { |
352 | unsigned int word; | |
6d4cc40f | 353 | struct reg0i15_format reg0i15_format; |
4e59e5a4 TY |
354 | struct reg0i26_format reg0i26_format; |
355 | struct reg1i20_format reg1i20_format; | |
356 | struct reg1i21_format reg1i21_format; | |
357 | struct reg2_format reg2_format; | |
358 | struct reg2i5_format reg2i5_format; | |
359 | struct reg2i6_format reg2i6_format; | |
360 | struct reg2i12_format reg2i12_format; | |
361 | struct reg2i14_format reg2i14_format; | |
362 | struct reg2i16_format reg2i16_format; | |
363 | struct reg2bstrd_format reg2bstrd_format; | |
81efe043 | 364 | struct reg2csr_format reg2csr_format; |
4e59e5a4 TY |
365 | struct reg3_format reg3_format; |
366 | struct reg3sa2_format reg3sa2_format; | |
b738c106 HC |
367 | }; |
368 | ||
369 | #define LOONGARCH_INSN_SIZE sizeof(union loongarch_instruction) | |
370 | ||
371 | enum loongarch_gpr { | |
372 | LOONGARCH_GPR_ZERO = 0, | |
373 | LOONGARCH_GPR_RA = 1, | |
374 | LOONGARCH_GPR_TP = 2, | |
375 | LOONGARCH_GPR_SP = 3, | |
376 | LOONGARCH_GPR_A0 = 4, /* Reused as V0 for return value */ | |
377 | LOONGARCH_GPR_A1, /* Reused as V1 for return value */ | |
378 | LOONGARCH_GPR_A2, | |
379 | LOONGARCH_GPR_A3, | |
380 | LOONGARCH_GPR_A4, | |
381 | LOONGARCH_GPR_A5, | |
382 | LOONGARCH_GPR_A6, | |
383 | LOONGARCH_GPR_A7, | |
384 | LOONGARCH_GPR_T0 = 12, | |
385 | LOONGARCH_GPR_T1, | |
386 | LOONGARCH_GPR_T2, | |
387 | LOONGARCH_GPR_T3, | |
388 | LOONGARCH_GPR_T4, | |
389 | LOONGARCH_GPR_T5, | |
390 | LOONGARCH_GPR_T6, | |
391 | LOONGARCH_GPR_T7, | |
392 | LOONGARCH_GPR_T8, | |
393 | LOONGARCH_GPR_FP = 22, | |
394 | LOONGARCH_GPR_S0 = 23, | |
395 | LOONGARCH_GPR_S1, | |
396 | LOONGARCH_GPR_S2, | |
397 | LOONGARCH_GPR_S3, | |
398 | LOONGARCH_GPR_S4, | |
399 | LOONGARCH_GPR_S5, | |
400 | LOONGARCH_GPR_S6, | |
401 | LOONGARCH_GPR_S7, | |
402 | LOONGARCH_GPR_S8, | |
403 | LOONGARCH_GPR_MAX | |
404 | }; | |
405 | ||
49aef111 QZ |
406 | #define is_imm12_negative(val) is_imm_negative(val, 12) |
407 | ||
408 | static inline bool is_imm_negative(unsigned long val, unsigned int bit) | |
409 | { | |
410 | return val & (1UL << (bit - 1)); | |
411 | } | |
412 | ||
6d4cc40f TY |
413 | static inline bool is_break_ins(union loongarch_instruction *ip) |
414 | { | |
415 | return ip->reg0i15_format.opcode == break_op; | |
416 | } | |
417 | ||
19e5eb15 HC |
418 | static inline bool is_pc_ins(union loongarch_instruction *ip) |
419 | { | |
420 | return ip->reg1i20_format.opcode >= pcaddi_op && | |
421 | ip->reg1i20_format.opcode <= pcaddu18i_op; | |
422 | } | |
423 | ||
49aef111 QZ |
424 | static inline bool is_branch_ins(union loongarch_instruction *ip) |
425 | { | |
426 | return ip->reg1i21_format.opcode >= beqz_op && | |
427 | ip->reg1i21_format.opcode <= bgeu_op; | |
428 | } | |
429 | ||
430 | static inline bool is_ra_save_ins(union loongarch_instruction *ip) | |
431 | { | |
432 | /* st.d $ra, $sp, offset */ | |
433 | return ip->reg2i12_format.opcode == std_op && | |
434 | ip->reg2i12_format.rj == LOONGARCH_GPR_SP && | |
435 | ip->reg2i12_format.rd == LOONGARCH_GPR_RA && | |
436 | !is_imm12_negative(ip->reg2i12_format.immediate); | |
437 | } | |
438 | ||
439 | static inline bool is_stack_alloc_ins(union loongarch_instruction *ip) | |
440 | { | |
441 | /* addi.d $sp, $sp, -imm */ | |
442 | return ip->reg2i12_format.opcode == addid_op && | |
443 | ip->reg2i12_format.rj == LOONGARCH_GPR_SP && | |
444 | ip->reg2i12_format.rd == LOONGARCH_GPR_SP && | |
445 | is_imm12_negative(ip->reg2i12_format.immediate); | |
446 | } | |
447 | ||
424421a7 QZ |
448 | static inline bool is_self_loop_ins(union loongarch_instruction *ip, struct pt_regs *regs) |
449 | { | |
450 | switch (ip->reg0i26_format.opcode) { | |
451 | case b_op: | |
452 | case bl_op: | |
453 | if (ip->reg0i26_format.immediate_l == 0 | |
454 | && ip->reg0i26_format.immediate_h == 0) | |
455 | return true; | |
456 | } | |
457 | ||
458 | switch (ip->reg1i21_format.opcode) { | |
459 | case beqz_op: | |
460 | case bnez_op: | |
461 | case bceqz_op: | |
462 | if (ip->reg1i21_format.immediate_l == 0 | |
463 | && ip->reg1i21_format.immediate_h == 0) | |
464 | return true; | |
465 | } | |
466 | ||
467 | switch (ip->reg2i16_format.opcode) { | |
468 | case beq_op: | |
469 | case bne_op: | |
470 | case blt_op: | |
471 | case bge_op: | |
472 | case bltu_op: | |
473 | case bgeu_op: | |
474 | if (ip->reg2i16_format.immediate == 0) | |
475 | return true; | |
476 | break; | |
477 | case jirl_op: | |
478 | if (regs->regs[ip->reg2i16_format.rj] + | |
479 | ((unsigned long)ip->reg2i16_format.immediate << 2) == (unsigned long)ip) | |
480 | return true; | |
481 | } | |
482 | ||
483 | return false; | |
484 | } | |
485 | ||
9b3441a6 TY |
486 | void simu_pc(struct pt_regs *regs, union loongarch_instruction insn); |
487 | void simu_branch(struct pt_regs *regs, union loongarch_instruction insn); | |
488 | ||
3d2c3daf TY |
489 | bool insns_not_supported(union loongarch_instruction insn); |
490 | bool insns_need_simulation(union loongarch_instruction insn); | |
491 | void arch_simulate_insn(union loongarch_instruction insn, struct pt_regs *regs); | |
492 | ||
4733f09d QZ |
493 | int larch_insn_read(void *addr, u32 *insnp); |
494 | int larch_insn_write(void *addr, u32 insn); | |
495 | int larch_insn_patch_text(void *addr, u32 insn); | |
496 | ||
497 | u32 larch_insn_gen_nop(void); | |
498 | u32 larch_insn_gen_b(unsigned long pc, unsigned long dest); | |
499 | u32 larch_insn_gen_bl(unsigned long pc, unsigned long dest); | |
500 | ||
49ed320d TY |
501 | u32 larch_insn_gen_break(int imm); |
502 | ||
4733f09d QZ |
503 | u32 larch_insn_gen_or(enum loongarch_gpr rd, enum loongarch_gpr rj, enum loongarch_gpr rk); |
504 | u32 larch_insn_gen_move(enum loongarch_gpr rd, enum loongarch_gpr rj); | |
505 | ||
28ac0a9e | 506 | u32 larch_insn_gen_lu12iw(enum loongarch_gpr rd, int imm); |
b738c106 HC |
507 | u32 larch_insn_gen_lu32id(enum loongarch_gpr rd, int imm); |
508 | u32 larch_insn_gen_lu52id(enum loongarch_gpr rd, enum loongarch_gpr rj, int imm); | |
0d03e9dc | 509 | u32 larch_insn_gen_jirl(enum loongarch_gpr rd, enum loongarch_gpr rj, int imm); |
b738c106 | 510 | |
8a34228e TY |
511 | static inline bool signed_imm_check(long val, unsigned int bit) |
512 | { | |
513 | return -(1L << (bit - 1)) <= val && val < (1L << (bit - 1)); | |
514 | } | |
515 | ||
516 | static inline bool unsigned_imm_check(unsigned long val, unsigned int bit) | |
517 | { | |
518 | return val < (1UL << bit); | |
519 | } | |
520 | ||
49ed320d TY |
521 | #define DEF_EMIT_REG0I15_FORMAT(NAME, OP) \ |
522 | static inline void emit_##NAME(union loongarch_instruction *insn, \ | |
523 | int imm) \ | |
524 | { \ | |
525 | insn->reg0i15_format.opcode = OP; \ | |
526 | insn->reg0i15_format.immediate = imm; \ | |
527 | } | |
528 | ||
529 | DEF_EMIT_REG0I15_FORMAT(break, break_op) | |
530 | ||
5dc61552 TY |
531 | #define DEF_EMIT_REG0I26_FORMAT(NAME, OP) \ |
532 | static inline void emit_##NAME(union loongarch_instruction *insn, \ | |
533 | int offset) \ | |
534 | { \ | |
535 | unsigned int immediate_l, immediate_h; \ | |
536 | \ | |
537 | immediate_l = offset & 0xffff; \ | |
538 | offset >>= 16; \ | |
539 | immediate_h = offset & 0x3ff; \ | |
540 | \ | |
541 | insn->reg0i26_format.opcode = OP; \ | |
542 | insn->reg0i26_format.immediate_l = immediate_l; \ | |
543 | insn->reg0i26_format.immediate_h = immediate_h; \ | |
544 | } | |
545 | ||
546 | DEF_EMIT_REG0I26_FORMAT(b, b_op) | |
3200983f | 547 | DEF_EMIT_REG0I26_FORMAT(bl, bl_op) |
5dc61552 TY |
548 | |
549 | #define DEF_EMIT_REG1I20_FORMAT(NAME, OP) \ | |
550 | static inline void emit_##NAME(union loongarch_instruction *insn, \ | |
551 | enum loongarch_gpr rd, int imm) \ | |
552 | { \ | |
553 | insn->reg1i20_format.opcode = OP; \ | |
554 | insn->reg1i20_format.immediate = imm; \ | |
555 | insn->reg1i20_format.rd = rd; \ | |
556 | } | |
557 | ||
558 | DEF_EMIT_REG1I20_FORMAT(lu12iw, lu12iw_op) | |
559 | DEF_EMIT_REG1I20_FORMAT(lu32id, lu32id_op) | |
560 | DEF_EMIT_REG1I20_FORMAT(pcaddu18i, pcaddu18i_op) | |
561 | ||
562 | #define DEF_EMIT_REG2_FORMAT(NAME, OP) \ | |
563 | static inline void emit_##NAME(union loongarch_instruction *insn, \ | |
564 | enum loongarch_gpr rd, \ | |
565 | enum loongarch_gpr rj) \ | |
566 | { \ | |
567 | insn->reg2_format.opcode = OP; \ | |
568 | insn->reg2_format.rd = rd; \ | |
569 | insn->reg2_format.rj = rj; \ | |
570 | } | |
571 | ||
572 | DEF_EMIT_REG2_FORMAT(revb2h, revb2h_op) | |
573 | DEF_EMIT_REG2_FORMAT(revb2w, revb2w_op) | |
574 | DEF_EMIT_REG2_FORMAT(revbd, revbd_op) | |
575 | ||
576 | #define DEF_EMIT_REG2I5_FORMAT(NAME, OP) \ | |
577 | static inline void emit_##NAME(union loongarch_instruction *insn, \ | |
578 | enum loongarch_gpr rd, \ | |
579 | enum loongarch_gpr rj, \ | |
580 | int imm) \ | |
581 | { \ | |
582 | insn->reg2i5_format.opcode = OP; \ | |
583 | insn->reg2i5_format.immediate = imm; \ | |
584 | insn->reg2i5_format.rd = rd; \ | |
585 | insn->reg2i5_format.rj = rj; \ | |
586 | } | |
587 | ||
588 | DEF_EMIT_REG2I5_FORMAT(slliw, slliw_op) | |
589 | DEF_EMIT_REG2I5_FORMAT(srliw, srliw_op) | |
590 | DEF_EMIT_REG2I5_FORMAT(sraiw, sraiw_op) | |
591 | ||
592 | #define DEF_EMIT_REG2I6_FORMAT(NAME, OP) \ | |
593 | static inline void emit_##NAME(union loongarch_instruction *insn, \ | |
594 | enum loongarch_gpr rd, \ | |
595 | enum loongarch_gpr rj, \ | |
596 | int imm) \ | |
597 | { \ | |
598 | insn->reg2i6_format.opcode = OP; \ | |
599 | insn->reg2i6_format.immediate = imm; \ | |
600 | insn->reg2i6_format.rd = rd; \ | |
601 | insn->reg2i6_format.rj = rj; \ | |
602 | } | |
603 | ||
604 | DEF_EMIT_REG2I6_FORMAT(sllid, sllid_op) | |
605 | DEF_EMIT_REG2I6_FORMAT(srlid, srlid_op) | |
606 | DEF_EMIT_REG2I6_FORMAT(sraid, sraid_op) | |
607 | ||
608 | #define DEF_EMIT_REG2I12_FORMAT(NAME, OP) \ | |
609 | static inline void emit_##NAME(union loongarch_instruction *insn, \ | |
610 | enum loongarch_gpr rd, \ | |
611 | enum loongarch_gpr rj, \ | |
612 | int imm) \ | |
613 | { \ | |
614 | insn->reg2i12_format.opcode = OP; \ | |
615 | insn->reg2i12_format.immediate = imm; \ | |
616 | insn->reg2i12_format.rd = rd; \ | |
617 | insn->reg2i12_format.rj = rj; \ | |
618 | } | |
619 | ||
620 | DEF_EMIT_REG2I12_FORMAT(addiw, addiw_op) | |
621 | DEF_EMIT_REG2I12_FORMAT(addid, addid_op) | |
622 | DEF_EMIT_REG2I12_FORMAT(lu52id, lu52id_op) | |
623 | DEF_EMIT_REG2I12_FORMAT(andi, andi_op) | |
624 | DEF_EMIT_REG2I12_FORMAT(ori, ori_op) | |
625 | DEF_EMIT_REG2I12_FORMAT(xori, xori_op) | |
626 | DEF_EMIT_REG2I12_FORMAT(ldbu, ldbu_op) | |
627 | DEF_EMIT_REG2I12_FORMAT(ldhu, ldhu_op) | |
628 | DEF_EMIT_REG2I12_FORMAT(ldwu, ldwu_op) | |
629 | DEF_EMIT_REG2I12_FORMAT(ldd, ldd_op) | |
630 | DEF_EMIT_REG2I12_FORMAT(stb, stb_op) | |
631 | DEF_EMIT_REG2I12_FORMAT(sth, sth_op) | |
632 | DEF_EMIT_REG2I12_FORMAT(stw, stw_op) | |
633 | DEF_EMIT_REG2I12_FORMAT(std, std_op) | |
634 | ||
635 | #define DEF_EMIT_REG2I14_FORMAT(NAME, OP) \ | |
636 | static inline void emit_##NAME(union loongarch_instruction *insn, \ | |
637 | enum loongarch_gpr rd, \ | |
638 | enum loongarch_gpr rj, \ | |
639 | int imm) \ | |
640 | { \ | |
641 | insn->reg2i14_format.opcode = OP; \ | |
642 | insn->reg2i14_format.immediate = imm; \ | |
643 | insn->reg2i14_format.rd = rd; \ | |
644 | insn->reg2i14_format.rj = rj; \ | |
645 | } | |
646 | ||
647 | DEF_EMIT_REG2I14_FORMAT(llw, llw_op) | |
648 | DEF_EMIT_REG2I14_FORMAT(scw, scw_op) | |
649 | DEF_EMIT_REG2I14_FORMAT(lld, lld_op) | |
650 | DEF_EMIT_REG2I14_FORMAT(scd, scd_op) | |
651 | DEF_EMIT_REG2I14_FORMAT(ldptrw, ldptrw_op) | |
652 | DEF_EMIT_REG2I14_FORMAT(stptrw, stptrw_op) | |
653 | DEF_EMIT_REG2I14_FORMAT(ldptrd, ldptrd_op) | |
654 | DEF_EMIT_REG2I14_FORMAT(stptrd, stptrd_op) | |
655 | ||
656 | #define DEF_EMIT_REG2I16_FORMAT(NAME, OP) \ | |
657 | static inline void emit_##NAME(union loongarch_instruction *insn, \ | |
658 | enum loongarch_gpr rj, \ | |
659 | enum loongarch_gpr rd, \ | |
660 | int offset) \ | |
661 | { \ | |
662 | insn->reg2i16_format.opcode = OP; \ | |
663 | insn->reg2i16_format.immediate = offset; \ | |
664 | insn->reg2i16_format.rj = rj; \ | |
665 | insn->reg2i16_format.rd = rd; \ | |
666 | } | |
667 | ||
668 | DEF_EMIT_REG2I16_FORMAT(beq, beq_op) | |
669 | DEF_EMIT_REG2I16_FORMAT(bne, bne_op) | |
670 | DEF_EMIT_REG2I16_FORMAT(blt, blt_op) | |
671 | DEF_EMIT_REG2I16_FORMAT(bge, bge_op) | |
672 | DEF_EMIT_REG2I16_FORMAT(bltu, bltu_op) | |
673 | DEF_EMIT_REG2I16_FORMAT(bgeu, bgeu_op) | |
674 | DEF_EMIT_REG2I16_FORMAT(jirl, jirl_op) | |
675 | ||
676 | #define DEF_EMIT_REG2BSTRD_FORMAT(NAME, OP) \ | |
677 | static inline void emit_##NAME(union loongarch_instruction *insn, \ | |
678 | enum loongarch_gpr rd, \ | |
679 | enum loongarch_gpr rj, \ | |
680 | int msbd, \ | |
681 | int lsbd) \ | |
682 | { \ | |
683 | insn->reg2bstrd_format.opcode = OP; \ | |
684 | insn->reg2bstrd_format.msbd = msbd; \ | |
685 | insn->reg2bstrd_format.lsbd = lsbd; \ | |
686 | insn->reg2bstrd_format.rj = rj; \ | |
687 | insn->reg2bstrd_format.rd = rd; \ | |
688 | } | |
689 | ||
690 | DEF_EMIT_REG2BSTRD_FORMAT(bstrpickd, bstrpickd_op) | |
691 | ||
692 | #define DEF_EMIT_REG3_FORMAT(NAME, OP) \ | |
693 | static inline void emit_##NAME(union loongarch_instruction *insn, \ | |
694 | enum loongarch_gpr rd, \ | |
695 | enum loongarch_gpr rj, \ | |
696 | enum loongarch_gpr rk) \ | |
697 | { \ | |
698 | insn->reg3_format.opcode = OP; \ | |
699 | insn->reg3_format.rd = rd; \ | |
700 | insn->reg3_format.rj = rj; \ | |
701 | insn->reg3_format.rk = rk; \ | |
702 | } | |
703 | ||
704 | DEF_EMIT_REG3_FORMAT(addd, addd_op) | |
705 | DEF_EMIT_REG3_FORMAT(subd, subd_op) | |
706 | DEF_EMIT_REG3_FORMAT(muld, muld_op) | |
707 | DEF_EMIT_REG3_FORMAT(divdu, divdu_op) | |
708 | DEF_EMIT_REG3_FORMAT(moddu, moddu_op) | |
709 | DEF_EMIT_REG3_FORMAT(and, and_op) | |
710 | DEF_EMIT_REG3_FORMAT(or, or_op) | |
711 | DEF_EMIT_REG3_FORMAT(xor, xor_op) | |
712 | DEF_EMIT_REG3_FORMAT(sllw, sllw_op) | |
713 | DEF_EMIT_REG3_FORMAT(slld, slld_op) | |
714 | DEF_EMIT_REG3_FORMAT(srlw, srlw_op) | |
715 | DEF_EMIT_REG3_FORMAT(srld, srld_op) | |
716 | DEF_EMIT_REG3_FORMAT(sraw, sraw_op) | |
717 | DEF_EMIT_REG3_FORMAT(srad, srad_op) | |
718 | DEF_EMIT_REG3_FORMAT(ldxbu, ldxbu_op) | |
719 | DEF_EMIT_REG3_FORMAT(ldxhu, ldxhu_op) | |
720 | DEF_EMIT_REG3_FORMAT(ldxwu, ldxwu_op) | |
721 | DEF_EMIT_REG3_FORMAT(ldxd, ldxd_op) | |
722 | DEF_EMIT_REG3_FORMAT(stxb, stxb_op) | |
723 | DEF_EMIT_REG3_FORMAT(stxh, stxh_op) | |
724 | DEF_EMIT_REG3_FORMAT(stxw, stxw_op) | |
725 | DEF_EMIT_REG3_FORMAT(stxd, stxd_op) | |
726 | DEF_EMIT_REG3_FORMAT(amaddw, amaddw_op) | |
727 | DEF_EMIT_REG3_FORMAT(amaddd, amaddd_op) | |
728 | DEF_EMIT_REG3_FORMAT(amandw, amandw_op) | |
729 | DEF_EMIT_REG3_FORMAT(amandd, amandd_op) | |
730 | DEF_EMIT_REG3_FORMAT(amorw, amorw_op) | |
731 | DEF_EMIT_REG3_FORMAT(amord, amord_op) | |
732 | DEF_EMIT_REG3_FORMAT(amxorw, amxorw_op) | |
733 | DEF_EMIT_REG3_FORMAT(amxord, amxord_op) | |
734 | DEF_EMIT_REG3_FORMAT(amswapw, amswapw_op) | |
735 | DEF_EMIT_REG3_FORMAT(amswapd, amswapd_op) | |
736 | ||
737 | #define DEF_EMIT_REG3SA2_FORMAT(NAME, OP) \ | |
738 | static inline void emit_##NAME(union loongarch_instruction *insn, \ | |
739 | enum loongarch_gpr rd, \ | |
740 | enum loongarch_gpr rj, \ | |
741 | enum loongarch_gpr rk, \ | |
742 | int imm) \ | |
743 | { \ | |
744 | insn->reg3sa2_format.opcode = OP; \ | |
745 | insn->reg3sa2_format.immediate = imm; \ | |
746 | insn->reg3sa2_format.rd = rd; \ | |
747 | insn->reg3sa2_format.rj = rj; \ | |
748 | insn->reg3sa2_format.rk = rk; \ | |
749 | } | |
750 | ||
751 | DEF_EMIT_REG3SA2_FORMAT(alsld, alsld_op) | |
752 | ||
61a6fccc HC |
753 | struct pt_regs; |
754 | ||
755 | void emulate_load_store_insn(struct pt_regs *regs, void __user *addr, unsigned int *pc); | |
756 | unsigned long unaligned_read(void __user *addr, void *value, unsigned long n, bool sign); | |
757 | unsigned long unaligned_write(void __user *addr, unsigned long value, unsigned long n); | |
758 | ||
b738c106 | 759 | #endif /* _ASM_INST_H */ |