From: Ley Foon Tan Date: Thu, 6 Nov 2014 07:19:36 +0000 (+0800) Subject: nios2: Assembly macros and definitions X-Git-Url: https://git.stricted.de/?a=commitdiff_plain;h=39b505cb7929d272020a2c9c25f6e3cd7c112447;p=GitHub%2FLineageOS%2FG12%2Fandroid_kernel_amlogic_linux-4.9.git nios2: Assembly macros and definitions This patch add assembly macros and definitions used in the .S files across arch/nios2/ and together with asm-offsets.c. Signed-off-by: Ley Foon Tan --- diff --git a/arch/nios2/include/asm/asm-macros.h b/arch/nios2/include/asm/asm-macros.h new file mode 100644 index 000000000000..29fa2e4d7b00 --- /dev/null +++ b/arch/nios2/include/asm/asm-macros.h @@ -0,0 +1,309 @@ +/* + * Macro used to simplify coding multi-line assembler. + * Some of the bit test macro can simplify down to one line + * depending on the mask value. + * + * Copyright (C) 2004 Microtronix Datacom Ltd. + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + */ +#ifndef _ASM_NIOS2_ASMMACROS_H +#define _ASM_NIOS2_ASMMACROS_H +/* + * ANDs reg2 with mask and places the result in reg1. + * + * You cannnot use the same register for reg1 & reg2. + */ + +.macro ANDI32 reg1, reg2, mask +.if \mask & 0xffff + .if \mask & 0xffff0000 + movhi \reg1, %hi(\mask) + movui \reg1, %lo(\mask) + and \reg1, \reg1, \reg2 + .else + andi \reg1, \reg2, %lo(\mask) + .endif +.else + andhi \reg1, \reg2, %hi(\mask) +.endif +.endm + +/* + * ORs reg2 with mask and places the result in reg1. + * + * It is safe to use the same register for reg1 & reg2. + */ + +.macro ORI32 reg1, reg2, mask +.if \mask & 0xffff + .if \mask & 0xffff0000 + orhi \reg1, \reg2, %hi(\mask) + ori \reg1, \reg2, %lo(\mask) + .else + ori \reg1, \reg2, %lo(\mask) + .endif +.else + orhi \reg1, \reg2, %hi(\mask) +.endif +.endm + +/* + * XORs reg2 with mask and places the result in reg1. + * + * It is safe to use the same register for reg1 & reg2. + */ + +.macro XORI32 reg1, reg2, mask +.if \mask & 0xffff + .if \mask & 0xffff0000 + xorhi \reg1, \reg2, %hi(\mask) + xori \reg1, \reg1, %lo(\mask) + .else + xori \reg1, \reg2, %lo(\mask) + .endif +.else + xorhi \reg1, \reg2, %hi(\mask) +.endif +.endm + +/* + * This is a support macro for BTBZ & BTBNZ. It checks + * the bit to make sure it is valid 32 value. + * + * It is safe to use the same register for reg1 & reg2. + */ + +.macro BT reg1, reg2, bit +.if \bit > 31 + .err +.else + .if \bit < 16 + andi \reg1, \reg2, (1 << \bit) + .else + andhi \reg1, \reg2, (1 << (\bit - 16)) + .endif +.endif +.endm + +/* + * Tests the bit in reg2 and branches to label if the + * bit is zero. The result of the bit test is stored in reg1. + * + * It is safe to use the same register for reg1 & reg2. + */ + +.macro BTBZ reg1, reg2, bit, label + BT \reg1, \reg2, \bit + beq \reg1, r0, \label +.endm + +/* + * Tests the bit in reg2 and branches to label if the + * bit is non-zero. The result of the bit test is stored in reg1. + * + * It is safe to use the same register for reg1 & reg2. + */ + +.macro BTBNZ reg1, reg2, bit, label + BT \reg1, \reg2, \bit + bne \reg1, r0, \label +.endm + +/* + * Tests the bit in reg2 and then compliments the bit in reg2. + * The result of the bit test is stored in reg1. + * + * It is NOT safe to use the same register for reg1 & reg2. + */ + +.macro BTC reg1, reg2, bit +.if \bit > 31 + .err +.else + .if \bit < 16 + andi \reg1, \reg2, (1 << \bit) + xori \reg2, \reg2, (1 << \bit) + .else + andhi \reg1, \reg2, (1 << (\bit - 16)) + xorhi \reg2, \reg2, (1 << (\bit - 16)) + .endif +.endif +.endm + +/* + * Tests the bit in reg2 and then sets the bit in reg2. + * The result of the bit test is stored in reg1. + * + * It is NOT safe to use the same register for reg1 & reg2. + */ + +.macro BTS reg1, reg2, bit +.if \bit > 31 + .err +.else + .if \bit < 16 + andi \reg1, \reg2, (1 << \bit) + ori \reg2, \reg2, (1 << \bit) + .else + andhi \reg1, \reg2, (1 << (\bit - 16)) + orhi \reg2, \reg2, (1 << (\bit - 16)) + .endif +.endif +.endm + +/* + * Tests the bit in reg2 and then resets the bit in reg2. + * The result of the bit test is stored in reg1. + * + * It is NOT safe to use the same register for reg1 & reg2. + */ + +.macro BTR reg1, reg2, bit +.if \bit > 31 + .err +.else + .if \bit < 16 + andi \reg1, \reg2, (1 << \bit) + andi \reg2, \reg2, %lo(~(1 << \bit)) + .else + andhi \reg1, \reg2, (1 << (\bit - 16)) + andhi \reg2, \reg2, %lo(~(1 << (\bit - 16))) + .endif +.endif +.endm + +/* + * Tests the bit in reg2 and then compliments the bit in reg2. + * The result of the bit test is stored in reg1. If the + * original bit was zero it branches to label. + * + * It is NOT safe to use the same register for reg1 & reg2. + */ + +.macro BTCBZ reg1, reg2, bit, label + BTC \reg1, \reg2, \bit + beq \reg1, r0, \label +.endm + +/* + * Tests the bit in reg2 and then compliments the bit in reg2. + * The result of the bit test is stored in reg1. If the + * original bit was non-zero it branches to label. + * + * It is NOT safe to use the same register for reg1 & reg2. + */ + +.macro BTCBNZ reg1, reg2, bit, label + BTC \reg1, \reg2, \bit + bne \reg1, r0, \label +.endm + +/* + * Tests the bit in reg2 and then sets the bit in reg2. + * The result of the bit test is stored in reg1. If the + * original bit was zero it branches to label. + * + * It is NOT safe to use the same register for reg1 & reg2. + */ + +.macro BTSBZ reg1, reg2, bit, label + BTS \reg1, \reg2, \bit + beq \reg1, r0, \label +.endm + +/* + * Tests the bit in reg2 and then sets the bit in reg2. + * The result of the bit test is stored in reg1. If the + * original bit was non-zero it branches to label. + * + * It is NOT safe to use the same register for reg1 & reg2. + */ + +.macro BTSBNZ reg1, reg2, bit, label + BTS \reg1, \reg2, \bit + bne \reg1, r0, \label +.endm + +/* + * Tests the bit in reg2 and then resets the bit in reg2. + * The result of the bit test is stored in reg1. If the + * original bit was zero it branches to label. + * + * It is NOT safe to use the same register for reg1 & reg2. + */ + +.macro BTRBZ reg1, reg2, bit, label + BTR \reg1, \reg2, \bit + bne \reg1, r0, \label +.endm + +/* + * Tests the bit in reg2 and then resets the bit in reg2. + * The result of the bit test is stored in reg1. If the + * original bit was non-zero it branches to label. + * + * It is NOT safe to use the same register for reg1 & reg2. + */ + +.macro BTRBNZ reg1, reg2, bit, label + BTR \reg1, \reg2, \bit + bne \reg1, r0, \label +.endm + +/* + * Tests the bits in mask against reg2 stores the result in reg1. + * If the all the bits in the mask are zero it branches to label. + * + * It is safe to use the same register for reg1 & reg2. + */ + +.macro TSTBZ reg1, reg2, mask, label + ANDI32 \reg1, \reg2, \mask + beq \reg1, r0, \label +.endm + +/* + * Tests the bits in mask against reg2 stores the result in reg1. + * If the any of the bits in the mask are 1 it branches to label. + * + * It is safe to use the same register for reg1 & reg2. + */ + +.macro TSTBNZ reg1, reg2, mask, label + ANDI32 \reg1, \reg2, \mask + bne \reg1, r0, \label +.endm + +/* + * Pushes reg onto the stack. + */ + +.macro PUSH reg + addi sp, sp, -4 + stw \reg, 0(sp) +.endm + +/* + * Pops the top of the stack into reg. + */ + +.macro POP reg + ldw \reg, 0(sp) + addi sp, sp, 4 +.endm + + +#endif /* _ASM_NIOS2_ASMMACROS_H */ diff --git a/arch/nios2/include/asm/asm-offsets.h b/arch/nios2/include/asm/asm-offsets.h new file mode 100644 index 000000000000..5b9f5e04a058 --- /dev/null +++ b/arch/nios2/include/asm/asm-offsets.h @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2010 Tobias Klauser + * Copyright (C) 2009 Thomas Chou + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#include diff --git a/arch/nios2/kernel/asm-offsets.c b/arch/nios2/kernel/asm-offsets.c new file mode 100644 index 000000000000..3852f5c970aa --- /dev/null +++ b/arch/nios2/kernel/asm-offsets.c @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2011 Tobias Klauser + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include +#include +#include +#include +#include + +int main(void) +{ + /* struct task_struct */ + OFFSET(TASK_THREAD, task_struct, thread); + BLANK(); + + /* struct thread_struct */ + OFFSET(THREAD_KSP, thread_struct, ksp); + OFFSET(THREAD_KPSR, thread_struct, kpsr); + BLANK(); + + /* struct pt_regs */ + OFFSET(PT_ORIG_R2, pt_regs, orig_r2); + OFFSET(PT_ORIG_R7, pt_regs, orig_r7); + + OFFSET(PT_R1, pt_regs, r1); + OFFSET(PT_R2, pt_regs, r2); + OFFSET(PT_R3, pt_regs, r3); + OFFSET(PT_R4, pt_regs, r4); + OFFSET(PT_R5, pt_regs, r5); + OFFSET(PT_R6, pt_regs, r6); + OFFSET(PT_R7, pt_regs, r7); + OFFSET(PT_R8, pt_regs, r8); + OFFSET(PT_R9, pt_regs, r9); + OFFSET(PT_R10, pt_regs, r10); + OFFSET(PT_R11, pt_regs, r11); + OFFSET(PT_R12, pt_regs, r12); + OFFSET(PT_R13, pt_regs, r13); + OFFSET(PT_R14, pt_regs, r14); + OFFSET(PT_R15, pt_regs, r15); + OFFSET(PT_EA, pt_regs, ea); + OFFSET(PT_RA, pt_regs, ra); + OFFSET(PT_FP, pt_regs, fp); + OFFSET(PT_SP, pt_regs, sp); + OFFSET(PT_GP, pt_regs, gp); + OFFSET(PT_ESTATUS, pt_regs, estatus); + DEFINE(PT_REGS_SIZE, sizeof(struct pt_regs)); + BLANK(); + + /* struct switch_stack */ + OFFSET(SW_R16, switch_stack, r16); + OFFSET(SW_R17, switch_stack, r17); + OFFSET(SW_R18, switch_stack, r18); + OFFSET(SW_R19, switch_stack, r19); + OFFSET(SW_R20, switch_stack, r20); + OFFSET(SW_R21, switch_stack, r21); + OFFSET(SW_R22, switch_stack, r22); + OFFSET(SW_R23, switch_stack, r23); + OFFSET(SW_FP, switch_stack, fp); + OFFSET(SW_GP, switch_stack, gp); + OFFSET(SW_RA, switch_stack, ra); + DEFINE(SWITCH_STACK_SIZE, sizeof(struct switch_stack)); + BLANK(); + + /* struct thread_info */ + OFFSET(TI_TASK, thread_info, task); + OFFSET(TI_FLAGS, thread_info, flags); + OFFSET(TI_PREEMPT_COUNT, thread_info, preempt_count); + BLANK(); + + return 0; +}