Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/62.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
关于SFR位访问的AVR 8bit,C标准合规性_C_Avr - Fatal编程技术网

关于SFR位访问的AVR 8bit,C标准合规性

关于SFR位访问的AVR 8bit,C标准合规性,c,avr,C,Avr,我的一位同事在编写ATMega时遇到了一些奇怪的问题,与访问输入输出端口有关 在一些研究后观察到问题,我得出结论,如果我们的目标是安全的C标准兼容软件,我们应该避免使用可能编译为SBI或CBI指令的操作访问SFR。我在寻找这个决定是否公正,所以如果我在这里的担心是正确的 Atmel处理器的数据表是,它是一个ATMega16。我将在下面参考本文件的一些页面 我将参考WG14 N1256链接下使用的C标准 处理器的SBI和CBI指令在位级运行,仅访问相关位。因此,它们不是真正的读-修改-写(R-M-

我的一位同事在编写ATMega时遇到了一些奇怪的问题,与访问输入输出端口有关

在一些研究后观察到问题,我得出结论,如果我们的目标是安全的C标准兼容软件,我们应该避免使用可能编译为
SBI
CBI
指令的操作访问SFR。我在寻找这个决定是否公正,所以如果我在这里的担心是正确的

Atmel处理器的数据表是,它是一个ATMega16。我将在下面参考本文件的一些页面

我将参考WG14 N1256链接下使用的C标准

处理器的
SBI
CBI
指令在位级运行,仅访问相关位。因此,它们不是真正的读-修改-写(R-M-W)指令,因为据我所知,它们不执行(目标8位SFR的)读取

在上述数据表的第50页上,第一句话的开头类似于所有AVR端口都具有真正的读-修改-写功能。。。,在进行中,它规定这仅适用于使用
SBI
CBI
指令进行的访问,这些指令在技术上不是R-M-W。数据表不定义什么读数,例如
PORTx
寄存器应该返回(但它表明它们是可读的)。因此,我假设读取这些SFR是未定义的(它们可能返回最后写入的内容或当前输入状态或其他内容)

在第70页,它列出了一些外部中断标志,这很有趣,因为这是
SBI
CBI
指令的性质变得重要的地方。这些标志是在中断发生时设置的,可以通过将它们写入一个来清除这些标志。因此,如果
SBI
是一条真正的R-M-W指令,它将清除所有三个标志,而不考虑操作码中指定的位

现在让我们来讨论C的问题

编译器本身确实是不相关的,唯一重要的事实是,它可能在某些情况下使用
CBI
SBI
指令,我认为这会使编译器不兼容

在上述C99标准中,第5.1.2.3节“程序执行”第2点和第3点(第13页)以及第6.7.3节“类型限定符”第6点(第109页)都提到了这一点。后者提到,构成对具有volatile限定类型的对象的访问的是实现定义的,但是在它之前的几句话要求引用此类对象的任何表达式都应严格按照抽象机器的规则进行评估

还请注意,示例中使用的硬件端口在相应的标头中声明为
volatile

例如:

PORTA |= 1U << 6;
这不会转换为
SBI
,即使它仍然只设置一位(因为
SBI
在操作码中编码了要设置的位)。因此,这将扩展到一个真正的R-M-W序列,其结果可能与上述结果不同(在
PORTA
的情况下,就我可以从数据表中推断,这是未定义的行为)

根据C标准,这种行为可能被允许,也可能不被允许。这一术语也很混乱,这里发生了两件事情,它们混合在一起。首先,在其中一种情况下,更明显的是缺少读访问。另一个不太明显的是如何执行写入

如果编译后的代码忽略了读取,它可能无法触发与这种访问相关的硬件行为。然而,据我所知,AVR没有这样的机制,所以它可能会通过标准

写作更有趣,但它也会吸收阅读

在使用
SBI
的情况下省略读取意味着受影响的SFR必须全部像锁存器一样工作(或者任何不这样工作的位都绑定到0或1),因此编译器可以确定如果它真的进行了访问,它将从中读取什么。如果不是这样,那么编译器至少会有bug。顺便说一下,这也与数据表没有定义从
PORTx
寄存器读取的内容相冲突

写入的执行方式也是不一致的一个原因:结果因编译器的编译方式而异(一个
CBI
SBI
仅影响一位,一个字节写入影响所有位)。因此,编写代码以清除/设置一位可能“起作用”(如不“意外”清除中断标志),或者如果编译器生成真正的R-M-W序列,则可能不起作用

也许这些技术在C标准中是允许的(作为“实现定义”的行为,编译器会推断这些读写对于易失性对象不是必需的),但是至少我会认为它是一种错误的或不一致的实现。 另一个例子:

PORTA = PORTA | (1U << 6);

PORTA=PORTA|(1U您可能应该停止尝试将C内存模型应用于I/O寄存器。它们不是普通内存。对于PORTn寄存器,事实上,无论是单位写入还是R-M-W操作,都是无关的,除非您混入了中断。如果您确实读取修改写入,则中断可能会改变其间的状态,从而导致竞争条件但是对于内存来说,这是完全相同的问题。SBI/CBI指令的优势在于它们是原子指令

PORTn寄存器是可读的,并且还驱动输出缓冲区。它们在读和写上没有不同的功能(如图所示),但为普通寄存器。较新的PIC还具有在LAT地址上可读的输出寄存器,因此您不需要阴影变量。其他SFR(如PINn或中断标志)具有更复杂的行为。在最近的AVR上,写入PINn会切换PORTn中的位,这同样有助于其快速原子操作。写入1s to中断标志寄存器清除它们,a
PORTA = PORTA | (1U << 6);