Nordic系列芯片讲解八( Nordic SDK常见特殊指令汇集)

内容比较多,读者可以点击右边的目录,找到你感兴趣的指令来看

Nordic里面有大量的特殊指令,理解这些指令对理解SDK有非常大的帮助,当然这些指令也非常有意思。特别是__svc、 __wfe、attribute((section(“name”))) 等。下面的特殊指令都是针对MDK KEIL编译器的。

一、Compiler-specific Keywords and Operators

  1. __asm

This keyword passes information from the compiler to the ARM assembler armasm.
The precise action of this keyword depends on its usage.
Usage
Embedded assembly
The __asm keyword can declare or define an embedded assembly function. For example:
__asm void my_strcpy(const char *src, char *dst);
Inline assembly
The __asm keyword can incorporate inline assembly into a function. For example:

int qadd(int i, int j) {
    int res;
    __asm
    {
        QADD   res, i, j
    }
    return res; }

Assembly labels
The __asm keyword can specify an assembly label for a C symbol. For example:
int count asm(“count_v1”); // export count_v1, not count
Named register variables
The __asm keyword can declare a named register variable. For example:
register int foo __asm(“r0”);

2.__inline

The __inline keyword suggests to the compiler that it compiles a C or C++ function inline, if it is sensible to do so.
The semantics of __inline are exactly the same as those of the inline keyword. However, inline is not available in C90.
__inline is a storage class qualifier. It does not affect the type of a function.
Example

__inline int f(int x)
{
    return x*5+1;
}
int g(int x, int y)
{
    return f(x) + f(y);
}

3.__align

The __align keyword instructs the compiler to align a variable on an n-byte boundary.
__align is a storage class modifier. It does not affect the type of the function.
Syntax
__align(n)
Where:
n
is the alignment boundary.
For local variables, n can take the values 1, 2, 4, or 8.
For global variables, n can take any value up to 0x80000000 in powers of 2.
Usage
__align(n) is useful when the normal alignment of the variable being declared is less than n. Eight-byte alignment can give a significant performance advantage with VFP instructions.
__align can be used in conjunction with extern and static.
Restrictions

Because __align is a storage class modifie

r, it cannot be used on:

Types, including typedefs and structure definitions.


Function parameters.

You can only overalign. That is, you can make a two-byte object four-byte aligned but you cannot align a four-byte object at 2 bytes.
Example

__align(8) char buffer[128];  // buffer starts on eight-byte boundary
void foo(void)
{
    ...
    __align(16) int i; // this alignment value is not permitted for
                       // a local variable
    ...
}
__align(16) int i; // permitted as a global variable.
  1. __INTADDR

The INTADDR operation treats the enclosed expression as a constant expression, and converts it to an integer constant.
Note
This is used in the offsetof macro.
Syntax
__INTADDR(expr)
Where:
expr
is an integral constant expression.
Return value
INTADDR(expr) returns an integer constant equivalent to expr.

5.__packed

The __packed qualifier is useful to map a structure to an external data structure, or for accessing unaligned data, but it is generally not useful to save data size because of the relatively high cost of unaligned access.
Usage
The __packed qualifier sets the alignment of any valid type to 1.
This means that:

There is no padding inserted to align the packed object.

Objects of packed type are read or written using unaligned accesses.

The __packed qualifier applies to all members of a structure or union when it is declared using __packed. There is no padding between members, or at the end of the structure. All substructures of a packed structure must be declared using __packed. Integral subfields of an unpacked structure can be packed individually.
Only packing fields in a structure that requires packing can reduce the number of unaligned accesses.
Note
On ARM processors that do not support unaligned access in hardware, for example, pre-ARMv6, access to unaligned data can be costly in terms of code size and execution speed. Data accesses through packed structures must be minimized to avoid increase in code size and performance loss.
Restrictions
The following restrictions apply to the use of __packed:

The __packed qualifier cannot be used on structures that were previously declared without __packed.

Unlike other type qualifiers you cannot have both a __packed and non-__packed version of the same structure type.

The __packed qualifier does not affect local variables of integral type.

A packed structure or union is not assignment-compatible with the corresponding unpacked structure. Because the structures have a different memory layout, the only way to assign a packed structure to an unpacked structure is by a field-by-field copy.

The effect of casting away __packed is undefined, except on char types. The effect of casting a nonpacked structure to a packed structure, or a packed structure to a nonpacked structure, is undefined. A pointer to an integral type that is not packed can be legally cast, explicitly or implicitly, to a pointer to a packed integral type.

There are no packed array types. A packed array is an array of objects of packed type. There is no padding in the array.

