RV32FD指令集
Risc-V架構定義了可選的單精度浮點指令(F擴充套件指令集)和雙精度浮點指令(D擴充套件指令集)。
Risc-V架構規定:處理器可以選擇只實現F擴充套件指令子集而不支援D擴充套件指令子集;但是如果支援了D擴充套件指令子集,則必須支援F擴充套件指令子集。
Risc-V架構規定的浮點數符合IEEE754 2008規則,可以從下面的連結瞭解浮點數格式的詳細資訊:
ofollow,noindex" target="_blank"> https://www.cnblogs.com/german-iris/p/5759557.html
Risc-V規定,如果支援單精度浮點指令或者雙精度浮點指令,則需要增加一組獨立的通用浮點暫存器組,包括32個通用浮點暫存器,標號位f0到f31。如果僅支援F擴充套件指令子集,則每個通用暫存器是32位的,如果支援D擴充套件那指令子集,則每個通用暫存器是64位的。
Risc-V架構規定,如果支援單精度浮點指令或者雙精度浮點指令,需要增加一個浮點控制狀態暫存器fcsr,該暫存器是一個可讀可寫的csr暫存器。
fcsr暫存器包含浮點異常標誌域(fflags),不同的標誌位表示不同的異常型別。如果浮點運算單元在運算中出現了相應的異常,則會將fcsr暫存器中對應的標誌位設定為1,且會一直保持累積。軟體可以通過寫0的方式單獨清除某個異常標誌位。
根據IEEE-754標準,浮點運算需要指定舍入模式(rounding mode),Risc-V架構浮點運算的舍入模式可以通過兩種方式指定。
使用靜態舍入模式,浮點指令編碼中有3位作為舍入模式域,不同的舍入模式編碼如下圖,Risc-V支援5種合法的舍入模式。如果舍入模式編碼為101或110,則為非法模式;如果舍入模式編碼為111,則意味著使用動態舍入模式。如果使用動態舍入模式,則使用fcsr暫存器中的舍入模式域,舍入模式域定義如上圖,如果fcsr暫存器中的舍入模式域指定為非法的舍入模式,則後續浮點指令會產生非法指令異常。
如果處理器不想使用浮點單元,比如把浮點單元關電以節省功耗,可以使用csr寫指令將mstatus暫存器的FS域設定成0,將浮點單元的功能予以關閉。當浮點單元功能關閉後,任何訪問浮點csr暫存器的操作或者執行浮點指令的行為將會產生非法指令異常。
Risc-V規定,對於非規格化數(subnormal Numbers)的處理完全遵循IEEE754定義。
根據IEEE-754標準,在浮點數的表示中,有一類特殊編碼資料屬於NaN(not a number)型別,且NaN分為Signaling-NaN和Quiet-NAN。
Risc-V架構規定,如果浮點運算的結果是一個NaN數,那麼使用一個固定的NaN數,將之命名為Canonical-NaN。單精度浮點對應的Canonical-NaN數值為0x7fc00000,雙精度浮點對應Canonical-NaN數值為0x7ff80000_00000000
如果同時支援單精度浮點(F擴充套件指令子集)和雙精度浮點(D擴充套件指令子集),由於浮點通用暫存器的寬度為64位,Risc-V架構規定單精度浮點指令產生的32位結果寫入浮點通用暫存器(64位)時,將結果寫入低32位,而高位全部寫入數值1,RiscV架構規定此種做法稱之為NaN-Boxing。NaN-boxing可以發生在如下情形:
對於單精度浮點數的讀(Load)/寫(store)指令和傳送(Move)指令(包括FLW,FSW,FMV.W.X,FMV.X.W),如果需要將32位的數值寫入通用浮點暫存器,則採用NaN-boxing的方式;如果需要將浮點通用暫存器中的數值讀出,則僅使用其低32位值。
對於單精度浮點運算(compute)和符號注入(sign-injection)指令,需要判斷其運算元浮點暫存器中的值是否為合法的NaN-Boxed值,即高位都是1,如果是,則正常使用其低32位,如果不是,則將此運算元當作Canonical-NaN來使用。
對於整數至單精度的浮點轉化指令(比如FCVT.S.X),則採用NaN-boxing的方式寫回浮點通用暫存器。對於單精度浮點至整數的轉化指令(比如FCVT.X.S),需要判斷其運算元浮點暫存器中的值是否為合法的NaN-boxed值(即高位都為1)。如果是,則正常使用其低32位,如果不是,則將此運算元當作Canonical-NaN來使用。
RV32FM主要包括以下指令:
Category | Fmt | RV32F | machine code(bin) | comment | float read/write instruction | flw rd offset[11:0](RS1) | [31-20, imm[11:0]][19-15,rs1]010[11-7, rd]‘0000111 | rd=mem[rs1+offset], offset是一個12位符號數,所以加法操作時候,需要符號位擴充套件。flw指令從儲存器中讀回一個單精度浮點數,寫回暫存器rd。 | fsw rd2 offset[11:0](RS1) | [31-25, imm[11:5]][24-20,rs2][19-15,rs1]010[11-7, imm[4:0]]‘0100111 | mem[rs1+offset]=rd2, offset是一個12位符號數,所以加法操作時候,需要符號位擴充套件。Fsw指令將運算元暫存器rs2中的單精度浮點數寫回儲存器中。 | fld rd offset[11:0](RS1) | [31-20, imm[11:0]][19-15,rs1]011[11-7, rd]‘0000111 | rd=mem[rs1+offset], offset是一個12位符號數,所以加法操作時候,需要符號位擴充套件。flw指令從儲存器中讀回一個雙精度浮點數,寫回暫存器rd。 | fsd rd2 offset[11:0](RS1) | [31-25, imm[11:5]][24-20,rs2][19-15,rs1]011[11-7, imm[4:0]]‘0100111 | mem[rs1+offset]=rd2, offset是一個12位符號數,所以加法操作時候,需要符號位擴充套件。Fsw指令將運算元暫存器rs2中的雙精度浮點數寫回儲存器中。 | float compute instruciton | fadd.s rd, rs1, rs2 | 0000000[24-20,rs2][19-15,rs1][14-12,rm][11-7,rd]‘1010011 | 將運算元暫存器rs1和rs2中的單精度浮點數進行加法操作,結果返回rd | fsub.s rd, rs1, rs2 | 0000100[24-20,rs2][19-15,rs1][14-12,rm][11-7,rd]‘1010011 | 將運算元暫存器rs1和rs2中的單精度浮點數進行減法操作,結果返回rd | fmul.s rd, rs1, rs2 | 0001000[24-20,rs2][19-15,rs1][14-12,rm][11-7,rd]‘1010011 | 將運算元暫存器rs1和rs2中的單精度浮點數進行乘法操作,結果返回rd | fdiv.s rd, rs1, rs2 | 0001100[24-20,rs2][19-15,rs1][14-12,rm][11-7,rd]‘1010011 | 將運算元暫存器rs1和rs2中的單精度浮點數進行除法操作,結果返回rd | fsqrt.s rd, rs1 | 010110000000[19-15,rs1][14-12,rm][11-7,rd]‘1010011 | 將運算元暫存器rs1和rs2中的單精度浮點數進行平方根操作,結果返回rd | fadd.d rd, rs1, rs2 | 0000001[24-20,rs2][19-15,rs1][14-12,rm][11-7,rd]‘1010011 | 將運算元暫存器rs1和rs2中的雙精度浮點數進行加法操作,結果返回rd | fsub.d rd, rs1, rs2 | 0000101[24-20,rs2][19-15,rs1][14-12,rm][11-7,rd]‘1010011 | 將運算元暫存器rs1和rs2中的雙精度浮點數進行加法操作,結果返回rd | fmul.d rd, rs1, rs2 | 0001001[24-20,rs2][19-15,rs1][14-12,rm][11-7,rd]‘1010011 | 將運算元暫存器rs1和rs2中的雙精度浮點數進行加法操作,結果返回rd | fdiv.d rd, rs1, rs2 | 0001101[24-20,rs2][19-15,rs1][14-12,rm][11-7,rd]‘1010011 | 將運算元暫存器rs1和rs2中的雙精度浮點數進行加法操作,結果返回rd | fsqrt.d rd, rs1 | 010110100000[19-15,rs1][14-12,rm][11-7,rd]‘1010011 | 將運算元暫存器rs1和rs2中的雙精度浮點數進行平方根操作,結果返回rd | min/max | fmin.s rd, rs1, rs2 | 0010100[24-20,rs2][19-15,rs1]000[11-7,rd]‘1010011 | 將運算元暫存器rs1和rs2中的單精度浮點數進行比較操作,將數字小的一方寫回rd | fmax.s rd, rs1, rs2 | 0010100[24-20,rs2][19-15,rs1]001[11-7,rd]‘1010011 | 將運算元暫存器rs1和rs2中的單精度浮點數進行比較操作,將數字大的一方寫回rd | fmin.d rd, rs1, rs2 | 0010101[24-20,rs2][19-15,rs1]000[11-7,rd]‘1010011 | 將運算元暫存器rs1和rs2中的雙精度浮點數進行比較操作,將數字小的一方寫回rd | fmax.d rd, rs1, rs2 | 0010101[24-20,rs2][19-15,rs1]001[11-7,rd]‘1010011 | 將運算元暫存器rs1和rs2中的雙精度浮點數進行比較操作,將數字大的一方寫回rd | 乘加指令 | fmadd.s rd, rs1, rs2, rs3 | [31-27, rs3]00[24-20,rs2][19-15,rs1][14-12,rm][11-7,rd]‘1000011 | 將運算元暫存器rs1,rs2和rs3中的單精度浮點數進行rd=rs1*rs2+r3操作 | fmsub.s rd, rs1, rs2, rs3 | [31-27, rs3]00[24-20,rs2][19-15,rs1][14-12,rm][11-7,rd]‘1000111 | 將運算元暫存器rs1,rs2和rs3中的單精度浮點數進行rd=rs1*rs2-r3操作 | fnmadd.s rd, rs1, rs2, rs3 | [31-27, rs3]00[24-20,rs2][19-15,rs1][14-12,rm][11-7,rd]‘1001011 | 將運算元暫存器rs1,rs2和rs3中的單精度浮點數進行rd=-rs1*rs2-r3操作 | fnmsub.s rd, rs1, rs2, rs3 | [31-27, rs3]00[24-20,rs2][19-15,rs1][14-12,rm][11-7,rd]‘1001111 | 將運算元暫存器rs1,rs2和rs3中的單精度浮點數進行rd=-rs1*rs2+r3操作 | fmadd.d rd, rs1, rs2, rs3 | [31-27, rs3]01[24-20,rs2][19-15,rs1][14-12,rm][11-7,rd]‘1000011 | 將運算元暫存器rs1,rs2和rs3中的雙精度浮點數進行rd=rs1*rs2+r3操作 | fmsub.d rd, rs1, rs2, rs3 | [31-27, rs3]01[24-20,rs2][19-15,rs1][14-12,rm][11-7,rd]‘1000111 | 將運算元暫存器rs1,rs2和rs3中的雙精度浮點數進行rd=rs1*rs2-r3操作 | fnmadd.d rd, rs1, rs2, rs3 | [31-27, rs3]01[24-20,rs2][19-15,rs1][14-12,rm][11-7,rd]‘1001011 | 將運算元暫存器rs1,rs2和rs3中的雙精度浮點數進行rd=-rs1*rs2-r3操作 | fnmsub.d rd, rs1, rs2, rs3 | [31-27, rs3]01[24-20,rs2][19-15,rs1][14-12,rm][11-7,rd]‘1001111 | 將運算元暫存器rs1,rs2和rs3中的雙精度浮點數進行rd=-rs1*rs2+r3操作 | 浮點數格式轉化指令 | fcvt.w.s rd, rs1 | 110000000000[19-15,rs1][14-12,rm][11-7,rd]‘1010011 | 將通用浮點暫存器rs1中的單精度浮點數轉化成有符號整數,寫入rd | fcvt.s.w rd, rs1 | 110100000000[19-15,rs1][14-12,rm][11-7,rd]‘1010011 | 將通用整數暫存器rs1中的有符號整數轉化成單精度浮點數,寫入rd | fcvt.uw.s rd, rs1 | 110000000001[19-15,rs1][14-12,rm][11-7,rd]‘1010011 | 將通用浮點暫存器rs1中的單精度浮點數轉化成無符號整數,寫入rd | fcvt.s.uw rd, rs1 | 110100000001[19-15,rs1][14-12,rm][11-7,rd]‘1010011 | 將通用整數暫存器rs1中的無符號整數轉化成單精度浮點數,寫入rd | fcvt.w.d rd, rs1 | 110000100000[19-15,rs1][14-12,rm][11-7,rd]‘1010011 | 將通用浮點暫存器rs1中的雙精度浮點數轉化成有符號整數,寫入rd | fcvt.d.w rd, rs1 | 110100100000[19-15,rs1][14-12,rm][11-7,rd]‘1010011 | 將通用整數暫存器rs1中的有符號整數轉化成雙精度浮點數,寫入rd | fcvt.uw.d rd, rs1 | 110000100001[19-15,rs1][14-12,rm][11-7,rd]‘1010011 | 將通用浮點暫存器rs1中的雙精度浮點數轉化成無符號整數,寫入rd | fcvt.d.uw rd, rs1 | 110100100001[19-15,rs1][14-12,rm][11-7,rd]‘1010011 | 將通用整數暫存器rs1中的無符號整數轉化成雙精度浮點數,寫入rd | fct.s.d rd, rs1 | 010000000001[19-15,rs1][14-12,rm][11-7,rd]‘1010011 | 將通用浮點暫存器rs1中的雙精度浮點數轉化成單精度浮點數,寫入rd | fct.d.s rd, rs1 | 010000100001[19-15,rs1][14-12,rm][11-7,rd]‘1010011 | 將通用浮點暫存器rs1中的單精度浮點數轉化成雙精度浮點數,寫入rd | 浮點數符號注入指令 | fsgnj.s rd, rs1, rs2 | 0010000[24-20,rs2][19-15,rs1]000[11-7,rd]‘1010011 | 運算元均為單精度浮點數,結果的符號位來自rs2,其它位來自rs1,結果寫回rd | fsgnjn.s rd, rs1, rs2 | 0010000[24-20,rs2][19-15,rs1]001[11-7,rd]‘1010011 | 運算元均為單精度浮點數,結果的符號位來自rs2符號取反,其它位來自rs1,結果寫回rd | fsgnjx.s rd, rs1, rs2 | 0010000[24-20,rs2][19-15,rs1]010[11-7,rd]‘1010011 | 運算元均為單精度浮點數,結果的符號位來自rs2符號與rs1符號xor操作,其它位來自rs1,結果寫回rd | fsgnj.d rd, rs1, rs2 | 0010001[24-20,rs2][19-15,rs1]000[11-7,rd]‘1010011 | 運算元均為雙精度浮點數,結果的符號位來自rs2,其它位來自rs1,結果寫回rd | fsgnjn.d rd, rs1, rs2 | 0010001[24-20,rs2][19-15,rs1]001[11-7,rd]‘1010011 | 運算元均為雙精度浮點數,結果的符號位來自rs2符號取反,其它位來自rs1,結果寫回rd | fsgnjx.d rd, rs1, rs2 | 0010001[24-20,rs2][19-15,rs1]010[11-7,rd]‘1010011 | 運算元均為雙精度浮點數,結果的符號位來自rs2符號與rs1符號xor操作,其它位來自rs1,結果寫回rd | 浮點與整數互搬指令 | fmv.x.w rd, rs1 | 111000000000[19-15,rs1]000[11-7,rd]‘1010011 | 將通用浮點暫存器中的rs1讀出,寫回通用整數暫存器rd中。 | fmv.w.x rd, rs1 | 111100000000[19-15,rs1]000[11-7,rd]‘1010011 | 將通用整數暫存器中的rs1讀出,寫回通用浮點暫存器rd中。 | 浮點數比較指令 | flt.s rd, rs1, rs2 | 1010000[24-20,rs2][19-15,rs1]001[11-7,rd]‘1010011 | 如果通用浮點暫存器rs1中的單精度值小於rs2中的值,則結果為1,否則為0,結果寫回整數暫存器rd | fle.s rd, rs1, rs2 | 1010000[24-20,rs2][19-15,rs1]000[11-7,rd]‘1010011 | 如果通用浮點暫存器rs1中的單精度值小於等於rs2中的值,則結果為1,否則為0,結果寫回整數暫存器rd | feq.s rd, rs1, rs2 | 1010000[24-20,rs2][19-15,rs1]010[11-7,rd]‘1010011 | 如果通用浮點暫存器rs1中的單精度值等於rs2中的值,則結果為1,否則為0,結果寫回整數暫存器rd | flt.d rd, rs1, rs2 | 1010001[24-20,rs2][19-15,rs1]001[11-7,rd]‘1010011 | 如果通用浮點暫存器rs1中的雙精度值小於rs2中的值,則結果為1,否則為0,結果寫回整數暫存器rd | fle.d rd, rs1, rs2 | 1010001[24-20,rs2][19-15,rs1]000[11-7,rd]‘1010011 | 如果通用浮點暫存器rs1中的雙精度值小於等於rs2中的值,則結果為1,否則為0,結果寫回整數暫存器rd | feq.d rd, rs1, rs2 | 1010001[24-20,rs2][19-15,rs1]001[11-7,rd]‘1010011 | 如果通用浮點暫存器rs1中的雙精度值等於rs2中的值,則結果為1,否則為0,結果寫回整數暫存器rd | 浮點數分類指令 | fclass.s rd, rs1 | 111000000000[19-15,rs1]010[11-7,rd]‘1010011 | 對通用浮點暫存器rs1中的單精度浮點數進行判斷,根據其所屬的型別,生成一個10位的獨熱碼(one-hot)結果,結果的每一位對應一種型別。 | fclass.d rd, rs1 | 111000100000[19-15,rs1]010[11-7,rd]‘1010011 | 對通用浮點暫存器rs1中的雙精度浮點數進行判斷,根據其所屬的型別,生成一個10位的獨熱碼(one-hot)結果,結果的每一位對應一種型別。 |
對於FMAX和FMIN指令,注意一下特殊情況:
1. 如果指令的兩個運算元都是NaN,那麼結果為Canonical-NaN。
2. 如果只有一個運算元位NaN,則結果為非NaN的另外一個運算元。
3. 如果任意一個運算元屬於Signaling-NaN,則需要在fcsr暫存器中產生NV異常標誌。
4. 由於浮點數可以表示兩個0值,分別是-0.0和+0.0,對於FMAX和FMIN指令而言,-0.0被認為比+0.0小。
由於浮點數的表示範圍遠遠大於整數的表示範圍,且浮點數存在某些特殊的型別(無窮大或者NaN),因此將浮點數換成整數的過程中存在諸多特殊情況,將其轉化成整數的過程如下圖所示:
浮點分類指令的分類結果(10位的獨熱碼):