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