Errors
Taking the address of a field in a __packed structure or a __packed-qualified field yields a __packed-qualified pointer. The compiler produces a type error if you attempt to implicitly cast this pointer to a non-__packed pointer. This contrasts with its behavior for address-taken fields of a #pragma packed structure.
Examples
This example shows that a pointer can point to a packed type.

typedef __packed int* PpI;          /* pointer to a __packed int */
__packed int *p;                    /* pointer to a __packed int */
PpI p2;                             /* 'p2' has the same type as 'p' */
                                    /* __packed is a qualifier  */
                                    /* like 'const' or 'volatile' */
typedef int *PI;                    /* pointer to int */
__packed PI p3;                     /* a __packed pointer to a normal int */
                                    /*  -- not the same type as 'p' and 'p2' */
int *__packed p4;                   /* 'p4' has the same type as 'p3' */

This example shows that when a packed object is accessed using a pointer, the compiler generates code that works and that is independent of the pointer alignment.

typedef __packed struct
{
    char x;                   // all fields inherit the __packed qualifier
    int y;
} X;                          // 5 byte structure, natural alignment = 1
int f(X *p)
{
    return p->y;              // does an unaligned read
}
typedef struct
{
    short x;
    char y;
    __packed int z;           // only pack this field
    char a;
} Y;                          // 8 byte structure, natural alignment = 2
int g(Y *p)
{
    return p->z + p->x;       // only unaligned read for z
}

6.__svc

The __svc keyword declares a SuperVisor Call (SVC) function taking up to four integer-like arguments and returning up to four results in a value_in_regs structure.
__svc is a function qualifier. It affects the type of a function.
Syntax
__svc(int svc_num) return-type function-name([argument-list]);
Where:
svc_num
Is the immediate value used in the SVC instruction.
It is an expression evaluating to an integer in the range:

0 to 224–1 (a 24-bit value) in an ARM instruction.

0-255 (an 8-bit value) in a 16-bit Thumb instruction.

Usage
This causes function invocations to be compiled inline as an AAPCS-compliant operation that behaves similarly to a normal call to a function.
You can use the __value_in_regs qualifier to specify that a small structure of up to 16 bytes is returned in registers, rather than by the usual structure-passing mechanism defined in the AAPCS.
Errors
When an ARM architecture variant or ARM architecture-based processor that does not support an SVC instruction is specified on the command line using the --cpu option, the compiler generates an error.
Example

__svc(42) void terminate_1(int procnum); // terminate_1 returns no results
__svc(42) int terminate_2(int procnum);  // terminate_2 returns one result
typedef struct res_type
{
    int res_1;
    int res_2;
    int res_3;
    int res_4;
} res_type;
__svc(42) __value_in_regs res_type terminate_3(int procnum);
                                         // terminate_3 returns more than
                                         // one result

7.__weak

This keyword instructs the compiler to export symbols weakly.
The __weak keyword can be applied to function and variable declarations, and to function definitions.
Usage
Functions and variable declarations
For declarations, this storage class specifies an extern object declaration that, even if not present, does not cause the linker to fault an unresolved reference.
For example:
__weak void f(void);

f(); // call f weakly
If the reference to a missing weak function is made from code that compiles to a branch or branch link instruction, then either:

The reference is resolved as branching to the next instruction. This effectively makes the branch a NOP.

The branch is replaced by a NOP instruction.

Function definitions
Functions defined with __weak export their symbols weakly. A weakly defined function behaves like a normally defined function unless a nonweakly defined function of the same name is linked into the same image. If both a nonweakly defined function and a weakly defined function exist in the same image then all calls to the function resolve to call the nonweak function. If multiple weak definitions are available, the linker generates an error message, unless the linker option --muldefweak is used. In this case, the linker chooses one for use by all calls.
Functions declared with __weak and then defined without __weak behave as nonweak functions.
Restrictions
There are restrictions when you qualify function and variable declarations, and function definitions, with __weak.
Functions and variable declarations
A function or variable cannot be used both weakly and nonweakly in the same compilation. For example, the following code uses f() weakly from g() and h():

void f(void);
void g()
{
    f();
}
__weak void f(void);
void h()
{
    f();
}

It is not possible to use a function or variable weakly from the same compilation that defines the function or variable. The following code uses f() nonweakly from h():

__weak void f(void);
void h()
{
    f();
}
void f() {}

The linker does not load the function or variable from a library unless another compilation uses the function or variable nonweakly. If the reference remains unresolved, its value is assumed to be NULL. Unresolved references, however, are not NULL if the reference is from code to a position-independent section or to a missing __weak function.
Function definitions
Weakly defined functions cannot be inlined.
Example

