如何优化C++ avr 代码
How to optimize C++ avr code
要设置或清除寄存器中的位,我使用以下代码:
template<int... pos, class Int>
static constexpr void write_one(Int& i)
{
using expand = int[];
expand{0,((i |= (Int{1} << pos)), 0)...};
}
template<int... pos, class Int>
static constexpr void write_zero(Int& i)
{
using expand = int[];
expand{0,((i &= ~(Int{1} << pos)), 0)...};
}
它工作正常。为了测试其效率,我编写了 2 个测试函数:
// The most efficiency
while(1){
PORTB |= (1 << PB0);
PORTB &= ~(1 << PB0);
}
// This is the one I want to measure
while(1){
Bit::write_one<PB0>(PORTB);
Bit::write_zero<PB0>(PORTB);
}
当我用示波器测量时间时,第二个需要更多时间,所以我分解代码得到以下内容:
; This is the first one (of course, the most efficient)
000000c8 <_Z12testv>:
ce: 28 9a sbi 0x05, 0 ; 5
d0: 28 98 cbi 0x05, 0 ; 5
d2: fd cf rjmp .-6 ; 0xce <_Z12testv+0x6>
; The second one
000000c8 <_Z12testv>:
; The compiler optimize perfectly write_one<PB0>(PORTB)
ce: 28 9a sbi 0x05, 0 ; 5
; but, look what happens with write_zero<PB0>(PORTB)!!!
; Why the compiler can't write "cbi"???
; Here is the problem:
d0: 85 b1 in r24, 0x05 ; 5
d2: 90 e0 ldi r25, 0x00 ; 0
d4: 8e 7f andi r24, 0xFE ; 254
d6: 85 b9 out 0x05, r24 ; 5
d8: fa cf rjmp .-12 ; 0xce <_Z12testv+0x6>
我正在使用带有 -O3 标志的 avr-g++ 4.9.2。
template<int... pos, class Int>
static constexpr void write_one(Int& i)
{
using expand = int[];
expand{0,((i |= (Int{1} << pos)), 0)...};
}
template<int... pos, class Int>
static constexpr void write_zero(Int& i)
{
using expand = int[];
expand{0,((i &= ~(Int{1} << pos)), 0)...};
}
I
Bit::write_one<PB0>(PORTB);
Bit::write_zero<PB0>(PORTB);
int[2] { 0, ((i |= (Int{1} << pos)), 0) }
int[2] { 0, 0 } // a tmp that is a nop
(i |= (Int{1} << pos))
(i |= (decl_type(PORTB){1} << int { PB0 }))
PORTB 看起来像是一个不稳定uint5_t可能的值为 0-31 (AVR(,值为 0x5
(i |= ( uint5_t{1} << int {0}))
1 和 0 是文字/constexpr,所以它给出 1。
i |= 1
哪个代码生成
sbi 0x5, 0 // set port 5 bit 0
expand{0,((i &= ~(Int{1} << pos)), 0)...};
遵循相同的逻辑给出
(i &= ~(1))
给出代码
d0: 85 b1 in r24, 0x05 ; 5
d2: 90 e0 ldi r25, 0x00 ; 0 <---------- this value is not used nor set any flags???
d4: 8e 7f andi r24, 0xFE ; 254 (i &= ~(1))
d6: 85 b9 out 0x05, r24 ; 5
因此,结论必须是 AVR 的代码生成中存在错误,因为它会生成虚假指令。
LDI解释
相关文章:
- 为什么我在 AVR 中的中断无法正常工作?
- 在arduino项目中使用ArduinoCore avr库
- 将 Arduino 库添加到 Atmel Studio 7 AVR C++项目 - 缺少 Arduino.h
- 使用 avr-gcc 隐式转换为浮点数:uint8_t vs. uint16_t
- AVR-GCC:(看似)简单功能中不需要的序言/尾声
- 如何优化C++ avr 代码
- GCC为AVR上的简单ISR产生不必要的寄存器推送
- 定义的参数在以下包含的标头 [AVR C++] 中不可见
- 组合宏定义以一次获得多个定义 [avr C++]
- C++ AVR 上的编译器差异?
- 是否可以为 AVR 编写一个 constexpr 舍入函数?
- 如何导入<chrono>以使用 avr-gcc
- 致命错误: avr/io.h: 没有这样的文件或目录
- 一种避免pgm_read访问闪存的方法(avr 微控制器)
- AVR G++:执行超过 128 Kb ROM 边界的函数
- 为AVR构建编译时间任意长度阵列
- 我的AVR PWM库代码中的错误
- constexpr引用AVR端口地址
- AVR ASM从变量出发到端口
- 如何在AVR(例如:ATMega)或Arduino微控制器上制作2D PROGMEM阵列的1D PROGMEM数组(存储