前言
众所周知,对于原子和同时读取/写入 16 位 I/O 寄存器(定时器计数器、ICR/OCR、ADC...)的高位和低位部分,AVR 使用影子临时寄存器。例如TCNT1
在 ATmega8 上阅读:
uint8_t tl, th;
tl = TCNT1L; // tl <- TCNT1L, avr_temp <- TCNT1H (atomic)
th = TCNT1H; // th <- avr_temp
(这里avr_temp
是 AVR 临时影子寄存器)。因此,TCNT1H
例如,首先阅读是错误的。
问题
将 AVR-GCC 与如下代码一起使用是否安全?
uint16_t ticks;
ticks = TCNT1;
TCNT1 = 0x1234;
AVR-GCC 是否总是为这些操作生成正确的代码?
(似乎是“否”(GCC怎么知道访问指向的内存TCNT1
使用AVR影子寄存器?),但是avr-libc定义宏TCNT1以及TCNT1H、TCNT1L和avr- libc'FAQ建议直接使用TCNT1
。我我很困惑。)
我测试了 AVR-GCC v4.7.2,它似乎总是生成正确的代码。即使我写了 'TCNT1 |= 1' 它也会产生正确的代码-O3
:
$ avr-gcc -std=c99 -mmcu=atmega8 -S -O3 -o - 1.c
...
in r24,0x2c // TCNT1L
in r25,0x2c+1 // TCNT1H
ori r24,1
out 0x2c+1,r25
out 0x2c,r24
...
即使我TCNT1
用普通的 16 位变量进行更改,代码也是一样的。那么,“GCC 怎么知道访问指向的内存TCNT1
使用 AVR 影子寄存器?” -- 默认情况下,似乎在访问任何16 位变量时总是假设影子寄存器。