今天又受教了,在汇编中对于一条指令的计较,代表了更高的性能和更小的 code size,工程师不能仅仅满足于功能的实现,挖掘硬件和编译器的全部潜力才是目标。学无止境~
1,之前讲到SCR1的CPU Timer寄存器是MMIO的,定义为:
#define MEM_MTIME_CTRL 0x00490000
#define MEM_MTIME_DIV 0x00490004
#define MEM_MTIME 0x00490008
#define MEM_MTIMEH 0x0049000C
#define MEM_MTIMECMP 0x00490010
#define MEM_MTIMECMPH 0x00490014
汇编中如下操作:
li t0, MEM_MTIMECMP
sw a1, 4(t0)
sw a2, 0(t0)
编译器转为:
4817e2: 004902b7 lui t0,0x490
4817e6: 01028293 addi t0,t0,16 # 490010 <__tcm_end_vma+0xe3cc>
4817ea: 00b2a223 sw a1,4(t0)
4817ee: 00c2a023 sw a2,0(t0)
而更好的办法是定义为:
#define MMIO_BASE 0x00490000
#define MMIO_MTIME_CTRL 0x00
#define MMIO_MTIME_DIV 0x04
#define MMIO_MTIME 0x08
#define MMIO_MTIMEH 0x0C
#define MMIO_MTIMECMP 0x10
#define MMIO_MTIMECMPH 0x14
代码这样写:
li t0, MMIO_BASE
sw a2, MMIO_MTIMECMP(t0)
sw a1, MMIO_MTIMECMPH(t0)
编译后:
4817da: 004902b7 lui t0,0x490
4817de: 00c2a823 sw a2,16(t0) # 490010 <__tcm_end_vma+0xe3cc>
4817e2: 00b2aa23 sw a1,20(t0)
实现一样的操作,节约了一条指令。
2,gp(global pointer) 应该初始化。理论上官方和很多sample code都对gp register进行了初始化,应该加入。
理论上gp寄存器 赋值为数据段中间地址,编译器可以利用这个地址的正负2k的访问范围 来替换 lui和aupic指令,这样可以节约一条指令
https://gnu-mcu-eclipse.github.io/arch/riscv/programmer/
但实际测试下来,结果不一致,用最新版本编译器看到的结果也是不符合的,但还是建议这样做,一是没有坏处,二是你可以避开因gp无值而导致的硬件异常。
编译器明明知道a0可以用gp+0x420来获取,但它竟然使用两条指令先lui a0,0x2,再加1052来取,也没用gp寄存器。
有可能是设置问题或是编译器问题,如果大家谁知道原因还请赐教。