xref: /openbmc/linux/arch/mips/mm/uasm.c (revision e8ef868b)
1e30ec452SThiemo Seufer /*
2e30ec452SThiemo Seufer  * This file is subject to the terms and conditions of the GNU General Public
3e30ec452SThiemo Seufer  * License.  See the file "COPYING" in the main directory of this archive
4e30ec452SThiemo Seufer  * for more details.
5e30ec452SThiemo Seufer  *
6e30ec452SThiemo Seufer  * A small micro-assembler. It is intentionally kept simple, does only
7e30ec452SThiemo Seufer  * support a subset of instructions, and does not try to hide pipeline
8e30ec452SThiemo Seufer  * effects like branch delay slots.
9e30ec452SThiemo Seufer  *
10e30ec452SThiemo Seufer  * Copyright (C) 2004, 2005, 2006, 2008	 Thiemo Seufer
11e30ec452SThiemo Seufer  * Copyright (C) 2005, 2007  Maciej W. Rozycki
12e30ec452SThiemo Seufer  * Copyright (C) 2006  Ralf Baechle (ralf@linux-mips.org)
13abc597feSSteven J. Hill  * Copyright (C) 2012, 2013  MIPS Technologies, Inc.  All rights reserved.
14e30ec452SThiemo Seufer  */
15e30ec452SThiemo Seufer 
16e30ec452SThiemo Seufer enum fields {
17e30ec452SThiemo Seufer 	RS = 0x001,
18e30ec452SThiemo Seufer 	RT = 0x002,
19e30ec452SThiemo Seufer 	RD = 0x004,
20e30ec452SThiemo Seufer 	RE = 0x008,
21e30ec452SThiemo Seufer 	SIMM = 0x010,
22e30ec452SThiemo Seufer 	UIMM = 0x020,
23e30ec452SThiemo Seufer 	BIMM = 0x040,
24e30ec452SThiemo Seufer 	JIMM = 0x080,
25e30ec452SThiemo Seufer 	FUNC = 0x100,
2658b9e223SDavid Daney 	SET = 0x200,
2758b9e223SDavid Daney 	SCIMM = 0x400
28e30ec452SThiemo Seufer };
29e30ec452SThiemo Seufer 
30e30ec452SThiemo Seufer #define OP_MASK		0x3f
31e30ec452SThiemo Seufer #define OP_SH		26
32e30ec452SThiemo Seufer #define RD_MASK		0x1f
33e30ec452SThiemo Seufer #define RD_SH		11
34e30ec452SThiemo Seufer #define RE_MASK		0x1f
35e30ec452SThiemo Seufer #define RE_SH		6
36e30ec452SThiemo Seufer #define IMM_MASK	0xffff
37e30ec452SThiemo Seufer #define IMM_SH		0
38e30ec452SThiemo Seufer #define JIMM_MASK	0x3ffffff
39e30ec452SThiemo Seufer #define JIMM_SH		0
40e30ec452SThiemo Seufer #define FUNC_MASK	0x3f
41e30ec452SThiemo Seufer #define FUNC_SH		0
42e30ec452SThiemo Seufer #define SET_MASK	0x7
43e30ec452SThiemo Seufer #define SET_SH		0
44e30ec452SThiemo Seufer 
45e30ec452SThiemo Seufer enum opcode {
46e30ec452SThiemo Seufer 	insn_invalid,
4771a1c776SSteven J. Hill 	insn_addiu, insn_addu, insn_and, insn_andi, insn_bbit0, insn_bbit1,
4871a1c776SSteven J. Hill 	insn_beq, insn_beql, insn_bgez, insn_bgezl, insn_bltz, insn_bltzl,
4971a1c776SSteven J. Hill 	insn_bne, insn_cache, insn_daddiu, insn_daddu, insn_dins, insn_dinsm,
504c12a854SMarkos Chandras 	insn_divu, insn_dmfc0, insn_dmtc0, insn_drotr, insn_drotr32, insn_dsll,
5171a1c776SSteven J. Hill 	insn_dsll32, insn_dsra, insn_dsrl, insn_dsrl32, insn_dsubu, insn_eret,
5249e9529bSPaul Burton 	insn_ext, insn_ins, insn_j, insn_jal, insn_jalr, insn_jr, insn_ld,
5349e9529bSPaul Burton 	insn_ldx, insn_ll, insn_lld, insn_lui, insn_lw, insn_lwx, insn_mfc0,
54f3ec7a23SMarkos Chandras 	insn_mfhi, insn_mtc0, insn_or, insn_ori, insn_pref, insn_rfe,
55390363edSMarkos Chandras 	insn_rotr, insn_sc, insn_scd, insn_sd, insn_sll, insn_sllv, insn_sltiu,
56e8ef868bSMarkos Chandras 	insn_sltu, insn_sra, insn_srl, insn_srlv, insn_subu, insn_sw, insn_sync,
57390363edSMarkos Chandras 	insn_syscall, insn_tlbp, insn_tlbr, insn_tlbwi, insn_tlbwr, insn_wait,
58390363edSMarkos Chandras 	insn_xor, insn_xori, insn_yield,
59e30ec452SThiemo Seufer };
60e30ec452SThiemo Seufer 
61e30ec452SThiemo Seufer struct insn {
62e30ec452SThiemo Seufer 	enum opcode opcode;
63e30ec452SThiemo Seufer 	u32 match;
64e30ec452SThiemo Seufer 	enum fields fields;
65e30ec452SThiemo Seufer };
66e30ec452SThiemo Seufer 
67078a55fcSPaul Gortmaker static inline u32 build_rs(u32 arg)
68e30ec452SThiemo Seufer {
698d662c8dSDavid Daney 	WARN(arg & ~RS_MASK, KERN_WARNING "Micro-assembler field overflow\n");
70e30ec452SThiemo Seufer 
71e30ec452SThiemo Seufer 	return (arg & RS_MASK) << RS_SH;
72e30ec452SThiemo Seufer }
73e30ec452SThiemo Seufer 
74078a55fcSPaul Gortmaker static inline u32 build_rt(u32 arg)
75e30ec452SThiemo Seufer {
768d662c8dSDavid Daney 	WARN(arg & ~RT_MASK, KERN_WARNING "Micro-assembler field overflow\n");
77e30ec452SThiemo Seufer 
78e30ec452SThiemo Seufer 	return (arg & RT_MASK) << RT_SH;
79e30ec452SThiemo Seufer }
80e30ec452SThiemo Seufer 
81078a55fcSPaul Gortmaker static inline u32 build_rd(u32 arg)
82e30ec452SThiemo Seufer {
838d662c8dSDavid Daney 	WARN(arg & ~RD_MASK, KERN_WARNING "Micro-assembler field overflow\n");
84e30ec452SThiemo Seufer 
85e30ec452SThiemo Seufer 	return (arg & RD_MASK) << RD_SH;
86e30ec452SThiemo Seufer }
87e30ec452SThiemo Seufer 
88078a55fcSPaul Gortmaker static inline u32 build_re(u32 arg)
89e30ec452SThiemo Seufer {
908d662c8dSDavid Daney 	WARN(arg & ~RE_MASK, KERN_WARNING "Micro-assembler field overflow\n");
91e30ec452SThiemo Seufer 
92e30ec452SThiemo Seufer 	return (arg & RE_MASK) << RE_SH;
93e30ec452SThiemo Seufer }
94e30ec452SThiemo Seufer 
95078a55fcSPaul Gortmaker static inline u32 build_simm(s32 arg)
96e30ec452SThiemo Seufer {
978d662c8dSDavid Daney 	WARN(arg > 0x7fff || arg < -0x8000,
988d662c8dSDavid Daney 	     KERN_WARNING "Micro-assembler field overflow\n");
99e30ec452SThiemo Seufer 
100e30ec452SThiemo Seufer 	return arg & 0xffff;
101e30ec452SThiemo Seufer }
102e30ec452SThiemo Seufer 
103078a55fcSPaul Gortmaker static inline u32 build_uimm(u32 arg)
104e30ec452SThiemo Seufer {
1058d662c8dSDavid Daney 	WARN(arg & ~IMM_MASK, KERN_WARNING "Micro-assembler field overflow\n");
106e30ec452SThiemo Seufer 
107e30ec452SThiemo Seufer 	return arg & IMM_MASK;
108e30ec452SThiemo Seufer }
109e30ec452SThiemo Seufer 
110078a55fcSPaul Gortmaker static inline u32 build_scimm(u32 arg)
11158b9e223SDavid Daney {
1128d662c8dSDavid Daney 	WARN(arg & ~SCIMM_MASK,
1138d662c8dSDavid Daney 	     KERN_WARNING "Micro-assembler field overflow\n");
11458b9e223SDavid Daney 
11558b9e223SDavid Daney 	return (arg & SCIMM_MASK) << SCIMM_SH;
11658b9e223SDavid Daney }
11758b9e223SDavid Daney 
118078a55fcSPaul Gortmaker static inline u32 build_func(u32 arg)
119e30ec452SThiemo Seufer {
1208d662c8dSDavid Daney 	WARN(arg & ~FUNC_MASK, KERN_WARNING "Micro-assembler field overflow\n");
121e30ec452SThiemo Seufer 
122e30ec452SThiemo Seufer 	return arg & FUNC_MASK;
123e30ec452SThiemo Seufer }
124e30ec452SThiemo Seufer 
125078a55fcSPaul Gortmaker static inline u32 build_set(u32 arg)
126e30ec452SThiemo Seufer {
1278d662c8dSDavid Daney 	WARN(arg & ~SET_MASK, KERN_WARNING "Micro-assembler field overflow\n");
128e30ec452SThiemo Seufer 
129e30ec452SThiemo Seufer 	return arg & SET_MASK;
130e30ec452SThiemo Seufer }
131e30ec452SThiemo Seufer 
132078a55fcSPaul Gortmaker static void build_insn(u32 **buf, enum opcode opc, ...);
133e30ec452SThiemo Seufer 
134e30ec452SThiemo Seufer #define I_u1u2u3(op)					\
135e30ec452SThiemo Seufer Ip_u1u2u3(op)						\
136e30ec452SThiemo Seufer {							\
137e30ec452SThiemo Seufer 	build_insn(buf, insn##op, a, b, c);		\
13822b0763aSDavid Daney }							\
13922b0763aSDavid Daney UASM_EXPORT_SYMBOL(uasm_i##op);
140e30ec452SThiemo Seufer 
141e30ec452SThiemo Seufer #define I_u2u1u3(op)					\
142e30ec452SThiemo Seufer Ip_u2u1u3(op)						\
143e30ec452SThiemo Seufer {							\
144e30ec452SThiemo Seufer 	build_insn(buf, insn##op, b, a, c);		\
14522b0763aSDavid Daney }							\
14622b0763aSDavid Daney UASM_EXPORT_SYMBOL(uasm_i##op);
147e30ec452SThiemo Seufer 
148beef8e02SMarkos Chandras #define I_u3u2u1(op)					\
149beef8e02SMarkos Chandras Ip_u3u2u1(op)						\
150beef8e02SMarkos Chandras {							\
151beef8e02SMarkos Chandras 	build_insn(buf, insn##op, c, b, a);		\
152beef8e02SMarkos Chandras }							\
153beef8e02SMarkos Chandras UASM_EXPORT_SYMBOL(uasm_i##op);
154beef8e02SMarkos Chandras 
155e30ec452SThiemo Seufer #define I_u3u1u2(op)					\
156e30ec452SThiemo Seufer Ip_u3u1u2(op)						\
157e30ec452SThiemo Seufer {							\
158e30ec452SThiemo Seufer 	build_insn(buf, insn##op, b, c, a);		\
15922b0763aSDavid Daney }							\
16022b0763aSDavid Daney UASM_EXPORT_SYMBOL(uasm_i##op);
161e30ec452SThiemo Seufer 
162e30ec452SThiemo Seufer #define I_u1u2s3(op)					\
163e30ec452SThiemo Seufer Ip_u1u2s3(op)						\
164e30ec452SThiemo Seufer {							\
165e30ec452SThiemo Seufer 	build_insn(buf, insn##op, a, b, c);		\
16622b0763aSDavid Daney }							\
16722b0763aSDavid Daney UASM_EXPORT_SYMBOL(uasm_i##op);
168e30ec452SThiemo Seufer 
169e30ec452SThiemo Seufer #define I_u2s3u1(op)					\
170e30ec452SThiemo Seufer Ip_u2s3u1(op)						\
171e30ec452SThiemo Seufer {							\
172e30ec452SThiemo Seufer 	build_insn(buf, insn##op, c, a, b);		\
17322b0763aSDavid Daney }							\
17422b0763aSDavid Daney UASM_EXPORT_SYMBOL(uasm_i##op);
175e30ec452SThiemo Seufer 
176e30ec452SThiemo Seufer #define I_u2u1s3(op)					\
177e30ec452SThiemo Seufer Ip_u2u1s3(op)						\
178e30ec452SThiemo Seufer {							\
179e30ec452SThiemo Seufer 	build_insn(buf, insn##op, b, a, c);		\
18022b0763aSDavid Daney }							\
18122b0763aSDavid Daney UASM_EXPORT_SYMBOL(uasm_i##op);
182e30ec452SThiemo Seufer 
18392078e06SDavid Daney #define I_u2u1msbu3(op)					\
18492078e06SDavid Daney Ip_u2u1msbu3(op)					\
18592078e06SDavid Daney {							\
18692078e06SDavid Daney 	build_insn(buf, insn##op, b, a, c+d-1, c);	\
18722b0763aSDavid Daney }							\
18822b0763aSDavid Daney UASM_EXPORT_SYMBOL(uasm_i##op);
18992078e06SDavid Daney 
190c42aef09SDavid Daney #define I_u2u1msb32u3(op)				\
191c42aef09SDavid Daney Ip_u2u1msbu3(op)					\
192c42aef09SDavid Daney {							\
193c42aef09SDavid Daney 	build_insn(buf, insn##op, b, a, c+d-33, c);	\
194c42aef09SDavid Daney }							\
195c42aef09SDavid Daney UASM_EXPORT_SYMBOL(uasm_i##op);
196c42aef09SDavid Daney 
197e6de1a09SSteven J. Hill #define I_u2u1msbdu3(op)				\
198e6de1a09SSteven J. Hill Ip_u2u1msbu3(op)					\
199e6de1a09SSteven J. Hill {							\
200e6de1a09SSteven J. Hill 	build_insn(buf, insn##op, b, a, d-1, c);	\
201e6de1a09SSteven J. Hill }							\
202e6de1a09SSteven J. Hill UASM_EXPORT_SYMBOL(uasm_i##op);
203e6de1a09SSteven J. Hill 
204e30ec452SThiemo Seufer #define I_u1u2(op)					\
205e30ec452SThiemo Seufer Ip_u1u2(op)						\
206e30ec452SThiemo Seufer {							\
207e30ec452SThiemo Seufer 	build_insn(buf, insn##op, a, b);		\
20822b0763aSDavid Daney }							\
20922b0763aSDavid Daney UASM_EXPORT_SYMBOL(uasm_i##op);
210e30ec452SThiemo Seufer 
211d674dd14SPaul Burton #define I_u2u1(op)					\
212d674dd14SPaul Burton Ip_u1u2(op)						\
213d674dd14SPaul Burton {							\
214d674dd14SPaul Burton 	build_insn(buf, insn##op, b, a);		\
215d674dd14SPaul Burton }							\
216d674dd14SPaul Burton UASM_EXPORT_SYMBOL(uasm_i##op);
217d674dd14SPaul Burton 
218e30ec452SThiemo Seufer #define I_u1s2(op)					\
219e30ec452SThiemo Seufer Ip_u1s2(op)						\
220e30ec452SThiemo Seufer {							\
221e30ec452SThiemo Seufer 	build_insn(buf, insn##op, a, b);		\
22222b0763aSDavid Daney }							\
22322b0763aSDavid Daney UASM_EXPORT_SYMBOL(uasm_i##op);
224e30ec452SThiemo Seufer 
225e30ec452SThiemo Seufer #define I_u1(op)					\
226e30ec452SThiemo Seufer Ip_u1(op)						\
227e30ec452SThiemo Seufer {							\
228e30ec452SThiemo Seufer 	build_insn(buf, insn##op, a);			\
22922b0763aSDavid Daney }							\
23022b0763aSDavid Daney UASM_EXPORT_SYMBOL(uasm_i##op);
231e30ec452SThiemo Seufer 
232e30ec452SThiemo Seufer #define I_0(op)						\
233e30ec452SThiemo Seufer Ip_0(op)						\
234e30ec452SThiemo Seufer {							\
235e30ec452SThiemo Seufer 	build_insn(buf, insn##op);			\
23622b0763aSDavid Daney }							\
23722b0763aSDavid Daney UASM_EXPORT_SYMBOL(uasm_i##op);
238e30ec452SThiemo Seufer 
239e30ec452SThiemo Seufer I_u2u1s3(_addiu)
240e30ec452SThiemo Seufer I_u3u1u2(_addu)
241e30ec452SThiemo Seufer I_u2u1u3(_andi)
242e30ec452SThiemo Seufer I_u3u1u2(_and)
243e30ec452SThiemo Seufer I_u1u2s3(_beq)
244e30ec452SThiemo Seufer I_u1u2s3(_beql)
245e30ec452SThiemo Seufer I_u1s2(_bgez)
246e30ec452SThiemo Seufer I_u1s2(_bgezl)
247e30ec452SThiemo Seufer I_u1s2(_bltz)
248e30ec452SThiemo Seufer I_u1s2(_bltzl)
249e30ec452SThiemo Seufer I_u1u2s3(_bne)
250fb2a27e7SThiemo Seufer I_u2s3u1(_cache)
251e30ec452SThiemo Seufer I_u1u2u3(_dmfc0)
252e30ec452SThiemo Seufer I_u1u2u3(_dmtc0)
253e30ec452SThiemo Seufer I_u2u1s3(_daddiu)
254e30ec452SThiemo Seufer I_u3u1u2(_daddu)
2554c12a854SMarkos Chandras I_u1u2(_divu)
256e30ec452SThiemo Seufer I_u2u1u3(_dsll)
257e30ec452SThiemo Seufer I_u2u1u3(_dsll32)
258e30ec452SThiemo Seufer I_u2u1u3(_dsra)
259e30ec452SThiemo Seufer I_u2u1u3(_dsrl)
260e30ec452SThiemo Seufer I_u2u1u3(_dsrl32)
26192078e06SDavid Daney I_u2u1u3(_drotr)
262de6d5b55SDavid Daney I_u2u1u3(_drotr32)
263e30ec452SThiemo Seufer I_u3u1u2(_dsubu)
264e30ec452SThiemo Seufer I_0(_eret)
265e6de1a09SSteven J. Hill I_u2u1msbdu3(_ext)
266e6de1a09SSteven J. Hill I_u2u1msbu3(_ins)
267e30ec452SThiemo Seufer I_u1(_j)
268e30ec452SThiemo Seufer I_u1(_jal)
26949e9529bSPaul Burton I_u2u1(_jalr)
270e30ec452SThiemo Seufer I_u1(_jr)
271e30ec452SThiemo Seufer I_u2s3u1(_ld)
272e30ec452SThiemo Seufer I_u2s3u1(_ll)
273e30ec452SThiemo Seufer I_u2s3u1(_lld)
274e30ec452SThiemo Seufer I_u1s2(_lui)
275e30ec452SThiemo Seufer I_u2s3u1(_lw)
276e30ec452SThiemo Seufer I_u1u2u3(_mfc0)
277f3ec7a23SMarkos Chandras I_u1(_mfhi)
278e30ec452SThiemo Seufer I_u1u2u3(_mtc0)
279e30ec452SThiemo Seufer I_u2u1u3(_ori)
2805808184fSRalf Baechle I_u3u1u2(_or)
281e30ec452SThiemo Seufer I_0(_rfe)
282e30ec452SThiemo Seufer I_u2s3u1(_sc)
283e30ec452SThiemo Seufer I_u2s3u1(_scd)
284e30ec452SThiemo Seufer I_u2s3u1(_sd)
285e30ec452SThiemo Seufer I_u2u1u3(_sll)
286bef581baSMarkos Chandras I_u3u2u1(_sllv)
287390363edSMarkos Chandras I_u2u1s3(_sltiu)
288e8ef868bSMarkos Chandras I_u3u1u2(_sltu)
289e30ec452SThiemo Seufer I_u2u1u3(_sra)
290e30ec452SThiemo Seufer I_u2u1u3(_srl)
291f31318fdSMarkos Chandras I_u3u2u1(_srlv)
29232546f38SDavid Daney I_u2u1u3(_rotr)
293e30ec452SThiemo Seufer I_u3u1u2(_subu)
294e30ec452SThiemo Seufer I_u2s3u1(_sw)
295729ff561SPaul Burton I_u1(_sync)
296e30ec452SThiemo Seufer I_0(_tlbp)
29732546f38SDavid Daney I_0(_tlbr)
298e30ec452SThiemo Seufer I_0(_tlbwi)
299e30ec452SThiemo Seufer I_0(_tlbwr)
30053ed1389SPaul Burton I_u1(_wait);
301e30ec452SThiemo Seufer I_u3u1u2(_xor)
302e30ec452SThiemo Seufer I_u2u1u3(_xori)
303d674dd14SPaul Burton I_u2u1(_yield)
30492078e06SDavid Daney I_u2u1msbu3(_dins);
305c42aef09SDavid Daney I_u2u1msb32u3(_dinsm);
30658b9e223SDavid Daney I_u1(_syscall);
3075b97c3f7SDavid Daney I_u1u2s3(_bbit0);
3085b97c3f7SDavid Daney I_u1u2s3(_bbit1);
309bb3d68c3SDavid Daney I_u3u1u2(_lwx)
310bb3d68c3SDavid Daney I_u3u1u2(_ldx)
311e30ec452SThiemo Seufer 
312c9941158SDavid Daney #ifdef CONFIG_CPU_CAVIUM_OCTEON
313c9941158SDavid Daney #include <asm/octeon/octeon.h>
314078a55fcSPaul Gortmaker void ISAFUNC(uasm_i_pref)(u32 **buf, unsigned int a, signed int b,
315c9941158SDavid Daney 			    unsigned int c)
316c9941158SDavid Daney {
317c9941158SDavid Daney 	if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_X) && a <= 24 && a != 5)
318c9941158SDavid Daney 		/*
319c9941158SDavid Daney 		 * As per erratum Core-14449, replace prefetches 0-4,
320c9941158SDavid Daney 		 * 6-24 with 'pref 28'.
321c9941158SDavid Daney 		 */
322c9941158SDavid Daney 		build_insn(buf, insn_pref, c, 28, b);
323c9941158SDavid Daney 	else
324c9941158SDavid Daney 		build_insn(buf, insn_pref, c, a, b);
325c9941158SDavid Daney }
326abc597feSSteven J. Hill UASM_EXPORT_SYMBOL(ISAFUNC(uasm_i_pref));
327c9941158SDavid Daney #else
328c9941158SDavid Daney I_u2s3u1(_pref)
329c9941158SDavid Daney #endif
330c9941158SDavid Daney 
331e30ec452SThiemo Seufer /* Handle labels. */
332078a55fcSPaul Gortmaker void ISAFUNC(uasm_build_label)(struct uasm_label **lab, u32 *addr, int lid)
333e30ec452SThiemo Seufer {
334e30ec452SThiemo Seufer 	(*lab)->addr = addr;
335e30ec452SThiemo Seufer 	(*lab)->lab = lid;
336e30ec452SThiemo Seufer 	(*lab)++;
337e30ec452SThiemo Seufer }
338abc597feSSteven J. Hill UASM_EXPORT_SYMBOL(ISAFUNC(uasm_build_label));
339e30ec452SThiemo Seufer 
340078a55fcSPaul Gortmaker int ISAFUNC(uasm_in_compat_space_p)(long addr)
341e30ec452SThiemo Seufer {
342e30ec452SThiemo Seufer 	/* Is this address in 32bit compat space? */
343e30ec452SThiemo Seufer #ifdef CONFIG_64BIT
344e30ec452SThiemo Seufer 	return (((addr) & 0xffffffff00000000L) == 0xffffffff00000000L);
345e30ec452SThiemo Seufer #else
346e30ec452SThiemo Seufer 	return 1;
347e30ec452SThiemo Seufer #endif
348e30ec452SThiemo Seufer }
349abc597feSSteven J. Hill UASM_EXPORT_SYMBOL(ISAFUNC(uasm_in_compat_space_p));
350e30ec452SThiemo Seufer 
351078a55fcSPaul Gortmaker static int uasm_rel_highest(long val)
352e30ec452SThiemo Seufer {
353e30ec452SThiemo Seufer #ifdef CONFIG_64BIT
354e30ec452SThiemo Seufer 	return ((((val + 0x800080008000L) >> 48) & 0xffff) ^ 0x8000) - 0x8000;
355e30ec452SThiemo Seufer #else
356e30ec452SThiemo Seufer 	return 0;
357e30ec452SThiemo Seufer #endif
358e30ec452SThiemo Seufer }
359e30ec452SThiemo Seufer 
360078a55fcSPaul Gortmaker static int uasm_rel_higher(long val)
361e30ec452SThiemo Seufer {
362e30ec452SThiemo Seufer #ifdef CONFIG_64BIT
363e30ec452SThiemo Seufer 	return ((((val + 0x80008000L) >> 32) & 0xffff) ^ 0x8000) - 0x8000;
364e30ec452SThiemo Seufer #else
365e30ec452SThiemo Seufer 	return 0;
366e30ec452SThiemo Seufer #endif
367e30ec452SThiemo Seufer }
368e30ec452SThiemo Seufer 
369078a55fcSPaul Gortmaker int ISAFUNC(uasm_rel_hi)(long val)
370e30ec452SThiemo Seufer {
371e30ec452SThiemo Seufer 	return ((((val + 0x8000L) >> 16) & 0xffff) ^ 0x8000) - 0x8000;
372e30ec452SThiemo Seufer }
373abc597feSSteven J. Hill UASM_EXPORT_SYMBOL(ISAFUNC(uasm_rel_hi));
374e30ec452SThiemo Seufer 
375078a55fcSPaul Gortmaker int ISAFUNC(uasm_rel_lo)(long val)
376e30ec452SThiemo Seufer {
377e30ec452SThiemo Seufer 	return ((val & 0xffff) ^ 0x8000) - 0x8000;
378e30ec452SThiemo Seufer }
379abc597feSSteven J. Hill UASM_EXPORT_SYMBOL(ISAFUNC(uasm_rel_lo));
380e30ec452SThiemo Seufer 
381078a55fcSPaul Gortmaker void ISAFUNC(UASM_i_LA_mostly)(u32 **buf, unsigned int rs, long addr)
382e30ec452SThiemo Seufer {
383abc597feSSteven J. Hill 	if (!ISAFUNC(uasm_in_compat_space_p)(addr)) {
384abc597feSSteven J. Hill 		ISAFUNC(uasm_i_lui)(buf, rs, uasm_rel_highest(addr));
385e30ec452SThiemo Seufer 		if (uasm_rel_higher(addr))
386abc597feSSteven J. Hill 			ISAFUNC(uasm_i_daddiu)(buf, rs, rs, uasm_rel_higher(addr));
387abc597feSSteven J. Hill 		if (ISAFUNC(uasm_rel_hi(addr))) {
388abc597feSSteven J. Hill 			ISAFUNC(uasm_i_dsll)(buf, rs, rs, 16);
389abc597feSSteven J. Hill 			ISAFUNC(uasm_i_daddiu)(buf, rs, rs,
390abc597feSSteven J. Hill 					ISAFUNC(uasm_rel_hi)(addr));
391abc597feSSteven J. Hill 			ISAFUNC(uasm_i_dsll)(buf, rs, rs, 16);
392e30ec452SThiemo Seufer 		} else
393abc597feSSteven J. Hill 			ISAFUNC(uasm_i_dsll32)(buf, rs, rs, 0);
394e30ec452SThiemo Seufer 	} else
395abc597feSSteven J. Hill 		ISAFUNC(uasm_i_lui)(buf, rs, ISAFUNC(uasm_rel_hi(addr)));
396e30ec452SThiemo Seufer }
397abc597feSSteven J. Hill UASM_EXPORT_SYMBOL(ISAFUNC(UASM_i_LA_mostly));
398e30ec452SThiemo Seufer 
399078a55fcSPaul Gortmaker void ISAFUNC(UASM_i_LA)(u32 **buf, unsigned int rs, long addr)
400e30ec452SThiemo Seufer {
401abc597feSSteven J. Hill 	ISAFUNC(UASM_i_LA_mostly)(buf, rs, addr);
402abc597feSSteven J. Hill 	if (ISAFUNC(uasm_rel_lo(addr))) {
403abc597feSSteven J. Hill 		if (!ISAFUNC(uasm_in_compat_space_p)(addr))
404abc597feSSteven J. Hill 			ISAFUNC(uasm_i_daddiu)(buf, rs, rs,
405abc597feSSteven J. Hill 					ISAFUNC(uasm_rel_lo(addr)));
406e30ec452SThiemo Seufer 		else
407abc597feSSteven J. Hill 			ISAFUNC(uasm_i_addiu)(buf, rs, rs,
408abc597feSSteven J. Hill 					ISAFUNC(uasm_rel_lo(addr)));
409e30ec452SThiemo Seufer 	}
410e30ec452SThiemo Seufer }
411abc597feSSteven J. Hill UASM_EXPORT_SYMBOL(ISAFUNC(UASM_i_LA));
412e30ec452SThiemo Seufer 
413e30ec452SThiemo Seufer /* Handle relocations. */
414078a55fcSPaul Gortmaker void ISAFUNC(uasm_r_mips_pc16)(struct uasm_reloc **rel, u32 *addr, int lid)
415e30ec452SThiemo Seufer {
416e30ec452SThiemo Seufer 	(*rel)->addr = addr;
417e30ec452SThiemo Seufer 	(*rel)->type = R_MIPS_PC16;
418e30ec452SThiemo Seufer 	(*rel)->lab = lid;
419e30ec452SThiemo Seufer 	(*rel)++;
420e30ec452SThiemo Seufer }
421abc597feSSteven J. Hill UASM_EXPORT_SYMBOL(ISAFUNC(uasm_r_mips_pc16));
422e30ec452SThiemo Seufer 
423078a55fcSPaul Gortmaker static inline void __resolve_relocs(struct uasm_reloc *rel,
424078a55fcSPaul Gortmaker 				    struct uasm_label *lab);
425e30ec452SThiemo Seufer 
426078a55fcSPaul Gortmaker void ISAFUNC(uasm_resolve_relocs)(struct uasm_reloc *rel,
427078a55fcSPaul Gortmaker 				  struct uasm_label *lab)
428e30ec452SThiemo Seufer {
429e30ec452SThiemo Seufer 	struct uasm_label *l;
430e30ec452SThiemo Seufer 
431e30ec452SThiemo Seufer 	for (; rel->lab != UASM_LABEL_INVALID; rel++)
432e30ec452SThiemo Seufer 		for (l = lab; l->lab != UASM_LABEL_INVALID; l++)
433e30ec452SThiemo Seufer 			if (rel->lab == l->lab)
434e30ec452SThiemo Seufer 				__resolve_relocs(rel, l);
435e30ec452SThiemo Seufer }
436abc597feSSteven J. Hill UASM_EXPORT_SYMBOL(ISAFUNC(uasm_resolve_relocs));
437e30ec452SThiemo Seufer 
438078a55fcSPaul Gortmaker void ISAFUNC(uasm_move_relocs)(struct uasm_reloc *rel, u32 *first, u32 *end,
439078a55fcSPaul Gortmaker 			       long off)
440e30ec452SThiemo Seufer {
441e30ec452SThiemo Seufer 	for (; rel->lab != UASM_LABEL_INVALID; rel++)
442e30ec452SThiemo Seufer 		if (rel->addr >= first && rel->addr < end)
443e30ec452SThiemo Seufer 			rel->addr += off;
444e30ec452SThiemo Seufer }
445abc597feSSteven J. Hill UASM_EXPORT_SYMBOL(ISAFUNC(uasm_move_relocs));
446e30ec452SThiemo Seufer 
447078a55fcSPaul Gortmaker void ISAFUNC(uasm_move_labels)(struct uasm_label *lab, u32 *first, u32 *end,
448078a55fcSPaul Gortmaker 			       long off)
449e30ec452SThiemo Seufer {
450e30ec452SThiemo Seufer 	for (; lab->lab != UASM_LABEL_INVALID; lab++)
451e30ec452SThiemo Seufer 		if (lab->addr >= first && lab->addr < end)
452e30ec452SThiemo Seufer 			lab->addr += off;
453e30ec452SThiemo Seufer }
454abc597feSSteven J. Hill UASM_EXPORT_SYMBOL(ISAFUNC(uasm_move_labels));
455e30ec452SThiemo Seufer 
456078a55fcSPaul Gortmaker void ISAFUNC(uasm_copy_handler)(struct uasm_reloc *rel, struct uasm_label *lab,
457078a55fcSPaul Gortmaker 				u32 *first, u32 *end, u32 *target)
458e30ec452SThiemo Seufer {
459e30ec452SThiemo Seufer 	long off = (long)(target - first);
460e30ec452SThiemo Seufer 
461e30ec452SThiemo Seufer 	memcpy(target, first, (end - first) * sizeof(u32));
462e30ec452SThiemo Seufer 
463abc597feSSteven J. Hill 	ISAFUNC(uasm_move_relocs(rel, first, end, off));
464abc597feSSteven J. Hill 	ISAFUNC(uasm_move_labels(lab, first, end, off));
465e30ec452SThiemo Seufer }
466abc597feSSteven J. Hill UASM_EXPORT_SYMBOL(ISAFUNC(uasm_copy_handler));
467e30ec452SThiemo Seufer 
468078a55fcSPaul Gortmaker int ISAFUNC(uasm_insn_has_bdelay)(struct uasm_reloc *rel, u32 *addr)
469e30ec452SThiemo Seufer {
470e30ec452SThiemo Seufer 	for (; rel->lab != UASM_LABEL_INVALID; rel++) {
471e30ec452SThiemo Seufer 		if (rel->addr == addr
472e30ec452SThiemo Seufer 		    && (rel->type == R_MIPS_PC16
473e30ec452SThiemo Seufer 			|| rel->type == R_MIPS_26))
474e30ec452SThiemo Seufer 			return 1;
475e30ec452SThiemo Seufer 	}
476e30ec452SThiemo Seufer 
477e30ec452SThiemo Seufer 	return 0;
478e30ec452SThiemo Seufer }
479abc597feSSteven J. Hill UASM_EXPORT_SYMBOL(ISAFUNC(uasm_insn_has_bdelay));
480e30ec452SThiemo Seufer 
481e30ec452SThiemo Seufer /* Convenience functions for labeled branches. */
482078a55fcSPaul Gortmaker void ISAFUNC(uasm_il_bltz)(u32 **p, struct uasm_reloc **r, unsigned int reg,
483078a55fcSPaul Gortmaker 			   int lid)
484e30ec452SThiemo Seufer {
485e30ec452SThiemo Seufer 	uasm_r_mips_pc16(r, *p, lid);
486abc597feSSteven J. Hill 	ISAFUNC(uasm_i_bltz)(p, reg, 0);
487e30ec452SThiemo Seufer }
488abc597feSSteven J. Hill UASM_EXPORT_SYMBOL(ISAFUNC(uasm_il_bltz));
489e30ec452SThiemo Seufer 
490078a55fcSPaul Gortmaker void ISAFUNC(uasm_il_b)(u32 **p, struct uasm_reloc **r, int lid)
491e30ec452SThiemo Seufer {
492e30ec452SThiemo Seufer 	uasm_r_mips_pc16(r, *p, lid);
493abc597feSSteven J. Hill 	ISAFUNC(uasm_i_b)(p, 0);
494e30ec452SThiemo Seufer }
495abc597feSSteven J. Hill UASM_EXPORT_SYMBOL(ISAFUNC(uasm_il_b));
496e30ec452SThiemo Seufer 
4978dee5901SPaul Burton void ISAFUNC(uasm_il_beq)(u32 **p, struct uasm_reloc **r, unsigned int r1,
4988dee5901SPaul Burton 			  unsigned int r2, int lid)
4998dee5901SPaul Burton {
5008dee5901SPaul Burton 	uasm_r_mips_pc16(r, *p, lid);
5018dee5901SPaul Burton 	ISAFUNC(uasm_i_beq)(p, r1, r2, 0);
5028dee5901SPaul Burton }
5038dee5901SPaul Burton UASM_EXPORT_SYMBOL(ISAFUNC(uasm_il_beq));
5048dee5901SPaul Burton 
505078a55fcSPaul Gortmaker void ISAFUNC(uasm_il_beqz)(u32 **p, struct uasm_reloc **r, unsigned int reg,
506078a55fcSPaul Gortmaker 			   int lid)
507e30ec452SThiemo Seufer {
508e30ec452SThiemo Seufer 	uasm_r_mips_pc16(r, *p, lid);
509abc597feSSteven J. Hill 	ISAFUNC(uasm_i_beqz)(p, reg, 0);
510e30ec452SThiemo Seufer }
511abc597feSSteven J. Hill UASM_EXPORT_SYMBOL(ISAFUNC(uasm_il_beqz));
512e30ec452SThiemo Seufer 
513078a55fcSPaul Gortmaker void ISAFUNC(uasm_il_beqzl)(u32 **p, struct uasm_reloc **r, unsigned int reg,
514078a55fcSPaul Gortmaker 			    int lid)
515e30ec452SThiemo Seufer {
516e30ec452SThiemo Seufer 	uasm_r_mips_pc16(r, *p, lid);
517abc597feSSteven J. Hill 	ISAFUNC(uasm_i_beqzl)(p, reg, 0);
518e30ec452SThiemo Seufer }
519abc597feSSteven J. Hill UASM_EXPORT_SYMBOL(ISAFUNC(uasm_il_beqzl));
520e30ec452SThiemo Seufer 
521078a55fcSPaul Gortmaker void ISAFUNC(uasm_il_bne)(u32 **p, struct uasm_reloc **r, unsigned int reg1,
522fb2a27e7SThiemo Seufer 			  unsigned int reg2, int lid)
523fb2a27e7SThiemo Seufer {
524fb2a27e7SThiemo Seufer 	uasm_r_mips_pc16(r, *p, lid);
525abc597feSSteven J. Hill 	ISAFUNC(uasm_i_bne)(p, reg1, reg2, 0);
526fb2a27e7SThiemo Seufer }
527abc597feSSteven J. Hill UASM_EXPORT_SYMBOL(ISAFUNC(uasm_il_bne));
528fb2a27e7SThiemo Seufer 
529078a55fcSPaul Gortmaker void ISAFUNC(uasm_il_bnez)(u32 **p, struct uasm_reloc **r, unsigned int reg,
530078a55fcSPaul Gortmaker 			   int lid)
531e30ec452SThiemo Seufer {
532e30ec452SThiemo Seufer 	uasm_r_mips_pc16(r, *p, lid);
533abc597feSSteven J. Hill 	ISAFUNC(uasm_i_bnez)(p, reg, 0);
534e30ec452SThiemo Seufer }
535abc597feSSteven J. Hill UASM_EXPORT_SYMBOL(ISAFUNC(uasm_il_bnez));
536e30ec452SThiemo Seufer 
537078a55fcSPaul Gortmaker void ISAFUNC(uasm_il_bgezl)(u32 **p, struct uasm_reloc **r, unsigned int reg,
538078a55fcSPaul Gortmaker 			    int lid)
539e30ec452SThiemo Seufer {
540e30ec452SThiemo Seufer 	uasm_r_mips_pc16(r, *p, lid);
541abc597feSSteven J. Hill 	ISAFUNC(uasm_i_bgezl)(p, reg, 0);
542e30ec452SThiemo Seufer }
543abc597feSSteven J. Hill UASM_EXPORT_SYMBOL(ISAFUNC(uasm_il_bgezl));
544e30ec452SThiemo Seufer 
545078a55fcSPaul Gortmaker void ISAFUNC(uasm_il_bgez)(u32 **p, struct uasm_reloc **r, unsigned int reg,
546078a55fcSPaul Gortmaker 			   int lid)
547e30ec452SThiemo Seufer {
548e30ec452SThiemo Seufer 	uasm_r_mips_pc16(r, *p, lid);
549abc597feSSteven J. Hill 	ISAFUNC(uasm_i_bgez)(p, reg, 0);
550e30ec452SThiemo Seufer }
551abc597feSSteven J. Hill UASM_EXPORT_SYMBOL(ISAFUNC(uasm_il_bgez));
5525b97c3f7SDavid Daney 
553078a55fcSPaul Gortmaker void ISAFUNC(uasm_il_bbit0)(u32 **p, struct uasm_reloc **r, unsigned int reg,
5545b97c3f7SDavid Daney 			    unsigned int bit, int lid)
5555b97c3f7SDavid Daney {
5565b97c3f7SDavid Daney 	uasm_r_mips_pc16(r, *p, lid);
557abc597feSSteven J. Hill 	ISAFUNC(uasm_i_bbit0)(p, reg, bit, 0);
5585b97c3f7SDavid Daney }
559abc597feSSteven J. Hill UASM_EXPORT_SYMBOL(ISAFUNC(uasm_il_bbit0));
5605b97c3f7SDavid Daney 
561078a55fcSPaul Gortmaker void ISAFUNC(uasm_il_bbit1)(u32 **p, struct uasm_reloc **r, unsigned int reg,
5625b97c3f7SDavid Daney 			    unsigned int bit, int lid)
5635b97c3f7SDavid Daney {
5645b97c3f7SDavid Daney 	uasm_r_mips_pc16(r, *p, lid);
565abc597feSSteven J. Hill 	ISAFUNC(uasm_i_bbit1)(p, reg, bit, 0);
5665b97c3f7SDavid Daney }
567abc597feSSteven J. Hill UASM_EXPORT_SYMBOL(ISAFUNC(uasm_il_bbit1));
568