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 <lftan@altera.com>
This commit is contained in:
Ley Foon Tan 2014-11-06 15:19:36 +08:00
parent 00f634bc52
commit 39b505cb79
3 changed files with 417 additions and 0 deletions

View File

@ -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 */

View File

@ -0,0 +1,20 @@
/*
* Copyright (C) 2010 Tobias Klauser <tklauser@distanz.ch>
* Copyright (C) 2009 Thomas Chou <thomas@wytron.com.tw>
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
#include <generated/asm-offsets.h>

View File

@ -0,0 +1,88 @@
/*
* Copyright (C) 2011 Tobias Klauser <tklauser@distanz.ch>
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
#include <linux/stddef.h>
#include <linux/sched.h>
#include <linux/kernel_stat.h>
#include <linux/ptrace.h>
#include <linux/hardirq.h>
#include <linux/thread_info.h>
#include <linux/kbuild.h>
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;
}