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