1 /* SPDX-License-Identifier: GPL-2.0 */
3 * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
8 #include <linux/types.h>
11 #define ADDR_IMMMASK_LU52ID 0xFFF0000000000000
12 #define ADDR_IMMMASK_LU32ID 0x000FFFFF00000000
13 #define ADDR_IMMMASK_ADDU16ID 0x00000000FFFF0000
15 #define ADDR_IMMSHIFT_LU52ID 52
16 #define ADDR_IMMSHIFT_LU32ID 32
17 #define ADDR_IMMSHIFT_ADDU16ID 16
19 #define ADDR_IMM(addr, INSN) ((addr & ADDR_IMMMASK_##INSN) >> ADDR_IMMSHIFT_##INSN)
55 struct reg0i26_format {
56 unsigned int immediate_h : 10;
57 unsigned int immediate_l : 16;
58 unsigned int opcode : 6;
61 struct reg1i20_format {
63 unsigned int immediate : 20;
64 unsigned int opcode : 7;
67 struct reg1i21_format {
68 unsigned int immediate_h : 5;
70 unsigned int immediate_l : 16;
71 unsigned int opcode : 6;
74 struct reg2i12_format {
77 unsigned int immediate : 12;
78 unsigned int opcode : 10;
81 struct reg2i16_format {
84 unsigned int immediate : 16;
85 unsigned int opcode : 6;
88 union loongarch_instruction {
90 struct reg0i26_format reg0i26_format;
91 struct reg1i20_format reg1i20_format;
92 struct reg1i21_format reg1i21_format;
93 struct reg2i12_format reg2i12_format;
94 struct reg2i16_format reg2i16_format;
97 #define LOONGARCH_INSN_SIZE sizeof(union loongarch_instruction)
100 LOONGARCH_GPR_ZERO = 0,
101 LOONGARCH_GPR_RA = 1,
102 LOONGARCH_GPR_TP = 2,
103 LOONGARCH_GPR_SP = 3,
104 LOONGARCH_GPR_A0 = 4, /* Reused as V0 for return value */
105 LOONGARCH_GPR_A1, /* Reused as V1 for return value */
112 LOONGARCH_GPR_T0 = 12,
121 LOONGARCH_GPR_FP = 22,
122 LOONGARCH_GPR_S0 = 23,
134 #define is_imm12_negative(val) is_imm_negative(val, 12)
136 static inline bool is_imm_negative(unsigned long val, unsigned int bit)
138 return val & (1UL << (bit - 1));
141 static inline bool is_branch_ins(union loongarch_instruction *ip)
143 return ip->reg1i21_format.opcode >= beqz_op &&
144 ip->reg1i21_format.opcode <= bgeu_op;
147 static inline bool is_ra_save_ins(union loongarch_instruction *ip)
149 /* st.d $ra, $sp, offset */
150 return ip->reg2i12_format.opcode == std_op &&
151 ip->reg2i12_format.rj == LOONGARCH_GPR_SP &&
152 ip->reg2i12_format.rd == LOONGARCH_GPR_RA &&
153 !is_imm12_negative(ip->reg2i12_format.immediate);
156 static inline bool is_stack_alloc_ins(union loongarch_instruction *ip)
158 /* addi.d $sp, $sp, -imm */
159 return ip->reg2i12_format.opcode == addid_op &&
160 ip->reg2i12_format.rj == LOONGARCH_GPR_SP &&
161 ip->reg2i12_format.rd == LOONGARCH_GPR_SP &&
162 is_imm12_negative(ip->reg2i12_format.immediate);
165 u32 larch_insn_gen_lu32id(enum loongarch_gpr rd, int imm);
166 u32 larch_insn_gen_lu52id(enum loongarch_gpr rd, enum loongarch_gpr rj, int imm);
167 u32 larch_insn_gen_jirl(enum loongarch_gpr rd, enum loongarch_gpr rj, unsigned long pc, unsigned long dest);
169 #endif /* _ASM_INST_H */