RISC-V 把原子指令劃分成單獨的指令擴展,命名為 'A'。該擴展中主要包含兩部分,一個 LR/SC 指令,即Load-Reserved/Store-Conditional,另外一個是 AMO 指令,RV32A 有兩種類型的原子操作:
-
內(nèi)存原子操作(AMO)
-
加載保留/條件存儲(load reserved / store conditional)
內(nèi)存原子操作(AMO)
AMO是強大的“讀改寫”指令,該操作加載rs1指向的存儲器位置的內(nèi)容,并將其存儲在寄存器 rd 中,然后與rs2中的值進行二進制運算,并將結(jié)果保存回rd中,然后再寫到rs1指向的存儲器位置。
為什么要amo指令?
AMO指令要求整個讀出,計算,寫回必須為原子性質(zhì),就是讀出和寫回之間,該存儲器地址不能被其它進程訪問,通??偩€會鎖定,這樣就支持多核SoC系統(tǒng)。雖然 RISC-V B位操作擴展支持一系列復(fù)雜的位控制指令,但Atomic擴展并不只是針對多處理器系統(tǒng),它還有助于那些必要的位操作需求比較簡單的嵌入式系統(tǒng),從而精簡軟件指令代碼。
AMO自旋鎖的示例如下:
-
先在寄存器t0中放入1(li t0, 1)。
-
load加載a0地址中的內(nèi)容到t1中,a0為鎖的地址。
-
比較t1和0(bnez),t1不等于0則跳轉(zhuǎn)到again,t1不等于0說明鎖已經(jīng)被持有。
-
把t0(1)放到a0表示的地址中,含義為上鎖,把a0處的原值放到t1中。
-
比較t1和0(bnez),t1不等于0則跳轉(zhuǎn)到again,t1不等于0說明鎖已經(jīng)被持有。
-
執(zhí)行關(guān)鍵區(qū)Critical section代碼。
-
解鎖,把x0(0)的值賦給(a0),把(a0)的值交給x0(丟棄)。注意,RISC-V架構(gòu)規(guī)定x0固定為0值。
再次申明,AMO指令要求整個讀出,計算,寫回必須為原子性質(zhì),就是讀出和寫回之間,該存儲器地址不能被其它進程訪問,通??偩€會鎖定。AMO指令也可以支持釋放一致性模型,可以通過指令中的aq/rl位,來設(shè)置獲取或釋放屬性。
另外還提供 AMO 指令的原因是,它們在多處理器系統(tǒng)中擁有比加載保留/條件存儲更好的可擴展性,例如可以用它們來實現(xiàn)高效的歸約。AMO 指令在于 I/O 設(shè)備通信時也很有用,可以實現(xiàn)總線事務(wù)的原子讀寫。這種原子性可以簡化設(shè)備驅(qū)動,并提高 I/O 性能。
LR/SC指令
雖然原子操作能解決多線程的競爭問題,但由于會將總線鎖住,導(dǎo)致其他核無法訪問總線,在核數(shù)眾多且頻發(fā)搶鎖的情況下,會造成總線長期被鎖的情況,因此引入一種新的互斥類型的存儲器訪問指令,即LR(load reserved)/SC(store conditional)指令。LR指令是Load Reserved的縮寫,讀取保留;SC指令是Store Conditional 的縮寫,條件存儲,即load reserved/store conditional。
LR指令是從內(nèi)存地址rs1中加載內(nèi)容到rd寄存器。然后在rs1對應(yīng)地址上設(shè)置保留標記(reservation set)。
SC指令在把rs2值寫到rs1地址之前,會先判斷rs1內(nèi)存地址是否有設(shè)置保留標記,如果設(shè)置了,則把rs2值正常寫入到rs1內(nèi)存地址里,并把rd寄存器設(shè)置成 0,表示保存成功。如果rs1內(nèi)存地址沒有設(shè)置保留標記,則不保存,并把rd寄存器設(shè)置成1表示保存失敗。不管成功還是失敗,SC指令都會把當前hart 保留的所有保留標記全部清除。一個例子如下:
-
加載舊的值
-
比較舊的值與 a1 是否相等
-
相等則存入新的值
-
如果存入失敗,重新嘗試
-
…比較-交換成功之后的代碼…
-
比較-交換不成功