| /* SPDX-License-Identifier: GPL-2.0 */ |
| /* |
| * Copyright (C) 2020-2022 Loongson Technology Corporation Limited |
| */ |
| #ifndef _ASM_INST_H |
| #define _ASM_INST_H |
| |
| #include <linux/types.h> |
| #include <asm/asm.h> |
| |
| #define ADDR_IMMMASK_LU52ID 0xFFF0000000000000 |
| #define ADDR_IMMMASK_LU32ID 0x000FFFFF00000000 |
| #define ADDR_IMMMASK_ADDU16ID 0x00000000FFFF0000 |
| |
| #define ADDR_IMMSHIFT_LU52ID 52 |
| #define ADDR_IMMSHIFT_LU32ID 32 |
| #define ADDR_IMMSHIFT_ADDU16ID 16 |
| |
| #define ADDR_IMM(addr, INSN) ((addr & ADDR_IMMMASK_##INSN) >> ADDR_IMMSHIFT_##INSN) |
| |
| enum reg1i20_op { |
| lu12iw_op = 0x0a, |
| lu32id_op = 0x0b, |
| }; |
| |
| enum reg1i21_op { |
| beqz_op = 0x10, |
| bnez_op = 0x11, |
| }; |
| |
| enum reg2i12_op { |
| addiw_op = 0x0a, |
| addid_op = 0x0b, |
| lu52id_op = 0x0c, |
| ldb_op = 0xa0, |
| ldh_op = 0xa1, |
| ldw_op = 0xa2, |
| ldd_op = 0xa3, |
| stb_op = 0xa4, |
| sth_op = 0xa5, |
| stw_op = 0xa6, |
| std_op = 0xa7, |
| }; |
| |
| enum reg2i16_op { |
| jirl_op = 0x13, |
| beq_op = 0x16, |
| bne_op = 0x17, |
| blt_op = 0x18, |
| bge_op = 0x19, |
| bltu_op = 0x1a, |
| bgeu_op = 0x1b, |
| }; |
| |
| struct reg0i26_format { |
| unsigned int immediate_h : 10; |
| unsigned int immediate_l : 16; |
| unsigned int opcode : 6; |
| }; |
| |
| struct reg1i20_format { |
| unsigned int rd : 5; |
| unsigned int immediate : 20; |
| unsigned int opcode : 7; |
| }; |
| |
| struct reg1i21_format { |
| unsigned int immediate_h : 5; |
| unsigned int rj : 5; |
| unsigned int immediate_l : 16; |
| unsigned int opcode : 6; |
| }; |
| |
| struct reg2i12_format { |
| unsigned int rd : 5; |
| unsigned int rj : 5; |
| unsigned int immediate : 12; |
| unsigned int opcode : 10; |
| }; |
| |
| struct reg2i16_format { |
| unsigned int rd : 5; |
| unsigned int rj : 5; |
| unsigned int immediate : 16; |
| unsigned int opcode : 6; |
| }; |
| |
| union loongarch_instruction { |
| unsigned int word; |
| struct reg0i26_format reg0i26_format; |
| struct reg1i20_format reg1i20_format; |
| struct reg1i21_format reg1i21_format; |
| struct reg2i12_format reg2i12_format; |
| struct reg2i16_format reg2i16_format; |
| }; |
| |
| #define LOONGARCH_INSN_SIZE sizeof(union loongarch_instruction) |
| |
| enum loongarch_gpr { |
| LOONGARCH_GPR_ZERO = 0, |
| LOONGARCH_GPR_RA = 1, |
| LOONGARCH_GPR_TP = 2, |
| LOONGARCH_GPR_SP = 3, |
| LOONGARCH_GPR_A0 = 4, /* Reused as V0 for return value */ |
| LOONGARCH_GPR_A1, /* Reused as V1 for return value */ |
| LOONGARCH_GPR_A2, |
| LOONGARCH_GPR_A3, |
| LOONGARCH_GPR_A4, |
| LOONGARCH_GPR_A5, |
| LOONGARCH_GPR_A6, |
| LOONGARCH_GPR_A7, |
| LOONGARCH_GPR_T0 = 12, |
| LOONGARCH_GPR_T1, |
| LOONGARCH_GPR_T2, |
| LOONGARCH_GPR_T3, |
| LOONGARCH_GPR_T4, |
| LOONGARCH_GPR_T5, |
| LOONGARCH_GPR_T6, |
| LOONGARCH_GPR_T7, |
| LOONGARCH_GPR_T8, |
| LOONGARCH_GPR_FP = 22, |
| LOONGARCH_GPR_S0 = 23, |
| LOONGARCH_GPR_S1, |
| LOONGARCH_GPR_S2, |
| LOONGARCH_GPR_S3, |
| LOONGARCH_GPR_S4, |
| LOONGARCH_GPR_S5, |
| LOONGARCH_GPR_S6, |
| LOONGARCH_GPR_S7, |
| LOONGARCH_GPR_S8, |
| LOONGARCH_GPR_MAX |
| }; |
| |
| #define is_imm12_negative(val) is_imm_negative(val, 12) |
| |
| static inline bool is_imm_negative(unsigned long val, unsigned int bit) |
| { |
| return val & (1UL << (bit - 1)); |
| } |
| |
| static inline bool is_branch_ins(union loongarch_instruction *ip) |
| { |
| return ip->reg1i21_format.opcode >= beqz_op && |
| ip->reg1i21_format.opcode <= bgeu_op; |
| } |
| |
| static inline bool is_ra_save_ins(union loongarch_instruction *ip) |
| { |
| /* st.d $ra, $sp, offset */ |
| return ip->reg2i12_format.opcode == std_op && |
| ip->reg2i12_format.rj == LOONGARCH_GPR_SP && |
| ip->reg2i12_format.rd == LOONGARCH_GPR_RA && |
| !is_imm12_negative(ip->reg2i12_format.immediate); |
| } |
| |
| static inline bool is_stack_alloc_ins(union loongarch_instruction *ip) |
| { |
| /* addi.d $sp, $sp, -imm */ |
| return ip->reg2i12_format.opcode == addid_op && |
| ip->reg2i12_format.rj == LOONGARCH_GPR_SP && |
| ip->reg2i12_format.rd == LOONGARCH_GPR_SP && |
| is_imm12_negative(ip->reg2i12_format.immediate); |
| } |
| |
| u32 larch_insn_gen_lu32id(enum loongarch_gpr rd, int imm); |
| u32 larch_insn_gen_lu52id(enum loongarch_gpr rd, enum loongarch_gpr rj, int imm); |
| u32 larch_insn_gen_jirl(enum loongarch_gpr rd, enum loongarch_gpr rj, unsigned long pc, unsigned long dest); |
| |
| #endif /* _ASM_INST_H */ |