loongarch架構介紹—基礎指令(一)
前言
最近龍芯中科宣布,龍芯2K0500開發板已與OpenHarmony(開源鴻蒙系統)完成了適配驗證,LoongArch平臺實現初步支持OpenHarmony。本系列文章將對loongarch架構進行介紹。
龍芯架構LoongArch是龍芯中科公司自主設計的一種精簡指令集計算機(RISC)風格的指令系統架構。其分為32位和64位兩個版本,分別稱為LA32架構和LA64架構。本文主要對其中的基礎部分進行介紹。本文中的主要信息來源于龍芯目前公開的資料。
1、指令編碼格式
下圖為龍芯架構的典型指令編碼格式,大部分指令格式都符合這些格式:
上圖中解釋:
- 指令長度固定為32位,無論是LA32還是LA64
- 上圖中共有2R-type、3R-type、2RI8-type等9種編碼格式,其中R表示寄存器,I表示立即數。如2RI8-type表示指令格式中除了操作碼opcode外,還指定了2個寄存器和一個8位的立即數。
2、指令匯編格式
loongarch的指令匯編格式主要包括指令名和操作數這兩部分,其中指令名格式比較特別。loongarch中指令名可以有前綴和后綴字母,前綴字母有:
- V:128位向量指令
- XV:256位向量指令
- F:非向量浮點指令
- VF:128位向量浮點指令
- XVF:256位向量浮點指令
后綴字母有:
- 對于整數類型指令:.B、.H、.W、.D、.BU、.HU、.WU、.DU分別表示有符號字節、有符號半字、有符號字、有符號雙字、無符號字節、無符號半字、無符號字、無符號雙字。其中雙字僅存在于LA64
- 對于浮點類型指令:.H、.S、.D、.W、.L、.WU、.LU分別表示半精度、單精度、雙精度的浮點數,以及有符號字、有符號雙字、無符號字、無符號雙字的整數。其中雙字僅存在于LA64
舉例如下:
- add.w rd, rj, rk: 表示寄存器rj和rk相加,結果寫入rd。無前綴,后綴.w表示操作數據的位數為32位。
- fadd.s fd, fj, fk:表示浮點寄存器fj和fk相加,結果寫入fd。前綴為f,表示為非向量浮點運算指令。后綴為.s,表示操作數據為單精度浮點數。
- mulw.d.wu rd, rj, rk:表示寄存器rj和rk相乘,結果寫入rd。無前綴。該指令有兩個后綴,.d表示rd中結果為雙精度浮點數,.wu表示rj和rk中數據為無符號32位整數。
3、基礎指令介紹
(1)整數運算類
loongarch中有32個通用寄存器,LA32和LA64中分別為32位和64位長度。loongarch中可用這些寄存器執行整數類的指令。
loongarch支持基本的整數運算,有:
- 加減乘除的add、sub、mul、div等指令。如addi.w rd, rj, si12表示將寄存器rj和有符號立即數si12進行32位加法運算,結果寫入rd。
- 邏輯移位、算術移位的sll、srl、sra、rotr等指令。如srl.w rd, rj, rk表示將寄存器rj作邏輯右移rk位,移位結果符號擴展寫入寄存器rd。
- 與或非等操作的and、or、nor、xor、andi、ori等指令。如and rd, rj, rk表示將寄存器rj和rk作位與運算,結果寫入rd。
- slt、sltu、slti、sltui指令用于小于比較。
- 如slt rd, rj, rk表示將寄存器rj和rk視為有符號整數作小于比較,將結果寫入rd。
- 如sltu rd, rj, rk表示將寄存器rj和rk視為無符號整數作小于比較,將結果寫入rd
- lu12i.w、lu32i.d等指令用于立即數連接。如lu12i.w rd, si20表示將20位立即數si20最低位連接上12位的0,然后符合擴展后寫入rd。
- 一些位操作指令,有clo、clz、ctz等指令、用于符號擴展的ext指令等。
- 如ext.w.b rd, rj表示將rj中低8位數據進行符號擴展后寫入rd。
- 如clz.w rd, rj表示從第31位開始計數寄存器rj中連續0的個數,結果寫入rd。
(2)浮點運算類
loongarch中有32個浮點寄存器,在LA32和LA64中均為64位。loongarch中可用這些寄存器進行浮點類指令。
loongarch中支持基本的浮點運算,有:
- 加減乘除相關的fadd、fsub、fmul、fdiv、fmadd、fnmsub等指令。
- 如fadd.s fd, fj, fk表示將浮點寄存器fj和fk進行單精度加法運算,結果寫入fd。
- 如fmsub.d fd, fj, fk, fa表示將浮點寄存器fj和fk進行雙精度乘法運算,然后再與fa進行雙精度減法運算,結果寫入fd。
- 浮點比較運算相關的fcmp.cond指令。其中.cond可以為多種比較含義的助記符。如fcmp.ceq.s cc, fj, fk 表示進行相等比較。
- 浮點轉換類的fcvt、ffint、frint等指令。
- 如fcvt.s.d fd, fj表示將浮點寄存器fj中的雙精度浮點數轉換為單精度,并寫入fd。
- 如ftintrne.w.s fd, fj表示將浮點寄存器fj中的單精度浮點數轉換為32位整數寫入到fd,并采用“向最近的偶數舍入”。
- 浮點搬運類型指令,包括fmov、fsel、movgr2fr等指令。
- 如fsel fd, fj, fk, ca表示如果條件標志寄存器ca的值為0,則將浮點寄存器fj寫入fd,否則將fk寫入fd。
- 如movgr2fr.w fd, rj表示將rj的低32位寫入浮點寄存器fj的低32位。
- 一些特殊浮點運算指令,有取最小/最大值運算的fmax、fmin、fmaxa、fmina指令、取絕對值的fabs指令、取反的fneg指令、開方和倒數運算相關的fsqrt和frecip等指令,等等。如fmaxa.s fd, fj, fk表示fd中寫入浮點寄存器fj、fk中絕對值的較大者。
(3)訪存指令
和一般RISC一樣,loongarch中通過load/store類指令進行訪存,有:
- ld/st指令。
- 如ld.b rd, rj, si12表示將rj+有符號立即數si12作為虛擬地址,從該地址取出一個字節數據寫入rd。
- 如st.w rd, rj, si12表示將rj+有符號立即數si12作為虛擬地址,將rd低32位數據寫入該地址。
- ldx/stx指令。相比ld/st指令,區別是虛擬地址表示不同:如ldx.b rd, rj, rk表示將rj+rk作為虛擬地址,從該地址取出一個字節數據寫入rd。
- ldptr/stptr指令。相比ld/st指令,區別是立即數表示不同,即立即數的最大位數不同以及其表示的偏移以4字節對齊。如stptr.w rd, rj, si14表示將rj+有符號立即數si14*4作為虛擬地址,從該地址取出32位數據寫入rd。
- ldgt/stgt、ldle/stle等邊界檢查訪存指令。如ldgt.b rd, rj, rk表示將rj作為虛擬地址,如果rj大于rk,則從該地址中取出一個字節數據到rd。否則觸發異常。
- 浮點訪存指令,包括fld/fst、fldx/fstx、fldgt/fstgt指令等。與前面指令含義基本一致,只不過是用浮點寄存器作為目標寄存器。如fld.s fd, rj, si12表示將rj+有符號立即數si12作為虛擬地址,從該地址取出一個單精度浮點數數據寫入fd。
(4)轉移指令
下面對loongarch中的轉移指令進行介紹:
- 無條件跳轉指令b。如b offs26表示無條件跳轉到地址pc+offs26*4,其中offs26為26位的立即數偏移量,且4字節對齊。
- 無條件跳轉指令jirl。和b的區別是,會將pc+4的值進行保存。如jirl rd, rj, offs16表示無條件跳轉到地址pc+offs16*4,然后將pc+4寫入rd。其中offs16為16位的立即數偏移量,且4字節對齊。
- 無條件跳轉指令bl。和jirl的區別是,pc+4的值固定保存在r1中。r1別名ra,一般用作保存返回地址。如bl offs26表示無條件跳轉到地址pc+offs26*4,然后將pc+4寫入r1。其中offs26為26位的立即數偏移量,且4字節對齊。
- 條件轉移指令beq、bne、blt等。如beq rj, rd, offs16表示當rj和rd相等時才跳轉到地址pc+offs16*4。
(5)一些補充的基礎指令
在閱讀linux上loongarch架構相關代碼的時候,遇到了一些loongarch資料中沒有寫出來的指令。本小節中將這些指令列出,其中指令的含義是根據上下文推測出來的。
- move:如move rd, rj將rj中值復制到rd。
- li:如li.w rd, 1將rd中值置為1。
- la:如la.abs rd, label將label對應地址賦值給rd。
- jr:如jr ra跳轉到ra中地址,可能會有一些額外的操作。
4、匯編案例說明
上圖中描述了loongarch中寄存器的使用約定,與其他的架構其實大同小異。有棧指針寄存器,有通用和浮點的傳參寄存器,有返回地址寄存器等。下面結合代碼進行說明。
以下為一段c語言代碼:
對應loongarch匯編如下:
loongarch的棧幀可用下圖表示:
總結
本文介紹了loongarch架構中的一些基礎指令,如整數和浮點運算指令、轉移指令、訪存指令,并結合案例對loongarch匯編語言的寫法進行了說明。下一篇文章將會介紹loongarch中的原子指令、柵障指令,及其用法。