我目前正在研究generating C++ code from SVD files。
在研究我可以在ARM应用程序二进制接口中进行位域布局假设时,我遇到了ARM's official C header file for the Cortex-M7 core(在撰写本文时提交了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位(即“负条件代码标志”)始终是该寄存器的最高有效位,无论字节序。从相应位字段的注释中也可以很清楚地看到这一点。
ARM可能假定任何为Cortex-M7目标编译该代码的编译器都满足Procedure Call Standard for the Arm® Architecture,这似乎是一个合理的假设。
ABI指定(以及其他):
按声明的顺序排列一系列位域。
这意味着上面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处理器,或者我错过了什么?
答案 0 :(得分:0)
我刚刚在Github上的ARM CMSIS存储库中注册了an issue。我现在的假设是,答案是肯定的:ARM确实假设,至少在它们发布的代码中,所有Cortex-M MCU都是并且将是低端的。我希望我能以某种方式得到他们的确认。在这种情况下,我将其发布在这里。
编辑:
我上面的假设已由one of the answers至my registered issue证实。这要么是一个忽视,要么是没有记载的有意识的选择,但结果是相同的。
要重述用于内存映射寄存器的显而易见的位域:
答案 1 :(得分:-2)
虽然其他体系结构具有/确实具有位字节序,字节/字尾字节序臂却没有/在其文档中明确指出和显示。但是31始终是第31位,与字节顺序无关,而字节地址第31位所到达的字节顺序受(字节可寻址地址)字节顺序的影响,并且如果它是寄存器,那么</ p>
字节序设置仅适用于数据访问。指令提取始终是小端的。
所有对SCS的访问均为小端
默认字节序由芯片供应商而非ARM选择:
ARMv7-M支持可选的字节序模型,该模型在复位时由控制输入确定字节序是大字节序(BE)还是小字节序(LE)。
AIRCR.ENDIANNESS位指示字节顺序
位[10:8]重置为0b000,有关更多信息,请参见寄存器描述。
cortex-m7
支持ARMv7-M大端字节不变或小端访问。
我在评论中向后说,armv7m确实显示字节不变,或使用arm术语显示BE-8。
因此,在cortex-m7 trm中没有调出皮带针,没有看m3,m4,m8。
芯片供应商在芯片的工作方式以及为内核选择的绑定选项或其他编译时间选项方面起着最大的作用。然后是他们的实现以及实现与否的程度,只有武器领域的东西在武器控制之内,而芯片供应商(包括位字节序)则不在此列。
因此,arm域中的寄存器应为低端字节序(如果少于字可寻址),并且同一字节地址中的第31位为第31位(如果字节可寻址)。
位域与此无关,它们是由编译器作者定义的实现,并且语言规范的版本(C或C ++)随着时间的推移而发展,但是使用位域仍然是一个非常糟糕的主意,如果您使用的是编译器,那么内存并不那么紧,1970年代已经结束。您绝不应该在编译域中指向结构或联合,因为它们也是实现定义的,而不是目标定义的或语言定义的。 (我使用诸如此类的示例作为面试问题来测试应聘者的语言经验和知识)。 ARM和芯片供应商将明确并合法地声明其代码应在何处运行,并且对于该代码的质量或失败概不负责,基本上这一切都在您身上,因此请谨慎使用此类代码,并保护自己,尤其是如果您看到这个位域结构联合的东西(通常,如果他们不能正确地使用那一部分,我通常会丢掉整个库,而我还需要挖掘其他东西)。
因此,您无法真正设计出关于在基于位域的代码中看到的内容的任何理论,请阅读ARM的(良好/更好)文档(意味着体系结构参考手册和技术参考手册,AMBA / AXI手册)。参考文献是有问题的),以及芯片供应商提供的通常在该级别上没有详细说明的任何东西,然后对该芯片和该内核进行实验,并且不对该供应商提供的其他芯片或在其他产品中使用的该内核进行任何假设。那个核心是否是同一供应商。
安全的做法是几乎用任何手臂伸向小端。 xscale是/是一个例外,我认为Marvell是从Intel那里购买的,并且直接混合了他们从arm购买的内核。我似乎记得我曾经使用过的xscale可以使用little endian,使一个大endian gcc工具链充其量只是一场噩梦。我没有从主要参与者那里看到任何cortex-ms,我当然有很多但不是全部,st,nxp,atmel到目前为止,我只看到了一点字节序。 ti的cortex-r大小不一,您无法切换,但不是cortex-ms。
如果您被供应商搞砸了,则在cortex-ms上贴上一点尾数,1)该产品将不会持久或不是为特定客户制造的。2)将这种行为列入该供应商的黑名单。否则,您应该过上幸福的生活,而不必纠结于无法正常工作的工具链。be8 vs be32,内部核心寄存器,总线对外部的访问与芯片供应商实现的核心寄存器的外部。没有任何迹象表明ARM会改变字节序的立场,此刻这将是一个坏的,甚至可能是致命的,请考虑一下您在文档中看到的字节序选择作为市场营销要点,是的,我们支持大字节序,很少支持字节序,而不是您实际使用的功能。