riscv amo instructions
riscv amo(Atomic Memory Operation)指令
指令介绍
amo指令主要用作多处理器同步,用来实现自旋锁,位操作。
These AMO instructions atomically load a data value from the address in rs1, place the value into register rd, apply a binary operator to the loaded value and the original value in rs2, then store the result back to the address in rs1.
amo指令从rs1所指向的地址addr中加载一个数据,把数据放到rd中,并把加载的数据和rs2中的数据进行运算,把结果放到rs1指向的addr中。
自旋锁
自旋锁的示例如下:
发现再两个不同版本的手册中,有略微的差别。
较新的版本[2]如下:
- 先在寄存器
t0中放入1(li t0, 1)。 - 然后把
a0地址中的内容放到t1中,a0为锁的地址。 - 比较
t1和0(bnez),如果不为0,说明锁已经被持有,回到again。 - 把
t0(1)放到a0表示的地址中,含义为上锁,把原(a0)放到t1中。 - 同3,检查是否已经上锁了,如果上锁了,跳到again。
- 执行关键区代码。
- 解锁,把
x0(0),的值交给(a0),把(a0)的值交给x0(遗弃)。
较旧版本[3]如下:
更加简洁一些,不知道为什么改掉了。
linux相关实现
bitops.h
分析linux riscv版本的bitops.h[4]。
set_bit函数:
1 | static inline void __set_bit(int nr, volatile unsigned long *addr) |
宏展开为:
1 | __op_bit_ord(or, __NOP, nr, addr, ) |
继续展开为:
1 | __asm__ __volatile__ ( |
其中:
1 | /* flags数组每个元素为64bit,可以表示的flag数量为:数组大小*64 */ |
再看一个test_and_set_bit函数的实现:
1 | static inline int test_and_clear_bit(int nr, volatile unsigned long *addr) |
展开为:
1 | __test_and_op_bit_ord(and, __NOT, nr, addr, .aqrl) |
继续展开为:
1 | unsigned long __res, __mask; |
把addr[BIT_WORD(nr)]旧的值保存在__res中,然后clear
bit(与 ~mask),然后返回旧的值与 __mask。
bit spinlock的实现(简版)
1 | /* |
参考资料
[1] Multithreaded Application Synchronization pt. II (Mutual Exclusion Locks a'la RISC-V)
[2] The RISC-V Instruction Set Manual Volume I: Unprivileged ISA Document Version 20191213
[3] The RISC-V Instruction Set Manual Volume I: User-Level ISA Document Version 2.2