xref: /kernel/linux/linux-6.6/arch/mips/mm/uasm.c (revision 62306a36)
162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public
362306a36Sopenharmony_ci * License.  See the file "COPYING" in the main directory of this archive
462306a36Sopenharmony_ci * for more details.
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * A small micro-assembler. It is intentionally kept simple, does only
762306a36Sopenharmony_ci * support a subset of instructions, and does not try to hide pipeline
862306a36Sopenharmony_ci * effects like branch delay slots.
962306a36Sopenharmony_ci *
1062306a36Sopenharmony_ci * Copyright (C) 2004, 2005, 2006, 2008	 Thiemo Seufer
1162306a36Sopenharmony_ci * Copyright (C) 2005, 2007  Maciej W. Rozycki
1262306a36Sopenharmony_ci * Copyright (C) 2006  Ralf Baechle (ralf@linux-mips.org)
1362306a36Sopenharmony_ci * Copyright (C) 2012, 2013  MIPS Technologies, Inc.  All rights reserved.
1462306a36Sopenharmony_ci */
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_cienum fields {
1762306a36Sopenharmony_ci	RS = 0x001,
1862306a36Sopenharmony_ci	RT = 0x002,
1962306a36Sopenharmony_ci	RD = 0x004,
2062306a36Sopenharmony_ci	RE = 0x008,
2162306a36Sopenharmony_ci	SIMM = 0x010,
2262306a36Sopenharmony_ci	UIMM = 0x020,
2362306a36Sopenharmony_ci	BIMM = 0x040,
2462306a36Sopenharmony_ci	JIMM = 0x080,
2562306a36Sopenharmony_ci	FUNC = 0x100,
2662306a36Sopenharmony_ci	SET = 0x200,
2762306a36Sopenharmony_ci	SCIMM = 0x400,
2862306a36Sopenharmony_ci	SIMM9 = 0x800,
2962306a36Sopenharmony_ci};
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci#define OP_MASK		0x3f
3262306a36Sopenharmony_ci#define OP_SH		26
3362306a36Sopenharmony_ci#define RD_MASK		0x1f
3462306a36Sopenharmony_ci#define RD_SH		11
3562306a36Sopenharmony_ci#define RE_MASK		0x1f
3662306a36Sopenharmony_ci#define RE_SH		6
3762306a36Sopenharmony_ci#define IMM_MASK	0xffff
3862306a36Sopenharmony_ci#define IMM_SH		0
3962306a36Sopenharmony_ci#define JIMM_MASK	0x3ffffff
4062306a36Sopenharmony_ci#define JIMM_SH		0
4162306a36Sopenharmony_ci#define FUNC_MASK	0x3f
4262306a36Sopenharmony_ci#define FUNC_SH		0
4362306a36Sopenharmony_ci#define SET_MASK	0x7
4462306a36Sopenharmony_ci#define SET_SH		0
4562306a36Sopenharmony_ci#define SIMM9_SH	7
4662306a36Sopenharmony_ci#define SIMM9_MASK	0x1ff
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_cienum opcode {
4962306a36Sopenharmony_ci	insn_addiu, insn_addu, insn_and, insn_andi, insn_bbit0, insn_bbit1,
5062306a36Sopenharmony_ci	insn_beq, insn_beql, insn_bgez, insn_bgezl, insn_bgtz, insn_blez,
5162306a36Sopenharmony_ci	insn_bltz, insn_bltzl, insn_bne, insn_break, insn_cache, insn_cfc1,
5262306a36Sopenharmony_ci	insn_cfcmsa, insn_ctc1, insn_ctcmsa, insn_daddiu, insn_daddu, insn_ddivu,
5362306a36Sopenharmony_ci	insn_ddivu_r6, insn_di, insn_dins, insn_dinsm, insn_dinsu, insn_divu,
5462306a36Sopenharmony_ci	insn_divu_r6, insn_dmfc0, insn_dmodu, insn_dmtc0, insn_dmultu,
5562306a36Sopenharmony_ci	insn_dmulu, insn_drotr, insn_drotr32, insn_dsbh, insn_dshd, insn_dsll,
5662306a36Sopenharmony_ci	insn_dsll32, insn_dsllv, insn_dsra, insn_dsra32, insn_dsrav, insn_dsrl,
5762306a36Sopenharmony_ci	insn_dsrl32, insn_dsrlv, insn_dsubu, insn_eret, insn_ext, insn_ins,
5862306a36Sopenharmony_ci	insn_j, insn_jal, insn_jalr, insn_jr, insn_lb, insn_lbu, insn_ld,
5962306a36Sopenharmony_ci	insn_lddir, insn_ldpte, insn_ldx, insn_lh, insn_lhu, insn_ll, insn_lld,
6062306a36Sopenharmony_ci	insn_lui, insn_lw, insn_lwu, insn_lwx, insn_mfc0, insn_mfhc0, insn_mfhi,
6162306a36Sopenharmony_ci	insn_mflo, insn_modu, insn_movn, insn_movz, insn_mtc0, insn_mthc0,
6262306a36Sopenharmony_ci	insn_mthi, insn_mtlo, insn_mul, insn_multu, insn_mulu, insn_muhu, insn_nor,
6362306a36Sopenharmony_ci	insn_or, insn_ori, insn_pref, insn_rfe, insn_rotr, insn_sb, insn_sc,
6462306a36Sopenharmony_ci	insn_scd, insn_seleqz, insn_selnez, insn_sd, insn_sh, insn_sll,
6562306a36Sopenharmony_ci	insn_sllv, insn_slt, insn_slti, insn_sltiu, insn_sltu, insn_sra,
6662306a36Sopenharmony_ci	insn_srav, insn_srl, insn_srlv, insn_subu, insn_sw, insn_sync,
6762306a36Sopenharmony_ci	insn_syscall, insn_tlbp, insn_tlbr, insn_tlbwi, insn_tlbwr, insn_wait,
6862306a36Sopenharmony_ci	insn_wsbh, insn_xor, insn_xori, insn_yield,
6962306a36Sopenharmony_ci	insn_invalid /* insn_invalid must be last */
7062306a36Sopenharmony_ci};
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_cistruct insn {
7362306a36Sopenharmony_ci	u32 match;
7462306a36Sopenharmony_ci	enum fields fields;
7562306a36Sopenharmony_ci};
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_cistatic inline u32 build_rs(u32 arg)
7862306a36Sopenharmony_ci{
7962306a36Sopenharmony_ci	WARN(arg & ~RS_MASK, KERN_WARNING "Micro-assembler field overflow\n");
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	return (arg & RS_MASK) << RS_SH;
8262306a36Sopenharmony_ci}
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_cistatic inline u32 build_rt(u32 arg)
8562306a36Sopenharmony_ci{
8662306a36Sopenharmony_ci	WARN(arg & ~RT_MASK, KERN_WARNING "Micro-assembler field overflow\n");
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	return (arg & RT_MASK) << RT_SH;
8962306a36Sopenharmony_ci}
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_cistatic inline u32 build_rd(u32 arg)
9262306a36Sopenharmony_ci{
9362306a36Sopenharmony_ci	WARN(arg & ~RD_MASK, KERN_WARNING "Micro-assembler field overflow\n");
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	return (arg & RD_MASK) << RD_SH;
9662306a36Sopenharmony_ci}
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_cistatic inline u32 build_re(u32 arg)
9962306a36Sopenharmony_ci{
10062306a36Sopenharmony_ci	WARN(arg & ~RE_MASK, KERN_WARNING "Micro-assembler field overflow\n");
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	return (arg & RE_MASK) << RE_SH;
10362306a36Sopenharmony_ci}
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_cistatic inline u32 build_simm(s32 arg)
10662306a36Sopenharmony_ci{
10762306a36Sopenharmony_ci	WARN(arg > 0x7fff || arg < -0x8000,
10862306a36Sopenharmony_ci	     KERN_WARNING "Micro-assembler field overflow\n");
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	return arg & 0xffff;
11162306a36Sopenharmony_ci}
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_cistatic inline u32 build_uimm(u32 arg)
11462306a36Sopenharmony_ci{
11562306a36Sopenharmony_ci	WARN(arg & ~IMM_MASK, KERN_WARNING "Micro-assembler field overflow\n");
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	return arg & IMM_MASK;
11862306a36Sopenharmony_ci}
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_cistatic inline u32 build_scimm(u32 arg)
12162306a36Sopenharmony_ci{
12262306a36Sopenharmony_ci	WARN(arg & ~SCIMM_MASK,
12362306a36Sopenharmony_ci	     KERN_WARNING "Micro-assembler field overflow\n");
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	return (arg & SCIMM_MASK) << SCIMM_SH;
12662306a36Sopenharmony_ci}
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_cistatic inline u32 build_scimm9(s32 arg)
12962306a36Sopenharmony_ci{
13062306a36Sopenharmony_ci	WARN((arg > 0xff || arg < -0x100),
13162306a36Sopenharmony_ci	       KERN_WARNING "Micro-assembler field overflow\n");
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	return (arg & SIMM9_MASK) << SIMM9_SH;
13462306a36Sopenharmony_ci}
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_cistatic inline u32 build_func(u32 arg)
13762306a36Sopenharmony_ci{
13862306a36Sopenharmony_ci	WARN(arg & ~FUNC_MASK, KERN_WARNING "Micro-assembler field overflow\n");
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci	return arg & FUNC_MASK;
14162306a36Sopenharmony_ci}
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_cistatic inline u32 build_set(u32 arg)
14462306a36Sopenharmony_ci{
14562306a36Sopenharmony_ci	WARN(arg & ~SET_MASK, KERN_WARNING "Micro-assembler field overflow\n");
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	return arg & SET_MASK;
14862306a36Sopenharmony_ci}
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_cistatic void build_insn(u32 **buf, enum opcode opc, ...);
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci#define I_u1u2u3(op)					\
15362306a36Sopenharmony_ciIp_u1u2u3(op)						\
15462306a36Sopenharmony_ci{							\
15562306a36Sopenharmony_ci	build_insn(buf, insn##op, a, b, c);		\
15662306a36Sopenharmony_ci}							\
15762306a36Sopenharmony_ciUASM_EXPORT_SYMBOL(uasm_i##op);
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci#define I_s3s1s2(op)					\
16062306a36Sopenharmony_ciIp_s3s1s2(op)						\
16162306a36Sopenharmony_ci{							\
16262306a36Sopenharmony_ci	build_insn(buf, insn##op, b, c, a);		\
16362306a36Sopenharmony_ci}							\
16462306a36Sopenharmony_ciUASM_EXPORT_SYMBOL(uasm_i##op);
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci#define I_u2u1u3(op)					\
16762306a36Sopenharmony_ciIp_u2u1u3(op)						\
16862306a36Sopenharmony_ci{							\
16962306a36Sopenharmony_ci	build_insn(buf, insn##op, b, a, c);		\
17062306a36Sopenharmony_ci}							\
17162306a36Sopenharmony_ciUASM_EXPORT_SYMBOL(uasm_i##op);
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci#define I_u3u2u1(op)					\
17462306a36Sopenharmony_ciIp_u3u2u1(op)						\
17562306a36Sopenharmony_ci{							\
17662306a36Sopenharmony_ci	build_insn(buf, insn##op, c, b, a);		\
17762306a36Sopenharmony_ci}							\
17862306a36Sopenharmony_ciUASM_EXPORT_SYMBOL(uasm_i##op);
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci#define I_u3u1u2(op)					\
18162306a36Sopenharmony_ciIp_u3u1u2(op)						\
18262306a36Sopenharmony_ci{							\
18362306a36Sopenharmony_ci	build_insn(buf, insn##op, b, c, a);		\
18462306a36Sopenharmony_ci}							\
18562306a36Sopenharmony_ciUASM_EXPORT_SYMBOL(uasm_i##op);
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci#define I_u1u2s3(op)					\
18862306a36Sopenharmony_ciIp_u1u2s3(op)						\
18962306a36Sopenharmony_ci{							\
19062306a36Sopenharmony_ci	build_insn(buf, insn##op, a, b, c);		\
19162306a36Sopenharmony_ci}							\
19262306a36Sopenharmony_ciUASM_EXPORT_SYMBOL(uasm_i##op);
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci#define I_u2s3u1(op)					\
19562306a36Sopenharmony_ciIp_u2s3u1(op)						\
19662306a36Sopenharmony_ci{							\
19762306a36Sopenharmony_ci	build_insn(buf, insn##op, c, a, b);		\
19862306a36Sopenharmony_ci}							\
19962306a36Sopenharmony_ciUASM_EXPORT_SYMBOL(uasm_i##op);
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci#define I_u2u1s3(op)					\
20262306a36Sopenharmony_ciIp_u2u1s3(op)						\
20362306a36Sopenharmony_ci{							\
20462306a36Sopenharmony_ci	build_insn(buf, insn##op, b, a, c);		\
20562306a36Sopenharmony_ci}							\
20662306a36Sopenharmony_ciUASM_EXPORT_SYMBOL(uasm_i##op);
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci#define I_u2u1msbu3(op)					\
20962306a36Sopenharmony_ciIp_u2u1msbu3(op)					\
21062306a36Sopenharmony_ci{							\
21162306a36Sopenharmony_ci	build_insn(buf, insn##op, b, a, c+d-1, c);	\
21262306a36Sopenharmony_ci}							\
21362306a36Sopenharmony_ciUASM_EXPORT_SYMBOL(uasm_i##op);
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci#define I_u2u1msb32u3(op)				\
21662306a36Sopenharmony_ciIp_u2u1msbu3(op)					\
21762306a36Sopenharmony_ci{							\
21862306a36Sopenharmony_ci	build_insn(buf, insn##op, b, a, c+d-33, c);	\
21962306a36Sopenharmony_ci}							\
22062306a36Sopenharmony_ciUASM_EXPORT_SYMBOL(uasm_i##op);
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci#define I_u2u1msb32msb3(op)				\
22362306a36Sopenharmony_ciIp_u2u1msbu3(op)					\
22462306a36Sopenharmony_ci{							\
22562306a36Sopenharmony_ci	build_insn(buf, insn##op, b, a, c+d-33, c-32);	\
22662306a36Sopenharmony_ci}							\
22762306a36Sopenharmony_ciUASM_EXPORT_SYMBOL(uasm_i##op);
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci#define I_u2u1msbdu3(op)				\
23062306a36Sopenharmony_ciIp_u2u1msbu3(op)					\
23162306a36Sopenharmony_ci{							\
23262306a36Sopenharmony_ci	build_insn(buf, insn##op, b, a, d-1, c);	\
23362306a36Sopenharmony_ci}							\
23462306a36Sopenharmony_ciUASM_EXPORT_SYMBOL(uasm_i##op);
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci#define I_u1u2(op)					\
23762306a36Sopenharmony_ciIp_u1u2(op)						\
23862306a36Sopenharmony_ci{							\
23962306a36Sopenharmony_ci	build_insn(buf, insn##op, a, b);		\
24062306a36Sopenharmony_ci}							\
24162306a36Sopenharmony_ciUASM_EXPORT_SYMBOL(uasm_i##op);
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci#define I_u2u1(op)					\
24462306a36Sopenharmony_ciIp_u1u2(op)						\
24562306a36Sopenharmony_ci{							\
24662306a36Sopenharmony_ci	build_insn(buf, insn##op, b, a);		\
24762306a36Sopenharmony_ci}							\
24862306a36Sopenharmony_ciUASM_EXPORT_SYMBOL(uasm_i##op);
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci#define I_u1s2(op)					\
25162306a36Sopenharmony_ciIp_u1s2(op)						\
25262306a36Sopenharmony_ci{							\
25362306a36Sopenharmony_ci	build_insn(buf, insn##op, a, b);		\
25462306a36Sopenharmony_ci}							\
25562306a36Sopenharmony_ciUASM_EXPORT_SYMBOL(uasm_i##op);
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci#define I_u1(op)					\
25862306a36Sopenharmony_ciIp_u1(op)						\
25962306a36Sopenharmony_ci{							\
26062306a36Sopenharmony_ci	build_insn(buf, insn##op, a);			\
26162306a36Sopenharmony_ci}							\
26262306a36Sopenharmony_ciUASM_EXPORT_SYMBOL(uasm_i##op);
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci#define I_0(op)						\
26562306a36Sopenharmony_ciIp_0(op)						\
26662306a36Sopenharmony_ci{							\
26762306a36Sopenharmony_ci	build_insn(buf, insn##op);			\
26862306a36Sopenharmony_ci}							\
26962306a36Sopenharmony_ciUASM_EXPORT_SYMBOL(uasm_i##op);
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ciI_u2u1s3(_addiu)
27262306a36Sopenharmony_ciI_u3u1u2(_addu)
27362306a36Sopenharmony_ciI_u2u1u3(_andi)
27462306a36Sopenharmony_ciI_u3u1u2(_and)
27562306a36Sopenharmony_ciI_u1u2s3(_beq)
27662306a36Sopenharmony_ciI_u1u2s3(_beql)
27762306a36Sopenharmony_ciI_u1s2(_bgez)
27862306a36Sopenharmony_ciI_u1s2(_bgezl)
27962306a36Sopenharmony_ciI_u1s2(_bgtz)
28062306a36Sopenharmony_ciI_u1s2(_blez)
28162306a36Sopenharmony_ciI_u1s2(_bltz)
28262306a36Sopenharmony_ciI_u1s2(_bltzl)
28362306a36Sopenharmony_ciI_u1u2s3(_bne)
28462306a36Sopenharmony_ciI_u1(_break)
28562306a36Sopenharmony_ciI_u2s3u1(_cache)
28662306a36Sopenharmony_ciI_u1u2(_cfc1)
28762306a36Sopenharmony_ciI_u2u1(_cfcmsa)
28862306a36Sopenharmony_ciI_u1u2(_ctc1)
28962306a36Sopenharmony_ciI_u2u1(_ctcmsa)
29062306a36Sopenharmony_ciI_u1u2(_ddivu)
29162306a36Sopenharmony_ciI_u3u1u2(_ddivu_r6)
29262306a36Sopenharmony_ciI_u1u2u3(_dmfc0)
29362306a36Sopenharmony_ciI_u3u1u2(_dmodu)
29462306a36Sopenharmony_ciI_u1u2u3(_dmtc0)
29562306a36Sopenharmony_ciI_u1u2(_dmultu)
29662306a36Sopenharmony_ciI_u3u1u2(_dmulu)
29762306a36Sopenharmony_ciI_u2u1s3(_daddiu)
29862306a36Sopenharmony_ciI_u3u1u2(_daddu)
29962306a36Sopenharmony_ciI_u1(_di);
30062306a36Sopenharmony_ciI_u1u2(_divu)
30162306a36Sopenharmony_ciI_u3u1u2(_divu_r6)
30262306a36Sopenharmony_ciI_u2u1(_dsbh);
30362306a36Sopenharmony_ciI_u2u1(_dshd);
30462306a36Sopenharmony_ciI_u2u1u3(_dsll)
30562306a36Sopenharmony_ciI_u2u1u3(_dsll32)
30662306a36Sopenharmony_ciI_u3u2u1(_dsllv)
30762306a36Sopenharmony_ciI_u2u1u3(_dsra)
30862306a36Sopenharmony_ciI_u2u1u3(_dsra32)
30962306a36Sopenharmony_ciI_u3u2u1(_dsrav)
31062306a36Sopenharmony_ciI_u2u1u3(_dsrl)
31162306a36Sopenharmony_ciI_u2u1u3(_dsrl32)
31262306a36Sopenharmony_ciI_u3u2u1(_dsrlv)
31362306a36Sopenharmony_ciI_u2u1u3(_drotr)
31462306a36Sopenharmony_ciI_u2u1u3(_drotr32)
31562306a36Sopenharmony_ciI_u3u1u2(_dsubu)
31662306a36Sopenharmony_ciI_0(_eret)
31762306a36Sopenharmony_ciI_u2u1msbdu3(_ext)
31862306a36Sopenharmony_ciI_u2u1msbu3(_ins)
31962306a36Sopenharmony_ciI_u1(_j)
32062306a36Sopenharmony_ciI_u1(_jal)
32162306a36Sopenharmony_ciI_u2u1(_jalr)
32262306a36Sopenharmony_ciI_u1(_jr)
32362306a36Sopenharmony_ciI_u2s3u1(_lb)
32462306a36Sopenharmony_ciI_u2s3u1(_lbu)
32562306a36Sopenharmony_ciI_u2s3u1(_ld)
32662306a36Sopenharmony_ciI_u2s3u1(_lh)
32762306a36Sopenharmony_ciI_u2s3u1(_lhu)
32862306a36Sopenharmony_ciI_u2s3u1(_ll)
32962306a36Sopenharmony_ciI_u2s3u1(_lld)
33062306a36Sopenharmony_ciI_u1s2(_lui)
33162306a36Sopenharmony_ciI_u2s3u1(_lw)
33262306a36Sopenharmony_ciI_u2s3u1(_lwu)
33362306a36Sopenharmony_ciI_u1u2u3(_mfc0)
33462306a36Sopenharmony_ciI_u1u2u3(_mfhc0)
33562306a36Sopenharmony_ciI_u3u1u2(_modu)
33662306a36Sopenharmony_ciI_u3u1u2(_movn)
33762306a36Sopenharmony_ciI_u3u1u2(_movz)
33862306a36Sopenharmony_ciI_u1(_mfhi)
33962306a36Sopenharmony_ciI_u1(_mflo)
34062306a36Sopenharmony_ciI_u1u2u3(_mtc0)
34162306a36Sopenharmony_ciI_u1u2u3(_mthc0)
34262306a36Sopenharmony_ciI_u1(_mthi)
34362306a36Sopenharmony_ciI_u1(_mtlo)
34462306a36Sopenharmony_ciI_u3u1u2(_mul)
34562306a36Sopenharmony_ciI_u1u2(_multu)
34662306a36Sopenharmony_ciI_u3u1u2(_mulu)
34762306a36Sopenharmony_ciI_u3u1u2(_muhu)
34862306a36Sopenharmony_ciI_u3u1u2(_nor)
34962306a36Sopenharmony_ciI_u3u1u2(_or)
35062306a36Sopenharmony_ciI_u2u1u3(_ori)
35162306a36Sopenharmony_ciI_0(_rfe)
35262306a36Sopenharmony_ciI_u2s3u1(_sb)
35362306a36Sopenharmony_ciI_u2s3u1(_sc)
35462306a36Sopenharmony_ciI_u2s3u1(_scd)
35562306a36Sopenharmony_ciI_u2s3u1(_sd)
35662306a36Sopenharmony_ciI_u3u1u2(_seleqz)
35762306a36Sopenharmony_ciI_u3u1u2(_selnez)
35862306a36Sopenharmony_ciI_u2s3u1(_sh)
35962306a36Sopenharmony_ciI_u2u1u3(_sll)
36062306a36Sopenharmony_ciI_u3u2u1(_sllv)
36162306a36Sopenharmony_ciI_s3s1s2(_slt)
36262306a36Sopenharmony_ciI_u2u1s3(_slti)
36362306a36Sopenharmony_ciI_u2u1s3(_sltiu)
36462306a36Sopenharmony_ciI_u3u1u2(_sltu)
36562306a36Sopenharmony_ciI_u2u1u3(_sra)
36662306a36Sopenharmony_ciI_u3u2u1(_srav)
36762306a36Sopenharmony_ciI_u2u1u3(_srl)
36862306a36Sopenharmony_ciI_u3u2u1(_srlv)
36962306a36Sopenharmony_ciI_u2u1u3(_rotr)
37062306a36Sopenharmony_ciI_u3u1u2(_subu)
37162306a36Sopenharmony_ciI_u2s3u1(_sw)
37262306a36Sopenharmony_ciI_u1(_sync)
37362306a36Sopenharmony_ciI_0(_tlbp)
37462306a36Sopenharmony_ciI_0(_tlbr)
37562306a36Sopenharmony_ciI_0(_tlbwi)
37662306a36Sopenharmony_ciI_0(_tlbwr)
37762306a36Sopenharmony_ciI_u1(_wait);
37862306a36Sopenharmony_ciI_u2u1(_wsbh)
37962306a36Sopenharmony_ciI_u3u1u2(_xor)
38062306a36Sopenharmony_ciI_u2u1u3(_xori)
38162306a36Sopenharmony_ciI_u2u1(_yield)
38262306a36Sopenharmony_ciI_u2u1msbu3(_dins);
38362306a36Sopenharmony_ciI_u2u1msb32u3(_dinsm);
38462306a36Sopenharmony_ciI_u2u1msb32msb3(_dinsu);
38562306a36Sopenharmony_ciI_u1(_syscall);
38662306a36Sopenharmony_ciI_u1u2s3(_bbit0);
38762306a36Sopenharmony_ciI_u1u2s3(_bbit1);
38862306a36Sopenharmony_ciI_u3u1u2(_lwx)
38962306a36Sopenharmony_ciI_u3u1u2(_ldx)
39062306a36Sopenharmony_ciI_u1u2(_ldpte)
39162306a36Sopenharmony_ciI_u2u1u3(_lddir)
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci#ifdef CONFIG_CPU_CAVIUM_OCTEON
39462306a36Sopenharmony_ci#include <asm/octeon/octeon.h>
39562306a36Sopenharmony_civoid uasm_i_pref(u32 **buf, unsigned int a, signed int b,
39662306a36Sopenharmony_ci			    unsigned int c)
39762306a36Sopenharmony_ci{
39862306a36Sopenharmony_ci	if (OCTEON_IS_MODEL(OCTEON_CN6XXX) && a <= 24 && a != 5)
39962306a36Sopenharmony_ci		/*
40062306a36Sopenharmony_ci		 * As per erratum Core-14449, replace prefetches 0-4,
40162306a36Sopenharmony_ci		 * 6-24 with 'pref 28'.
40262306a36Sopenharmony_ci		 */
40362306a36Sopenharmony_ci		build_insn(buf, insn_pref, c, 28, b);
40462306a36Sopenharmony_ci	else
40562306a36Sopenharmony_ci		build_insn(buf, insn_pref, c, a, b);
40662306a36Sopenharmony_ci}
40762306a36Sopenharmony_ciUASM_EXPORT_SYMBOL(uasm_i_pref);
40862306a36Sopenharmony_ci#else
40962306a36Sopenharmony_ciI_u2s3u1(_pref)
41062306a36Sopenharmony_ci#endif
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci/* Handle labels. */
41362306a36Sopenharmony_civoid uasm_build_label(struct uasm_label **lab, u32 *addr, int lid)
41462306a36Sopenharmony_ci{
41562306a36Sopenharmony_ci	(*lab)->addr = addr;
41662306a36Sopenharmony_ci	(*lab)->lab = lid;
41762306a36Sopenharmony_ci	(*lab)++;
41862306a36Sopenharmony_ci}
41962306a36Sopenharmony_ciUASM_EXPORT_SYMBOL(uasm_build_label);
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ciint uasm_in_compat_space_p(long addr)
42262306a36Sopenharmony_ci{
42362306a36Sopenharmony_ci	/* Is this address in 32bit compat space? */
42462306a36Sopenharmony_ci	return addr == (int)addr;
42562306a36Sopenharmony_ci}
42662306a36Sopenharmony_ciUASM_EXPORT_SYMBOL(uasm_in_compat_space_p);
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_cistatic int uasm_rel_highest(long val)
42962306a36Sopenharmony_ci{
43062306a36Sopenharmony_ci#ifdef CONFIG_64BIT
43162306a36Sopenharmony_ci	return ((((val + 0x800080008000L) >> 48) & 0xffff) ^ 0x8000) - 0x8000;
43262306a36Sopenharmony_ci#else
43362306a36Sopenharmony_ci	return 0;
43462306a36Sopenharmony_ci#endif
43562306a36Sopenharmony_ci}
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_cistatic int uasm_rel_higher(long val)
43862306a36Sopenharmony_ci{
43962306a36Sopenharmony_ci#ifdef CONFIG_64BIT
44062306a36Sopenharmony_ci	return ((((val + 0x80008000L) >> 32) & 0xffff) ^ 0x8000) - 0x8000;
44162306a36Sopenharmony_ci#else
44262306a36Sopenharmony_ci	return 0;
44362306a36Sopenharmony_ci#endif
44462306a36Sopenharmony_ci}
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ciint uasm_rel_hi(long val)
44762306a36Sopenharmony_ci{
44862306a36Sopenharmony_ci	return ((((val + 0x8000L) >> 16) & 0xffff) ^ 0x8000) - 0x8000;
44962306a36Sopenharmony_ci}
45062306a36Sopenharmony_ciUASM_EXPORT_SYMBOL(uasm_rel_hi);
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ciint uasm_rel_lo(long val)
45362306a36Sopenharmony_ci{
45462306a36Sopenharmony_ci	return ((val & 0xffff) ^ 0x8000) - 0x8000;
45562306a36Sopenharmony_ci}
45662306a36Sopenharmony_ciUASM_EXPORT_SYMBOL(uasm_rel_lo);
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_civoid UASM_i_LA_mostly(u32 **buf, unsigned int rs, long addr)
45962306a36Sopenharmony_ci{
46062306a36Sopenharmony_ci	if (!uasm_in_compat_space_p(addr)) {
46162306a36Sopenharmony_ci		uasm_i_lui(buf, rs, uasm_rel_highest(addr));
46262306a36Sopenharmony_ci		if (uasm_rel_higher(addr))
46362306a36Sopenharmony_ci			uasm_i_daddiu(buf, rs, rs, uasm_rel_higher(addr));
46462306a36Sopenharmony_ci		if (uasm_rel_hi(addr)) {
46562306a36Sopenharmony_ci			uasm_i_dsll(buf, rs, rs, 16);
46662306a36Sopenharmony_ci			uasm_i_daddiu(buf, rs, rs,
46762306a36Sopenharmony_ci					uasm_rel_hi(addr));
46862306a36Sopenharmony_ci			uasm_i_dsll(buf, rs, rs, 16);
46962306a36Sopenharmony_ci		} else
47062306a36Sopenharmony_ci			uasm_i_dsll32(buf, rs, rs, 0);
47162306a36Sopenharmony_ci	} else
47262306a36Sopenharmony_ci		uasm_i_lui(buf, rs, uasm_rel_hi(addr));
47362306a36Sopenharmony_ci}
47462306a36Sopenharmony_ciUASM_EXPORT_SYMBOL(UASM_i_LA_mostly);
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_civoid UASM_i_LA(u32 **buf, unsigned int rs, long addr)
47762306a36Sopenharmony_ci{
47862306a36Sopenharmony_ci	UASM_i_LA_mostly(buf, rs, addr);
47962306a36Sopenharmony_ci	if (uasm_rel_lo(addr)) {
48062306a36Sopenharmony_ci		if (!uasm_in_compat_space_p(addr))
48162306a36Sopenharmony_ci			uasm_i_daddiu(buf, rs, rs,
48262306a36Sopenharmony_ci					uasm_rel_lo(addr));
48362306a36Sopenharmony_ci		else
48462306a36Sopenharmony_ci			uasm_i_addiu(buf, rs, rs,
48562306a36Sopenharmony_ci					uasm_rel_lo(addr));
48662306a36Sopenharmony_ci	}
48762306a36Sopenharmony_ci}
48862306a36Sopenharmony_ciUASM_EXPORT_SYMBOL(UASM_i_LA);
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci/* Handle relocations. */
49162306a36Sopenharmony_civoid uasm_r_mips_pc16(struct uasm_reloc **rel, u32 *addr, int lid)
49262306a36Sopenharmony_ci{
49362306a36Sopenharmony_ci	(*rel)->addr = addr;
49462306a36Sopenharmony_ci	(*rel)->type = R_MIPS_PC16;
49562306a36Sopenharmony_ci	(*rel)->lab = lid;
49662306a36Sopenharmony_ci	(*rel)++;
49762306a36Sopenharmony_ci}
49862306a36Sopenharmony_ciUASM_EXPORT_SYMBOL(uasm_r_mips_pc16);
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_cistatic inline void __resolve_relocs(struct uasm_reloc *rel,
50162306a36Sopenharmony_ci				    struct uasm_label *lab);
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_civoid uasm_resolve_relocs(struct uasm_reloc *rel,
50462306a36Sopenharmony_ci				  struct uasm_label *lab)
50562306a36Sopenharmony_ci{
50662306a36Sopenharmony_ci	struct uasm_label *l;
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci	for (; rel->lab != UASM_LABEL_INVALID; rel++)
50962306a36Sopenharmony_ci		for (l = lab; l->lab != UASM_LABEL_INVALID; l++)
51062306a36Sopenharmony_ci			if (rel->lab == l->lab)
51162306a36Sopenharmony_ci				__resolve_relocs(rel, l);
51262306a36Sopenharmony_ci}
51362306a36Sopenharmony_ciUASM_EXPORT_SYMBOL(uasm_resolve_relocs);
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_civoid uasm_move_relocs(struct uasm_reloc *rel, u32 *first, u32 *end,
51662306a36Sopenharmony_ci			       long off)
51762306a36Sopenharmony_ci{
51862306a36Sopenharmony_ci	for (; rel->lab != UASM_LABEL_INVALID; rel++)
51962306a36Sopenharmony_ci		if (rel->addr >= first && rel->addr < end)
52062306a36Sopenharmony_ci			rel->addr += off;
52162306a36Sopenharmony_ci}
52262306a36Sopenharmony_ciUASM_EXPORT_SYMBOL(uasm_move_relocs);
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_civoid uasm_move_labels(struct uasm_label *lab, u32 *first, u32 *end,
52562306a36Sopenharmony_ci			       long off)
52662306a36Sopenharmony_ci{
52762306a36Sopenharmony_ci	for (; lab->lab != UASM_LABEL_INVALID; lab++)
52862306a36Sopenharmony_ci		if (lab->addr >= first && lab->addr < end)
52962306a36Sopenharmony_ci			lab->addr += off;
53062306a36Sopenharmony_ci}
53162306a36Sopenharmony_ciUASM_EXPORT_SYMBOL(uasm_move_labels);
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_civoid uasm_copy_handler(struct uasm_reloc *rel, struct uasm_label *lab,
53462306a36Sopenharmony_ci				u32 *first, u32 *end, u32 *target)
53562306a36Sopenharmony_ci{
53662306a36Sopenharmony_ci	long off = (long)(target - first);
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci	memcpy(target, first, (end - first) * sizeof(u32));
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci	uasm_move_relocs(rel, first, end, off);
54162306a36Sopenharmony_ci	uasm_move_labels(lab, first, end, off);
54262306a36Sopenharmony_ci}
54362306a36Sopenharmony_ciUASM_EXPORT_SYMBOL(uasm_copy_handler);
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ciint uasm_insn_has_bdelay(struct uasm_reloc *rel, u32 *addr)
54662306a36Sopenharmony_ci{
54762306a36Sopenharmony_ci	for (; rel->lab != UASM_LABEL_INVALID; rel++) {
54862306a36Sopenharmony_ci		if (rel->addr == addr
54962306a36Sopenharmony_ci		    && (rel->type == R_MIPS_PC16
55062306a36Sopenharmony_ci			|| rel->type == R_MIPS_26))
55162306a36Sopenharmony_ci			return 1;
55262306a36Sopenharmony_ci	}
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci	return 0;
55562306a36Sopenharmony_ci}
55662306a36Sopenharmony_ciUASM_EXPORT_SYMBOL(uasm_insn_has_bdelay);
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ci/* Convenience functions for labeled branches. */
55962306a36Sopenharmony_civoid uasm_il_bltz(u32 **p, struct uasm_reloc **r, unsigned int reg,
56062306a36Sopenharmony_ci			   int lid)
56162306a36Sopenharmony_ci{
56262306a36Sopenharmony_ci	uasm_r_mips_pc16(r, *p, lid);
56362306a36Sopenharmony_ci	uasm_i_bltz(p, reg, 0);
56462306a36Sopenharmony_ci}
56562306a36Sopenharmony_ciUASM_EXPORT_SYMBOL(uasm_il_bltz);
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_civoid uasm_il_b(u32 **p, struct uasm_reloc **r, int lid)
56862306a36Sopenharmony_ci{
56962306a36Sopenharmony_ci	uasm_r_mips_pc16(r, *p, lid);
57062306a36Sopenharmony_ci	uasm_i_b(p, 0);
57162306a36Sopenharmony_ci}
57262306a36Sopenharmony_ciUASM_EXPORT_SYMBOL(uasm_il_b);
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_civoid uasm_il_beq(u32 **p, struct uasm_reloc **r, unsigned int r1,
57562306a36Sopenharmony_ci			  unsigned int r2, int lid)
57662306a36Sopenharmony_ci{
57762306a36Sopenharmony_ci	uasm_r_mips_pc16(r, *p, lid);
57862306a36Sopenharmony_ci	uasm_i_beq(p, r1, r2, 0);
57962306a36Sopenharmony_ci}
58062306a36Sopenharmony_ciUASM_EXPORT_SYMBOL(uasm_il_beq);
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_civoid uasm_il_beqz(u32 **p, struct uasm_reloc **r, unsigned int reg,
58362306a36Sopenharmony_ci			   int lid)
58462306a36Sopenharmony_ci{
58562306a36Sopenharmony_ci	uasm_r_mips_pc16(r, *p, lid);
58662306a36Sopenharmony_ci	uasm_i_beqz(p, reg, 0);
58762306a36Sopenharmony_ci}
58862306a36Sopenharmony_ciUASM_EXPORT_SYMBOL(uasm_il_beqz);
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_civoid uasm_il_beqzl(u32 **p, struct uasm_reloc **r, unsigned int reg,
59162306a36Sopenharmony_ci			    int lid)
59262306a36Sopenharmony_ci{
59362306a36Sopenharmony_ci	uasm_r_mips_pc16(r, *p, lid);
59462306a36Sopenharmony_ci	uasm_i_beqzl(p, reg, 0);
59562306a36Sopenharmony_ci}
59662306a36Sopenharmony_ciUASM_EXPORT_SYMBOL(uasm_il_beqzl);
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_civoid uasm_il_bne(u32 **p, struct uasm_reloc **r, unsigned int reg1,
59962306a36Sopenharmony_ci			  unsigned int reg2, int lid)
60062306a36Sopenharmony_ci{
60162306a36Sopenharmony_ci	uasm_r_mips_pc16(r, *p, lid);
60262306a36Sopenharmony_ci	uasm_i_bne(p, reg1, reg2, 0);
60362306a36Sopenharmony_ci}
60462306a36Sopenharmony_ciUASM_EXPORT_SYMBOL(uasm_il_bne);
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_civoid uasm_il_bnez(u32 **p, struct uasm_reloc **r, unsigned int reg,
60762306a36Sopenharmony_ci			   int lid)
60862306a36Sopenharmony_ci{
60962306a36Sopenharmony_ci	uasm_r_mips_pc16(r, *p, lid);
61062306a36Sopenharmony_ci	uasm_i_bnez(p, reg, 0);
61162306a36Sopenharmony_ci}
61262306a36Sopenharmony_ciUASM_EXPORT_SYMBOL(uasm_il_bnez);
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_civoid uasm_il_bgezl(u32 **p, struct uasm_reloc **r, unsigned int reg,
61562306a36Sopenharmony_ci			    int lid)
61662306a36Sopenharmony_ci{
61762306a36Sopenharmony_ci	uasm_r_mips_pc16(r, *p, lid);
61862306a36Sopenharmony_ci	uasm_i_bgezl(p, reg, 0);
61962306a36Sopenharmony_ci}
62062306a36Sopenharmony_ciUASM_EXPORT_SYMBOL(uasm_il_bgezl);
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_civoid uasm_il_bgez(u32 **p, struct uasm_reloc **r, unsigned int reg,
62362306a36Sopenharmony_ci			   int lid)
62462306a36Sopenharmony_ci{
62562306a36Sopenharmony_ci	uasm_r_mips_pc16(r, *p, lid);
62662306a36Sopenharmony_ci	uasm_i_bgez(p, reg, 0);
62762306a36Sopenharmony_ci}
62862306a36Sopenharmony_ciUASM_EXPORT_SYMBOL(uasm_il_bgez);
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_civoid uasm_il_bbit0(u32 **p, struct uasm_reloc **r, unsigned int reg,
63162306a36Sopenharmony_ci			    unsigned int bit, int lid)
63262306a36Sopenharmony_ci{
63362306a36Sopenharmony_ci	uasm_r_mips_pc16(r, *p, lid);
63462306a36Sopenharmony_ci	uasm_i_bbit0(p, reg, bit, 0);
63562306a36Sopenharmony_ci}
63662306a36Sopenharmony_ciUASM_EXPORT_SYMBOL(uasm_il_bbit0);
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_civoid uasm_il_bbit1(u32 **p, struct uasm_reloc **r, unsigned int reg,
63962306a36Sopenharmony_ci			    unsigned int bit, int lid)
64062306a36Sopenharmony_ci{
64162306a36Sopenharmony_ci	uasm_r_mips_pc16(r, *p, lid);
64262306a36Sopenharmony_ci	uasm_i_bbit1(p, reg, bit, 0);
64362306a36Sopenharmony_ci}
64462306a36Sopenharmony_ciUASM_EXPORT_SYMBOL(uasm_il_bbit1);
645