【发布时间】:2012-12-19 04:09:50
【问题描述】:
序言
众所周知,对于原子和同时读取/写入 16 位 I/O 寄存器(定时器计数器、ICR/OCR、ADC...)的高位和低位部分,AVR 使用影子临时寄存器。例如。在 ATmega8 上阅读 TCNT1:
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
...
即使我用普通的 16 位变量更改 TCNT1,代码也是一样的。那么,“GCC 怎么知道访问 TCNT1 指向的内存使用 AVR 影子寄存器?” -- 在访问 any 16 位变量时,默认情况下会假设影子寄存器 always。
【问题讨论】: