1/* SPDX-License-Identifier: BSD-2-Clause */
2/*
3 * Copyright (c) 2015, Linaro Limited
4 */
5
6	.altmacro
7
8	/*
9	 * This helper macro concatenates instr_prefix, instr_suffix, to
10	 * create a ldp/stp instruction. It also selects register name x/w
11	 * based on reg_bytes.
12	 */
13	.macro __do_dregs instr_prefix, instr_suffix, reg_bytes, base_reg, \
14			base_offs, reg0, reg1
15		.if \reg_bytes == 8
16			\instr_prefix\instr_suffix \
17				x\reg0, x\reg1, [\base_reg, #\base_offs]
18		.else
19			\instr_prefix\instr_suffix \
20				w\reg0, w\reg1, [\base_reg, #\base_offs]
21		.endif
22	.endm
23
24	/*
25	 * This helper macro concatenates instr_prefix, instr_suffix, to
26	 * create a ldr/str instruction. It also selects register name x/w
27	 * based on reg_bytes.
28	 */
29	.macro __do_reg instr_prefix, instr_suffix, reg_bytes, base_reg, \
30			base_offs, reg
31		.if \reg_bytes == 8
32			\instr_prefix\instr_suffix \
33				x\reg, [\base_reg, #\base_offs]
34		.else
35			\instr_prefix\instr_suffix \
36				w\reg, [\base_reg, #\base_offs]
37		.endif
38	.endm
39
40	/*
41	 * This helper macro uses recursion to create a loop which will
42	 * start with generating instructions for register pairs and if
43	 * it's an odd number of registers end with a single load/store.
44	 */
45	.macro _do_regs instr_prefix, reg_bytes, base_reg, base_offs, \
46			from_regnum, to_regnum
47		.if (\to_regnum - \from_regnum + 1) >= 2
48			__do_dregs \instr_prefix, p, \reg_bytes, \base_reg, \
49				\base_offs, \from_regnum, %(\from_regnum + 1)
50		.else
51			__do_reg \instr_prefix, r, \reg_bytes, \base_reg, \
52				\base_offs, \from_regnum
53		.endif
54		.if (\to_regnum - \from_regnum + 1) > 2
55			_do_regs \instr_prefix, \reg_bytes, \base_reg, \
56				%(\base_offs + 2 * \reg_bytes), \
57				%(\from_regnum + 2), \to_regnum
58		.endif
59	.endm
60
61	/*
62	 * Stores registers x[from_regnum]..x[to_regnum] at
63	 * [base_reg, #base_offs]
64	 */
65	.macro store_xregs base_reg, base_offs, from_regnum, to_regnum
66		_do_regs st 8 \base_reg, \base_offs, \from_regnum, \to_regnum
67	.endm
68
69	/*
70	 * Stores registers w[from_regnum]..w[to_regnum] at
71	 * [base_reg, #base_offs]
72	 */
73	.macro store_wregs base_reg, base_offs, from_regnum, to_regnum
74		_do_regs st 4 \base_reg, \base_offs, \from_regnum, \to_regnum
75	.endm
76
77	/*
78	 * Loads registers x[from_regnum]..x[to_regnum] at
79	 * [base_reg, #base_offs]
80	 */
81	.macro load_xregs base_reg, base_offs, from_regnum, to_regnum
82		_do_regs ld 8 \base_reg, \base_offs, \from_regnum, \to_regnum
83	.endm
84
85	/*
86	 * Loads registers w[from_regnum]..w[to_regnum] at
87	 * [base_reg, #base_offs]
88	 */
89	.macro load_wregs base_reg, base_offs, from_regnum, to_regnum
90		_do_regs ld 4 \base_reg, \base_offs, \from_regnum, \to_regnum
91	.endm
92
93
94	/* Push register pair on stack */
95	.macro  push, r1, r2
96	stp     \r1, \r2, [sp, #-16]!
97	.endm
98
99	/* Pop register pair from stack */
100	.macro  pop, r1, r2
101	ldp     \r1, \r2, [sp], #16
102	.endm
103
104	.macro mov_imm _reg, _val
105	.if (((\_val) >> 31) == 0 || ((\_val) >> 31) == 0x1ffffffff)
106		movz    \_reg, :abs_g1_s:\_val
107	.else
108		.if (((\_val) >> 47) == 0 || ((\_val) >> 47) == 0x1ffff)
109			movz    \_reg, :abs_g2_s:\_val
110		.else
111			movz    \_reg, :abs_g3:\_val
112			movk    \_reg, :abs_g2_nc:\_val
113		.endif
114		movk    \_reg, :abs_g1_nc:\_val
115	.endif
116		movk    \_reg, :abs_g0_nc:\_val
117	.endm
118
119	/*
120	 * Load address of <sym> into <reg>, <sym> being in the range
121	 * +/- 4GB of the PC (note that 'adr reg, sym' is limited to +/- 1MB).
122	 */
123	.macro adr_l reg, sym
124	adrp	\reg, \sym
125	add	\reg, \reg, :lo12:\sym
126	.endm
127