__weak const int c;                // assume 'c' is not present in final link
const int *f1() { return &c; } // '&c' returns non-NULL if
                                   // compiled and linked /ropi
__weak int i;                      // assume 'i' is not present in final link
int *f2() { return &i; }       // '&i' returns non-NULL if 
                                   // compiled and linked /rwpi
__weak void f(void);               // assume 'f' is not present in final link
typedef void (*FP)(void);
FP g() { return f; }               // 'g' returns non-NULL if 
                                   // compiled and linked /ropi

二、Function attributes

1.attribute((aligned)) variable attribute

The aligned variable attribute specifies a minimum alignment for the variable or structure field, measured in bytes.
Note
This variable attribute is a GNU compiler extension that the ARM compiler supports.
Example

/* Aligns on 16-byte boundary */
int x __attribute__((aligned (16)));
/* In this case, the alignment used is the maximum alignment for a scalar data type. For ARM, this is 8 bytes. */
short my_array[3] __attribute__((aligned));

2.attribute((section(“name”))) variable attribute

The section attribute specifies that a variable must be placed in a particular data section.
Normally, the ARM compiler places the objects it generates in sections like .data and .bss. However, you might require additional data sections or you might want a variable to appear in a special section, for example, to map to special hardware.
If you use the section attribute, read-only variables are placed in RO data sections, read-write variables are placed in RW data sections unless you use the zero_init attribute. In this case, the variable is placed in a ZI section.
Note
This variable attribute is a GNU compiler extension that the ARM compiler supports.
Example

/* in RO section */
const int descriptor[3] __attribute__((section ("descr"))) = { 1,2,3 };
/* in RW section */
long long rw_initialized[10] __attribute__((section ("INITIALIZED_RW"))) = {5};
/* in RW section */
long long rw[10] __attribute__((section ("RW")));
/* in ZI section */
long long altstack[10] __attribute__((section ("STACK"), zero_init));

3.attribute((naked)) function attribute

This attribute tells the compiler that the function is an embedded assembly function. You can write the body of the function entirely in assembly code using __asm statements.
The compiler does not generate prologue and epilogue sequences for functions with attribute((naked)).
The compiler only supports basic __asm statements in attribute((naked)) functions. Using extended assembly, parameter references or mixing C code with __asm statements might not work reliably.
Example 3-1 Examples

__attribute__((naked)) int add(int i, int j); /* Declaring a function with __attribute__((naked)). */

__attribute__((naked)) int add(int i, int j)
{
    __asm("ADD r0, r1, #1"); /* Basic assembler statements are supported. */

/*  Parameter references are not supported inside naked functions: */
/*  __asm (
    "ADD r0, %[input_i], %[input_j]"       /* Assembler statement with parameter references */
    :                                      /* Output operand parameter */
    : [input_i] "r" (i), [input_j] "r" (j) /* Input operand parameter */
    );
*/

/*  Mixing C code is not supported inside naked functions: */
/*  int res = 0;
    return res; 
*/

}

4.attribute((unused)) function attribute

The unused function attribute prevents the compiler from generating warnings if the function is not referenced. This does not change the behavior of the unused function removal process.
Note:
By default, the compiler does not warn about unused functions. Use -Wunused-function to enable this warning specifically, or use an encompassing -W value such as -Wall.
The attribute((unused)) attribute can be useful if you usually want to warn about unused functions, but want to suppress warnings for a specific set of functions.
Example

static int unused_no_warning(int b) __attribute__((unused));
static int unused_no_warning(int b)
{
  return b++;
}

static int unused_with_warning(int b);
static int unused_with_warning(int b)
{
  return b++;
}

Compiling this example with -Wall results in the following warning:
armclang --target=aarch64-arm-none-eabi -c test.c -Wall
test.c:10:12: warning: unused function ‘unused_with_warning’ [-Wunused-function]
static int unused_with_warning(int b)
^
1 warning generated.

5.attribute((packed)) type attribute

The packed type attribute specifies that a type must have the smallest possible alignment. This attribute only applies to struct and union types.
Note:
You must access a packed member of a struct or union directly from a variable of the containing type. Taking the address of such a member produces a normal pointer which might be unaligned. The compiler assumes that the pointer is aligned. Dereferencing such a pointer can be unsafe even when unaligned accesses are supported by the target, because certain instructions always require word-aligned addresses.
Note:
If you take the address of a packed member, in most cases, the compiler generates a warning.
When you specify attribute((packed)) to a structure or union, it applies to all members of the structure or union. If a packed structure has a member that is also a structure, then this member structure has an alignment of 1-byte. However, the packed attribute does not apply to the members of the member structure. The members of the member structure continue to have their natural alignment.
Example 3-2 Examples

