ARM 是否假设所有 Cortex-M 微控制器都是小端法?

Does ARM assume that all Cortex-M microcontrollers are little-endian?

我目前正在 generating C++ code from SVD files

在研究我可以假设的 ARM 应用程序二进制接口中的位域布局时,我在撰写本文时遇到了 ARM's official C header file for the Cortex-M7 core (commit 10a6d292f2

它包含以下代码:

/**
  \brief  Union type to access the Application Program Status Register (APSR).
 */
typedef union
{
  struct
  {
    uint32_t _reserved0:16;              /*!< bit:  0..15  Reserved */
    uint32_t GE:4;                       /*!< bit: 16..19  Greater than or Equal flags */
    uint32_t _reserved1:7;               /*!< bit: 20..26  Reserved */
    uint32_t Q:1;                        /*!< bit:     27  Saturation condition flag */
    uint32_t V:1;                        /*!< bit:     28  Overflow condition code flag */
    uint32_t C:1;                        /*!< bit:     29  Carry condition code flag */
    uint32_t Z:1;                        /*!< bit:     30  Zero condition code flag */
    uint32_t N:1;                        /*!< bit:     31  Negative condition code flag */
  } b;                                   /*!< Structure used for bit  access */
  uint32_t w;                            /*!< Type      used for word access */
} APSR_Type;

/* APSR Register Definitions */
#define APSR_N_Pos                         31U                                            /*!< APSR: N Position */
#define APSR_N_Msk                         (1UL << APSR_N_Pos)                            /*!< APSR: N Mask */

我有意在并集之后包含第一个位掩码,因为它确认了 ARM®v7-M Architecture Reference Manual 指定的内容:N 位,又名 "Negative condition code flag",始终是该寄存器的最高有效位,不管字节顺序。从相应位字段的注释中也可以清楚地看出这一点。

ARM 可能假设任何为 Cortex-M7 目标编译该代码的编译器都满足 Procedure Call Standard for the Arm® Architecture,这似乎是一个合理的假设。

ABI 指定(除其他外):

A sequence of bit-fields is laid out in the order declared [...].

这意味着上面 struct 中的位域 N 将始终被布置为内存中寄存器的最后一位。

但是,如果处理器是 big-endian,上面 struct 中的位域 N 在这种情况下将是寄存器的最低有效位,即第 0 位,而不是第 31 位!

我在 core_cm7.h.

中找不到可以解决此问题的注释或任何编译时标志

事实上,我刚刚发现 another piece of ARM-code 这似乎证实了我的分析:

#ifndef __BIG_ENDIAN // bitfield layout of APSR is sensitive to endianness
typedef union
{
    struct
    {
        int mode:5;
        int T:1;
        int F:1;
        int I:1;
        int _dnm:19;
        int Q:1;
        int V:1;
        int C:1;
        int Z:1;
        int N:1;
    } b;
    unsigned int word;
} PSR;
#else /* __BIG_ENDIAN */
typedef union
{
    struct 
    {
        int N:1;
        int Z:1;
        int C:1;
        int V:1;
        int Q:1;
        int _dnm:19;
        int I:1;
        int F:1;
        int T:1;
        int mode:5;
    } b;
    unsigned int word;
} PSR;
#endif /* __BIG_ENDIAN */

这显然是针对不同的内核(我猜不是 Cortex),但它证实了原理。

那么 ARM 是否只是假设永远不会有任何大端 Cortex-M 处理器,还是我遗漏了什么?

虽然其他体系结构 have/do 和 byte/word 字节序一样,但 arm 并没有在其文档中明确说明和显示在图片中。但是 31 始终是第 31 位,与字节序无关,字节地址位 31 所在的是受(字节可寻址地址)字节序影响的内容,如果它是寄存器,则

The endianness setting only applies to data accesses. Instruction fetches are always little endian.

All accesses to the SCS are little endian

默认字节顺序由芯片供应商而非 ARM 选择:

ARMv7-M supports a selectable endian model in which, on a reset, a control input determines whether the endianness is big endian (BE) or little endian (LE).

The AIRCR.ENDIANNESS bit indicates the endianness

Bits[10:8] reset to 0b000 , see register description for more information.

