知识卡片

处理器是实现细节:用标准stdint.h取代厂商专有扩展,并靠PAL隔离寄存器访问

普通读书笔记卡

内容

嵌入式工具链的编译器常常自带基于C语言的扩展库和特殊关键字,方便直接访问寄存器、I/O端口、时钟、中断控制器等硬件功能——代码看起来还是C,实际已经不是标准C了,一旦用了这些扩展,就再也不能用其他编译器编译,甚至同一处理器换个编译器都可能不行。作者不认为这是厂商故意设的陷阱,但强调必须学会限制这类”帮助”的使用范围:比如某ACME DSP系统专属的acmetypes.h头文件如果被直接引用,代码就和这个具体芯片绑死了——脱离该平台测试时整数类型大小会算错,日后要迁移到别的处理器上更是难上加难;解法是改用更标准的stdint.h(如果目标编译器没提供,可以自己基于厂商头文件包一层typedef来实现),这样写出的嵌入式软件和固件才能保持整洁且可移植。但并非所有代码都能做到完全独立于处理器——像直接操作IE(中断使能位)、SBUF0(串口输出缓冲区)、TI_0(发送中断标志)这类寄存器级变量的函数,本质上就是在利用C语言扩展直接访问微处理器内置部件,这类代码没法回避。整洁的嵌入式架构对此的处理方式是:把所有涉及设备访问的寄存器操作集中起来、严格限制在固件层——任何需要了解这些寄存器值的代码都必须归为固件代码,与具体硬件实现绑定,在处理器工作稳定之前无法独立运行,迁移到新处理器时也必然要经历改动;如果确实需要这类访问,固件应该把这些底层函数隔离进一个专门的处理器抽象层(PAL),这样使用PAL的固件代码就能在脱离目标平台的情况下被测试。

参考来源

- 位置:《架构整洁之道》第29章《整洁的嵌入式架构》"处理器是实现细节"(源文件:_epub-src/text/part0014_split_014.html) - 结论依据:原文说明厂商专有C扩展会导致代码无法跨编译器/跨处理器使用,用acmetypes.h绑定ACME DSP的例子说明改用stdint.h能保持代码整洁可移植,并说明必须使用寄存器访问的代码应集中限制在固件层、通过处理器抽象层(PAL)实现脱离目标平台测试,直接支撑本卡片结论。 - 原始内容:一旦你在代码中使用了这些函数,你写的就不再是C语言程序……我们应该用更标准的stdint.h来替代acmetypes.h……在整洁的嵌入式架构中,我们会将这些用于设备访问的寄存器访问集中在一起,并将其限制在固件层中……固件就必须将这类底层函数隔离成处理器抽象层(PAL)。