struct __attribute__((packed)) foobar 
{
  char x;
  short y;
}; 

short get_y(struct foobar *s) 
{
    // Correct usage: the compiler will not use unaligned accesses
    // unless they are allowed.
    return s->y;
} 

short get2_y(struct foobar *s) 
{
    short *p = &s->y; // Incorrect usage: 'p' might be an unaligned pointer.
    return *p;  // This might cause an unaligned access.
}

6.attribute((weak)) function attribute

Functions defined with attribute((weak)) export their symbols weakly.
Functions declared with attribute((weak)) and then defined without attribute((weak)) behave as weak functions.

7.attribute((always_inline)) function attribute

This function attribute indicates that a function must be inlined.
The compiler attempts to inline the function, regardless of the characteristics of the function.
In some circumstances the compiler may choose to ignore the attribute((always_inline)) attribute and not inline a function. For example:
A recursive function is never inlined into itself.
Functions making use of alloca() are never inlined.
Note
This function attribute is a GNU compiler extension that the ARM compiler supports. It has the keyword equivalent __forceinline.
Example

static int max(int x, int y) __attribute__((always_inline));
static int max(int x, int y)
{
    return x > y ? x : y; // always inline if possible
}

8.attribute((used)) function attribute

This function attribute informs the compiler that a static function is to be retained in the object file, even if it is unreferenced.
Functions marked with attribute((used)) are tagged in the object file to avoid removal by linker unused section removal.
Note:
Static variables can also be marked as used, by using attribute((used)).
Example

static int lose_this(int);
static int keep_this(int) __attribute__((used));     // retained in object file
static int keep_this_too(int) __attribute__((used)); // retained in object file

三、 Instruction intrinsics

1.__breakpoint intrinsic

This intrinsic inserts a BKPT instruction into the instruction stream generated by the compiler.
To use this intrinsic, your source file must contain #include <arm_compat.h>. This is only available for AArch32.
It enables you to include a breakpoint instruction in your C or C++ code.
Syntax
void __breakpoint(int val)
Where:
val
is a compile-time constant integer whose range is:
0 … 65535
if you are compiling source as ARM code
0 … 255
if you are compiling source as Thumb code.
Errors
The __breakpoint intrinsic is not available when compiling for a target that does not support the BKPT instruction. The compiler generates an error in this case.
Example

void func(void)
{
    ...
    __breakpoint(0xF02C);
    ...
}

2.__current_sp intrinsic

This intrinsic returns the value of the stack pointer at the current point in your program.
To use this intrinsic, your source file must contain #include <arm_compat.h>. This is only available for AArch32.
Syntax
unsigned int __current_sp(void)
Return value
The __current_sp intrinsic returns the current value of the stack pointer at the point in the program where the intrinsic is used

4.__disable_fiq

This intrinsic disables FIQ interrupts.
To use this intrinsic, your source file must contain #include <arm_compat.h>. This is only available for AArch32.
Note:
Typically, this intrinsic disables FIQ interrupts by setting the F-bit in the CPSR. However, for v7-M and v8-M.mainline, it sets the fault mask register (FAULTMASK). This intrinsic is not supported for v6-M and v8-M.baseline.
Syntax
int __disable_fiq(void)
Usage
int __disable_fiq(void); disables fast interrupts and returns the value the FIQ interrupt mask has in the PSR before disabling interrupts.
Return value
int __disable_fiq(void); returns the value the FIQ interrupt mask has in the PSR before disabling FIQ interrupts.
Restrictions
The __disable_fiq intrinsic can only be executed in privileged modes, that is, in non-user modes. In User mode this intrinsic does not change the interrupt flags in the CPSR.
Example

void foo(void)
{
    int was_masked = __disable_fiq();
    /* ... */
    if (!was_masked)
        __enable_fiq();
}

5.__disable_irq intrinsic

This intrinsic disables IRQ interrupts.
To use this intrinsic, your source file must contain #include <arm_compat.h>. This is only available for AArch32.
Note:
Typically, this intrinsic disables IRQ interrupts by setting the I-bit in the CPSR. However, for M-profile it sets the exception mask register (PRIMASK).
Syntax
int __disable_irq(void)
Usage
int __disable_irq(void); disables interrupts and returns the value the IRQ interrupt mask has in the PSR before disabling interrupts.
Return value
int __disable_irq(void); returns the value the IRQ interrupt mask has in the PSR before disabling IRQ interrupts.
Example