皮质-m7

Support for ARMv7-M big-endian byte-invariant or little-endian accesses.

我在我的评论中提到了这一点,armv7m 确实显示了字节不变性,或者使用 arm 术语的 BE-8。

所以cortex-m7 trm中没有调用strap pin,没看m3,m4,m8

芯片供应商在芯片的工作方式以及为核心制定了哪些 strap 选项或其他编译时选项方面起着最大的作用。然后是他们的实现以及它符合或不符合的程度,只有武器领域的东西在武器控制范围内,在芯片供应商之外(包括位字节顺序)。

因此 arm 域中的寄存器应该是小端(如果小于字可寻址)并且第 31 位是同一字节地址中的第 31 位(如果字节可寻址)。

位域与这些无关,它们是由编译器作者定义的实现,语言规范(C 或 C++)的版本随着时间的推移而发展,但使用位域仍然是一个非常糟糕的主意-字段,如果你使用编译器,你的内存不会那么紧张,1970 年代已经结束。您永远不应跨编译域指向结构或联合,因为它们也是实现定义的,而不是目标定义的或语言定义的。 (我使用像这样的例子作为面试问题来测试候选人的语言经验和知识)。 ARM 和芯片供应商将明确和合法地声明他们的代码应该在哪里 运行 并且他们对该代码的质量或故障不承担任何责任,基本上这一切都在你身上,所以小心使用这样的代码,并且保护自己,特别是如果你看到这个位域结构联合的东西(如果他们不能把那部分弄好我通常会扔掉整个库还有什么我必须挖掘的)。

因此,对于您在基于位域的代码中看到的内容,您无法真正提出任何理论,请阅读 ARM 的 (good/better) 文档(即体系结构参考手册和技术参考手册。AMBA/AXI 手册。程序员的参考资料一直有问题)以及芯片供应商提供的任何东西,通常在该级别上没有详细说明,然后对该芯片和该内核进行实验,不对该供应商的其他芯片做出任何假设,也不其他产品中使用的内核是否具有相同供应商的内核。

安全的做法是使用几乎任何 arm 进行小端排序。 xscale is/was 一个例外,我认为 Marvell 从 Intel 那里购买了这些,并且混合了他们直接从 arm 购买的内核。我似乎记得我使用的 xscale 可以使用小端,制作大端 gcc 工具链充其量是一场噩梦。我没有看到任何主要玩家的cortex-ms,我有很多但不是所有当然,st,nxp,atmel到目前为止我只看到little endian。 ti 有一个 cortex-r,他们提供或大或小的,你不能切换,但那些不是 cortex-ms。

坚持使用 cortex-ms 的小端,如果您被供应商搞砸了,1) 该产品将不会持续或为特定客户制造 2) 将该供应商列入黑名单以进行此类行为。否则你应该过上幸福的生活,而不必纠结于 be8 与 be32 不工作的工具链,内部核心寄存器与外部总线访问与芯片供应商实现的核心寄存器外部访问。没有任何迹象表明 ARM 会改变它在字节序上的立场,这将是一个糟糕的,可能是致命的,在这一点上的举动,将您在文档中看到的字节序选择视为营销要点,是的,我们支持大字节序和小字节序endian,而不是您实际使用的功能。

我刚刚在 Github 上注册了 an issue ARM 的 CMSIS 存储库。我现在的假设是答案是肯定的:ARM 确实假设所有 Cortex-M MCU 都是并且将是小端,至少在它们发布的代码中是这样。我希望我能以某种方式从他们那里得到一些确认。既然如此,我就post这里吧

编辑:

我的上述假设已经被one of the answers to my registered issue明确证实。这要么是疏忽,要么是无证自觉的选择,但结果是一样的。

重申用于内存映射寄存器的显而易见的位域:

  • 应该非常清楚地记录下来。在 C 和 C++ 中,它们使用实现定义的行为,因此只能在特定的 ABI 下才有意义。应明确指定此类代码预期工作的假设。
  • 假定某种字节序。这在 ARM ABI 下是正确的,但可能是一个更普遍的问题。这意味着此类代码需要有一种策略来断言字节顺序假设是正确的。