类似register uint32_t __regPriMask __ASM("primask");的代码分析

本文仅对 keil armcc 编译器有效,对于其他编译器未验证,不清楚。

代码:

#define __ASM            __asm   /*!< asm keyword for ARM Compiler */
#define __INLINE         __inline  /*!< inline keyword for ARM Compiler */
#define __STATIC_INLINE  static __inline

/** \brief Set Priority Mask
This function assigns the given value to the Priority Mask Register.
\param [in] priMask Priority Mask
*/
__STATIC_INLINE void __set_PRIMASK(uint32_t priMask)
{
   register uint32_t __regPriMask         __ASM("primask");
   __regPriMask = (priMask);
}

参见armcc.chm文件9.155 Named register variables一节。

9.155 Named register variables
The compiler enables you to access registers of an ARM architecture-based processor or coprocessor using named register variables.
Syntax register type var-name __asm(reg); Where:

type

  • is the type of the named register variable.
  • Any type of the same size as the register being named can be used in the declaration of a named register variable. The type can be a structure, but bitfield layout is sensitive to endianness.

var-name

  • is the name of the named register variable.

reg

  • is a character string denoting the name of a register on an ARM architecture-based processor, or for coprocessor registers, a string syntax that identifies the coprocessor and corresponds with how you intend to use the variable.
  • Registers available for use with named register variables on ARM architecture-based processors are shown in the following table.

其大致意思是:可以用register type var-name __asm(reg)这样的定义,来声明一个命名寄存器的变量,像使用变量一样操作他们;
type 是声明变量的类型;需要与寄存器大小一致,且注意大小端;
var-name 是声明变量的名称;
reg 是指定的ARM体系寄存器名称;

  • 能够声明为命名寄存器变量的寄存器表
    Table 9-19 Named registers available on ARM architecture-based processors
Register Character string for __asm Processors
APSR "apsr" All processors
CPSR "cpsr" All processors, apart from Cortex-M series processors.
BASEPRI "basepri" ARMv7-M processors
BASEPRI_MAX "basepri_max" ARMv7-M processors
CONTROL "control" ARMv6-M and ARMv7-M processors
DSP "dsp" ARMv6-M and ARMv7-M processors
EAPSR "eapsr" ARMv6-M and ARMv7-M processors
EPSR "epsr" ARMv6-M and ARMv7-M processors
FAULTMASK "faultmask" ARMv7-M processors
IAPSR "iapsr" ARMv6-M and ARMv7-M processors
IEPSR "iepsr" ARMv6-M and ARMv7-M processors
IPSR "ipsr" ARMv6-M and ARMv7-M processors
MSP "msp" ARMv6-M and ARMv7-M processors
PRIMASK "primask" ARMv6-M and ARMv7-M processors
PSP "psp" ARMv6-M and ARMv7-M processors
PSR "psr" ARMv6-M and ARMv7-M processors
r0 to r12 "r0" to "r12" All processors
r13 or sp "r13" or "sp" All processors
r14 or lr "r14" or "lr" All processors
r15 or pc "r15" or "pc" All processors
SPSR "spsr" All processors, apart from Cortex-M series processors.
XPSR "xpsr" ARMv6-M and ARMv7-M processors
  • 对于具有浮点硬件的目标,下表中列出的寄存器也可用于命名寄存器变量。
    Table 9-20 Named registers available on targets with floating-point hardware
Register Character string for __asm
FPSID "fpsid"
FPSCR "fpscr"
FPEXC "fpexc"
FPINST "fpinst"
FPINST2 "fpinst2"
FPSR "fpsr"
MVFR0 "mvfr0"
MVFR1 "mvfr1"

Note

  • 有些寄存器在某些体系结构上不可用;
  • 必须将核心寄存器声明为全局而不是本地命名寄存器变量。
  1. 如果您在本地声明它们,您的程序可能仍然会编译,但是如果这样做,您会有意外的运行时行为的风险。
  2. 对其他寄存器的命名寄存器变量的范围没有限制。
  • 全局命名寄存器变量是声明它的源文件的全局变量,而不是程序的全局变量。
    它对其他文件没有影响,除非使用多文件编译或在头文件中声明。
  • 将核心寄存器声明为命名寄存器变量意味着编译器无法使用该寄存器执行其他操作。
  1. 如果声明的命名寄存器变量太多,代码大小会显著增加。
  2. 在某些情况下,程序可能无法编译,例如,如果没有足够的寄存器可用于计算特定表达式。
  • 由ARM体系结构(AAPCS)的过程调用标准定义的寄存器使用不受声明命名寄存器变量的影响。

例如,r0总是用于返回函数的结果值,即使它声明为命名的寄存器变量。

  • 命名寄存器变量是一个编译器专用的功能。除R12之外,链接器等工具不会更改对象文件中的寄存器用法。

aapcs保留R12作为程序间临时寄存器。如果要求在函数调用之间保留R12的值,则不能将其声明为命名寄存器变量。

Examples

1. 在以下示例中,APSR声明为“APSR”寄存器的命名寄存器变量:

register unsigned int apsr __asm("apsr");
apsr = ~(~apsr | 0x40);

这将生成以下指令序列:

MRS r0,APSR ; formerly CPSR
BIC r0,r0,#0x40
MSR CPSR_c, r0

2. 在下面的示例中,pmcr声明为与协处理器cp15关联的寄存器变量,

在MCR或MRC指令中, CRn = c9, CRm = c12, opcode1 = 0, opcode2 = 0;

register unsigned int PMCR __asm("cp15:0:c9:c12:0");
__inline void __reset_cycle_counter(void)
{
   PMCR = 4;
}

反汇编输出如下:

__reset_cycle_counter PROC
   MOV    r0,#4
   MCR    p15,#0x0,r0,c9,c12,#0
   BX     lr
   ENDP

3. 在下面的示例中,cp15_control声明为访问协处理器寄存器的寄存器变量。

此示例使用CP15启用MMU:

register unsigned int cp15_control __asm("cp15:0:c1:c0:0");
cp15_control |= 0x1;

生成以下指令序列 :

MRC  p15,#0x0,r0,c1,c0,#0
ORR  r0,r0,#1
MCR  p15,#0x0,r0,c1,c0,#0

4. 在以下示例中,用声明Cortex-M3的_msp、_control和_psp命名寄存器变量来设置堆栈指针:

register unsigned int _control __asm("control");
register unsigned int _msp     __asm("msp");
register unsigned int _psp     __asm("psp");void init(void)
{
 _msp = 0x30000000;        // set up Main Stack Pointer
 _control = _control | 3;  // switch to User Mode with Process Stack
 _psp = 0x40000000;        // set up Process Stack Pointer
}

生成以下指令序列 :

init
 MOV r0,#0x30000000
 MSR MSP,r0
 MRS r0,CONTROL
 ORR r0,r0,#3
 MSR CONTROL,r0
 MOV r0,#0x40000000
 MSR PSP,r0
 BX lr
posted @ 2019-08-16 09:15  NickQ  阅读(1627)  评论(0编辑  收藏  举报