void foo(void)
{
    int was_masked = __disable_irq();
    /* ... */
    if (!was_masked)
        __enable_irq();
}

Restrictions
The __disable_irq intrinsic can only be executed in privileged modes, that is, in non-user modes. In User mode this intrinsic does not change the interrupt flags in the CPSR

6.__enable_irq intrinsic

This intrinsic enables IRQ interrupts.
To use this intrinsic, your source file must contain #include <arm_compat.h>. This is only available for AArch32.
Note:
Typically, this intrinsic enables IRQ interrupts by clearing the I-bit in the CPSR. However, for Cortex M-profile processors, it clears the exception mask register (PRIMASK).
Synvoid __enable_irq(void) trictions
The __enable_irq intrinsic can only be executed in privileged modes, that is, in non-user modes. In User mode this intrinsic does not change the interrupt flags in the CPSR

7.__wfe

This intrinsic inserts a WFE instruction into the instruction stream generated by the compiler.
In some architectures, for example the v6T2 architecture, the WFE instruction executes as a NOP instruction.
Syntax

void __wfe(void)

Errors
The compiler does not recognize the __wfe intrinsic when compiling for a target that does not support the WFE instruction. The compiler generates either a warning or an error in this case, depending on the source language:
In C code: Warning: #223-D: function “__wfe” declared implicitly.
In C++ code: Error: #20: identifier “__wfe” is undefined.

8.__wfi

This intrinsic inserts a WFI instruction into the instruction stream generated by the compiler.
In some architectures, for example the v6T2 architecture, the WFI instruction executes as a NOP instruction.
Syntax
void __wfi(void)
Errors
The compiler does not recognize the __wfi intrinsic when compiling for a target that does not support the WFI instruction. The compiler generates either a warning or an error in this case, depending on the source language:
In C code: Warning: #223-D: function “__wfi” declared implicitly.
In C++ code: Error: #20: identifier “__wfi” is undefined.

9.__sev intrinsic

This intrinsic inserts a SEV instruction into the instruction stream generated by the compiler.
In some architectures, for example the v6T2 architecture, the SEV instruction executes as a NOP instruction.
Syntax
void __sev(void)
Errors
The compiler does not recognize the __sev intrinsic when compiling for a target that does not support the SEV instruction. The compiler generates either a warning or an error in this case, depending on the source language:
In C code: Warning: #223-D: function “__sev” declared implicitly.
In C++ code: Error: #20: identifier “__sev” is undefined.

四、Pragmas

.1. #pragma import(__use_full_stdio)

This pragma selects an extended version of microlib that uses full standard ANSI C input and output functionality.
Note
Microlib is an alternative library to the default C library. Only use this pragma if you are using microlib.
The following exceptions apply:

feof() and ferror() always return 0.

setvbuf() and setbuf() are guaranteed to fail.

feof() and ferror() always return 0 because the error and end-of-file indicators are not supported.
setvbuf() and setbuf() are guaranteed to fail because all streams are unbuffered.
This version of microlib stdio can be retargeted in the same way as the standardlib stdio functions

2.#pragma pop

This pragma restores the previously saved pragma state.

3.#pragma push

This pragma saves the current pragma state.

4.#pragma pack(n)

This pragma aligns members of a structure to the minimum of n and their natural alignment. Packed objects are read and written using unaligned accesses.
Note
This pragma is a GNU compiler extension that the ARM compiler supports.
Syntax

pragma pack(n)

Where:
n
is the alignment in bytes, valid alignment values being 1, 2, 4 and 8.
Default
The default is #pragma pack(8).
Errors
Taking the address of a field in a #pragma packed struct does not yield a __packed pointer, so the compiler does not produce an error if you assign this address to a non-__packed pointer. However, the field might not be properly aligned for its type, and dereferencing such an unaligned pointer results in undefined behavior.
Example
This example demonstrates how pack(2) aligns integer variable b to a 2-byte boundary.

typedef struct
{ 
    char a;
    int b;
} S;

pragma pack(2)

typedef struct
{ 
    char a;
    int b;
} SP;
S var = { 0x11, 0x44444444 };
SP pvar = { 0x11, 0x44444444 };

The layout of S is:
Figure 9-1 Nonpacked structure S

这里写图片描述
The layout of SP is:
Figure 9-2 Packed structure SP
这里写图片描述

Note
In this layout, x denotes one byte of padding.
SP is a 6-byte structure. There is no padding after b.

5.#pragma anon_unions, #pragma no_anon_unions

These pragmas enable and disable support for anonymous structures and unions.
Default
The default is #pragma no_anon_unions.

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值