xref: /openbmc/linux/arch/loongarch/include/asm/inst.h (revision 7cc39531)
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 
8 #include <linux/types.h>
9 #include <asm/asm.h>
10 
11 #define ADDR_IMMMASK_LU52ID	0xFFF0000000000000
12 #define ADDR_IMMMASK_LU32ID	0x000FFFFF00000000
13 #define ADDR_IMMMASK_ADDU16ID	0x00000000FFFF0000
14 
15 #define ADDR_IMMSHIFT_LU52ID	52
16 #define ADDR_IMMSHIFT_LU32ID	32
17 #define ADDR_IMMSHIFT_ADDU16ID	16
18 
19 #define ADDR_IMM(addr, INSN)	((addr & ADDR_IMMMASK_##INSN) >> ADDR_IMMSHIFT_##INSN)
20 
21 enum reg1i20_op {
22 	lu12iw_op	= 0x0a,
23 	lu32id_op	= 0x0b,
24 };
25 
26 enum reg1i21_op {
27 	beqz_op		= 0x10,
28 	bnez_op		= 0x11,
29 };
30 
31 enum reg2i12_op {
32 	addiw_op	= 0x0a,
33 	addid_op	= 0x0b,
34 	lu52id_op	= 0x0c,
35 	ldb_op		= 0xa0,
36 	ldh_op		= 0xa1,
37 	ldw_op		= 0xa2,
38 	ldd_op		= 0xa3,
39 	stb_op		= 0xa4,
40 	sth_op		= 0xa5,
41 	stw_op		= 0xa6,
42 	std_op		= 0xa7,
43 };
44 
45 enum reg2i16_op {
46 	jirl_op		= 0x13,
47 	beq_op		= 0x16,
48 	bne_op		= 0x17,
49 	blt_op		= 0x18,
50 	bge_op		= 0x19,
51 	bltu_op		= 0x1a,
52 	bgeu_op		= 0x1b,
53 };
54 
55 struct reg0i26_format {
56 	unsigned int immediate_h : 10;
57 	unsigned int immediate_l : 16;
58 	unsigned int opcode : 6;
59 };
60 
61 struct reg1i20_format {
62 	unsigned int rd : 5;
63 	unsigned int immediate : 20;
64 	unsigned int opcode : 7;
65 };
66 
67 struct reg1i21_format {
68 	unsigned int immediate_h  : 5;
69 	unsigned int rj : 5;
70 	unsigned int immediate_l : 16;
71 	unsigned int opcode : 6;
72 };
73 
74 struct reg2i12_format {
75 	unsigned int rd : 5;
76 	unsigned int rj : 5;
77 	unsigned int immediate : 12;
78 	unsigned int opcode : 10;
79 };
80 
81 struct reg2i16_format {
82 	unsigned int rd : 5;
83 	unsigned int rj : 5;
84 	unsigned int immediate : 16;
85 	unsigned int opcode : 6;
86 };
87 
88 union loongarch_instruction {
89 	unsigned int word;
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;
95 };
96 
97 #define LOONGARCH_INSN_SIZE	sizeof(union loongarch_instruction)
98 
99 enum loongarch_gpr {
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 */
106 	LOONGARCH_GPR_A2,
107 	LOONGARCH_GPR_A3,
108 	LOONGARCH_GPR_A4,
109 	LOONGARCH_GPR_A5,
110 	LOONGARCH_GPR_A6,
111 	LOONGARCH_GPR_A7,
112 	LOONGARCH_GPR_T0 = 12,
113 	LOONGARCH_GPR_T1,
114 	LOONGARCH_GPR_T2,
115 	LOONGARCH_GPR_T3,
116 	LOONGARCH_GPR_T4,
117 	LOONGARCH_GPR_T5,
118 	LOONGARCH_GPR_T6,
119 	LOONGARCH_GPR_T7,
120 	LOONGARCH_GPR_T8,
121 	LOONGARCH_GPR_FP = 22,
122 	LOONGARCH_GPR_S0 = 23,
123 	LOONGARCH_GPR_S1,
124 	LOONGARCH_GPR_S2,
125 	LOONGARCH_GPR_S3,
126 	LOONGARCH_GPR_S4,
127 	LOONGARCH_GPR_S5,
128 	LOONGARCH_GPR_S6,
129 	LOONGARCH_GPR_S7,
130 	LOONGARCH_GPR_S8,
131 	LOONGARCH_GPR_MAX
132 };
133 
134 #define is_imm12_negative(val)	is_imm_negative(val, 12)
135 
136 static inline bool is_imm_negative(unsigned long val, unsigned int bit)
137 {
138 	return val & (1UL << (bit - 1));
139 }
140 
141 static inline bool is_branch_ins(union loongarch_instruction *ip)
142 {
143 	return ip->reg1i21_format.opcode >= beqz_op &&
144 		ip->reg1i21_format.opcode <= bgeu_op;
145 }
146 
147 static inline bool is_ra_save_ins(union loongarch_instruction *ip)
148 {
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);
154 }
155 
156 static inline bool is_stack_alloc_ins(union loongarch_instruction *ip)
157 {
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);
163 }
164 
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);
168 
169 #endif /* _ASM_INST_H */
170