隨著國內第一本RISC-V中文書籍《手把手教你設計CPU——RISC-V處理器篇》正式上市,越來越多的愛好者開始使用開源的蜂鳥E203 RISC-V處理核,很多初學者留言詢問有關RISC-V工具鏈使用的問題,因此本公眾號將開始陸續發表若干篇有關RISC-V軟件工具鏈使用的文章,包括:RISC-V嵌入式開發準備篇1:編譯過程簡介RISC-V嵌入式開發準備篇2:嵌入式開發的特點介紹RISC-V嵌入式開發入門篇1:RISC-V GCC工具鏈的介紹RISC-V嵌入式開發入門篇2:RISC-V匯編語言程序設計RISC-V嵌入式開發上手篇:基于HBird-E-SDK平臺的軟件開發與運行RISC-V嵌入式開發實踐篇:運行開源蜂鳥E200 MCU更多示例程序RISC-V嵌入式開發新奇篇:基于Windows Eclipse IDE的軟件開發與運行RISC-V嵌入式開發升華篇:基于開源蜂鳥E200 MCU移植RTOS
本文為RISC-V嵌入式開發入門篇1:RISC-V GCC工具鏈的介紹。
本文的目的是對RISC-V GCC工具鏈進行簡單的中文科普與介紹。
注:本文力求通俗易懂,主要面向初學者,對RISC-V GCC工具鏈有所了解的讀者可以忽略此文。
1 RISC-V GCC工具鏈種類
在本號上次發表的文章《編譯過程簡介》中已經介紹了通用的GCC工具鏈,RISC-V GCC工具鏈與普通的GCC工具鏈基本相同,用戶可以遵照開源的riscv-gnu-toolchain項目(請在Github中搜索riscv-gnu-toolchain)中的說明自行生成全套的GCC工具鏈。
由于GCC工具鏈支持各種不同的處理器架構,因此不同處理器架構的GCC工具鏈會有不同的命名。遵循GCC工具鏈的命名規則,當前RISC-V GCC工具鏈有如下幾個版本:
以“riscv64-unknown-linux-gnu-”為前綴的版本,譬如riscv64-unknown-linux-gnu-gcc、riscv64-unknown-linux-gnu-gdb、riscv64-unknown-linux-gnu-ar等。具體的后綴名稱與《編譯過程簡介》中描述的GCC、GDB和Binutils工具相對應。
“riscv64-unknown-linux-gnu-”前綴表示該版本的工具鏈是64位架構的Linux版本工具鏈。注意:此Linux不是指當前版本工具鏈一定要運行在Linux操作系統的電腦上,此Linux是指該GCC工具鏈會使用Linux的Glibc作為C運行庫,請參見《編譯過程簡介》了解Glibc的更多信息。
同理,“riscv32-unknown-linux-gnu-”前綴的版本則是32位架構。
注意:此處的前綴riscv64(還有riscv32的版本)與運行在64位或者32位電腦上毫無關系,此處的64和32是指如果沒有通過-march和-mabi選項指定RISC-V架構的位寬,默認將會按照64位還是32位的RISC-V架構來編譯程序。有關-march和-mabi選項的含義,請參見第3節。
以“riscv64-unknown-elf-”為前綴的版本,則表示該版本為非Linux(Non-linux)版本的工具鏈。注意:
此Non-Linux不是指當前版本工具鏈一定不能運行在Linux操作系統的電腦上,此Non-Linux是指該GCC工具鏈會使用newlib作為C運行庫,請參見本號上次發表的文章《嵌入式開發特點》中了解newlib的更多信息。
同上理,此處的前綴riscv64(還有riscv32的版本)與運行在64位或者32位電腦上毫無關系,此處的64和32是指如果沒有通過-march和-mabi選項指定RISC-V架構的位寬,默認將會按照64位還是32位的RISC-V架構來編譯程序。有關-march和-mabi選項的含義,請參見第3節。
以“riscv-none-embed-”為前綴的版本,則表示是最新為裸機(bare-metal)嵌入式系統而生成的交叉編譯工具鏈,所謂裸機(bare-metal)是嵌入式領域的一個常見形態,表示不運行操作系統的系統。該版本使用新版本的newlib作為C運行庫,并且支持newlib-nano,能夠為嵌入式系統生成更加優化的代碼體積(Code Size)。開源的蜂鳥E203 MCU系統是典型的嵌入式系統,因此將使用“riscv-none-embed-”為前綴的版本作為RISC-V GCC交叉工具鏈。注意:
此版本編譯器由于使用newlib和newlib-nano作為C運行庫,所以必須對 newlib底層的樁函數進行移植,否則無法正常使用調用底層樁函數的C函數(譬如printf會調用write樁函數)。
關于Newlib和newlib-nano及其樁函數,請參見本號上次發表的文章《嵌入式開發特點》中了解更多信息。
2 riscv-none-embed工具鏈下載
對于riscv-none-embed版本的工具鏈而言,為了方便用戶直接使用預編譯好的工具鏈,Eclipse開源社區會定期更新發布最新版本的預編譯好的RISC-V嵌入式GCC工具鏈,包括Windows版本和Linux版本。請在谷歌中搜索“releases gnu-mcu-eclipse/riscv-none-gcc”進入網頁下載Windows版本或者Linux版本,如圖1中所示。對于Linux和Windows版本均只需在相應的操作系統中解壓即可使用。
圖1 riscv-none-embed工具鏈下載鏈接
3 RISC-V GCC工具鏈的(–march=)和(–mabi=)選項
3.1 (–march=)選項
由于RISC-V的指令集是模塊化的指令集,因此在為目標RISC-V平臺進行交叉編譯之時,需要通過選項指定目標RISC-V平臺所支持的模塊化指令集組合,該選項為(-march=),有效的選項值如下:
rv32i[m][a][f[d]][c]
rv32g[c]
rv64i[m][a][f[d]][c]
rv64g[c]
注意:在上述選項中rv32表示目標平臺是32位架構,rv64表示目標平臺是64位架構,其他i/m/a/f/d/c/g分別代表了RISC-V模塊化指令子集的字母簡稱。請參見RISC-V中文書籍《手把手教你設計CPU——RISC-V處理器篇》中附錄A.1節中關于RISC-V架構指令集的詳細中文介紹。
本節后文會介紹(-march=)選項使用的具體實例。
3.2 (–mabi=)選項
由于RISC-V的指令集是模塊化的指令集,因此在為目標RISC-V平臺進行交叉編譯之時,需要通過選項指定嵌入式RISC-V目標平臺所支持的ABI函數調用規則(有關ABI函數調用規則的相關信息請參見RISC-V中文書籍《手把手教你設計CPU——RISC-V處理器篇》中附錄A的圖A-1)。RISC-V定義了兩種整數的ABI調用規則和三種浮點ABI調用規則,通過選項(-abi=)指明,有效的選項值如下:
ilp32
ilp32f
ilp32d
lp64
lp64f
lp64d
注意:
在上述選項中兩種前綴(ilp32和lp64)表示的含義如下:
前綴ilp32表示目標平臺是32位架構,在此架構下,C語言的“int”和“long”變量長度為32比特,“long long”變量為64位;
前綴lp64表示目標平臺是64位架構,C語言的“int”變量長度為32比特,而“long”變量長度為64比特。
RISC-V的32位和64位架構下更多的數據類型寬度如圖2中所示。
圖2 RISC-V的32位和64位架構下的數據類型寬度
上述選項中的三種后綴類型(無后綴、后綴f、后綴d)表示的含義如下:
無后綴:在此架構下,如果使用了浮點類型的操作,直接使用RISC-V浮點指令進行支持。但是當浮點數作為函數參數進行傳遞之時,無論單精度浮點數還是雙精度浮點數均需要通過存儲器中的堆棧進行傳遞。
f:表示目標平臺支持硬件單精度浮點指令。在此架構下,如果使用了浮點類型的操作,直接使用RISC-V浮點指令進行支持。但是當浮點數作為函數參數進行傳遞之時,單精度浮點數可以直接通過寄存器傳遞,而雙精度浮點數需要通過存儲器中的堆棧進行傳遞。
d:表示目標平臺支持硬件雙精度浮點指令。在此架構下,如果使用了浮點類型的操作,直接使用RISC-V浮點指令進行支持。當浮點數作為函數參數進行傳遞之時,無論單精度還是雙精度浮點數都可以直接通過寄存器傳遞。
本節后文會介紹(-mabi=)選項使用的具體實例。
3.3 (–march=)和(–mabi=)不同選項編譯實例
為了便于讀者更加形象地理解(-march=)和(-mabi=)選項的具體含義,下面以一個實例加以介紹。
假設有一段C語言函數代碼,如下所示:
//這是一個名為dmul的函數,其有兩個參數,為double類型的雙精度浮點數 double dmul(double a, double b) { return b * a; }
如果使用-march=rv64imafdc -mabi=lp64d的選項組合進行編譯,則會生成如下匯編代碼:
$ riscv64-unknown-elf-gcc test.c -march=rv64imafdc -mabi=lp64d -o- -S -O3//所生成的匯編代碼如下,從中可以看出,浮點數乘法操作直接使用了RISC-V的fmul.d指令進行支持,且函數的兩個double類型的參數直接使用浮點通用寄存器fa0和fa1進行傳遞。這是因為:- -march選項指明了目標平臺支持的模塊化指令子集為imafdc,其中包含了F和D指令子集,即支持單精度和雙精度浮點指令,因此可以直接使用RISC-V的浮點指令來支持浮點數的操作。- -mabi選項指明了后綴“d”,表示當浮點數作為函數參數進行傳遞之時,無論單精度還是雙精度浮點數都可以直接通過寄存器傳遞。 dmul: fmul.d fa0,fa0,fa1 ret
如果使用-march=rv32imac -mabi=ilp32的選項組合進行編譯,則會生成如下匯編代碼:
$ riscv64-unknown-elf-gcc test.c -march=rv32imac -mabi=ilp32 -o- -S -O3//所生成的匯編代碼如下,從中可以看出,浮點數乘法操作由C庫函數(__muldf3)進行支持,這是因為:- -march選項指明了目標平臺支持的模塊化指令子集為I/M/A/C,其中未包含了F和D指令子集,即不支持單精度和雙精度浮點指令,因此無法直接使用RISC-V的浮點指令來支持浮點數的操作。 dmul: mv a4,a2 mv a5,a3 add sp,sp,-16 mv a2,a0 mv a3,a1 mv a0,a4 mv a1,a5 sw ra,12(sp) call __muldf3 lw ra,12(sp) add sp,sp,16 jr ra
如果使用-march=rv32imafdc -mabi=ilp32的選項組合進行編譯,則會生成如下匯編代碼:
$ riscv64-unknown-elf-gcc test.c -march=rv32imafdc -mabi=ilp32 -o- -S -O3//所生成的匯編代碼如下,從中可以看出,浮點數乘法操作直接使用了RISC-V的fmul.d指令進行支持,但是函數的兩個浮點類型的參數均通過堆棧進行的傳遞,這是因為:- -march選項指明了目標平臺支持的模塊化指令子集為I/M/A/F/D/C,其中包含了F和D指令子集,即支持單精度和雙精度浮點指令,因此可以直接使用RISC-V的浮點指令來支持浮點數的操作。- -mabi選項指明了“無后綴”,表示當浮點數作為函數參數進行傳遞之時,無論單精度還是雙精度浮點數都需要通過堆棧進行傳遞。 dmul: add sp,sp,-16 //對堆棧指針寄存器(sp)進行調整,分配堆棧空間 sw a0,8(sp) //將函數參數寄存器a0中的值存入堆棧 sw a1,12(sp) //將函數參數寄存器a1中的值存入堆棧 fld fa5,8(sp) //從堆棧中取回雙精度浮點操作數 sw a2,8(sp) //將函數參數寄存器a2中的值存入堆棧 sw a3,12(sp) //將函數參數寄存器a3中的值存入堆棧 fld fa4,8(sp) //從堆棧中取回雙精度浮點操作數 fmul.d fa5,fa5,fa4 //調用RISC-V的浮點指令進行運算 fsd fa5,8(sp) //將計算結果存回堆棧 lw a0,8(sp) //通過堆棧將結果賦值給函數結果返回寄存器a0 lw a1,12(sp) //通過堆棧將結果賦值給函數結果返回寄存器a1 add sp,sp,16 //對堆棧指針寄存器(sp)進行調整,回收堆棧空間 jr ra
如果使用-march=rv32imac -mabi=ilp32d的選項組合進行編譯,則會報非法錯誤:
$ riscv64-unknown-elf-gcc test.c -march=rv32imac -mabi=ilp32d -o- -S -O3cc1: error: requested ABI requires -march to subsume the 'D' extension//從中可以看出報非法錯誤,這是因為:- -march選項指明了目標平臺支持的模塊化指令子集為I/M/A/C,其中未包含了F和D指令子集,即不支持單精度和雙精度浮點指令,因此無法直接使用RISC-V的浮點指令來支持浮點數的操作。- -mabi選項指明了后綴“d”,表示目標平臺支持硬件浮點指令。這一點與-march選項中指明的指令集子集產生了沖突。
3.4 (–march=)和(–mabi=)選項合法組合
雖然(–march=)和(–mabi=)選項理論上可以組成很多種不同的組合,但是目前并不是所有的(–march=)和(–mabi=)選項組合都是合法,目前的riscv-none-embed工具所支持的組合如下:
march=rv32i/mabi=ilp32
march=rv32ic/mabi=ilp32
march=rv32im/mabi=ilp32
march=rv32imc/mabi=ilp32
march=rv32iac/mabi=ilp32
march=rv32imac/mabi=ilp32
march=rv32imaf/mabi=ilp32f
march=rv32imafc/mabi=ilp32f
march=rv32imafdc/mabi=ilp32f
march=rv32gc/mabi=ilp32f
march=rv64imac/mabi=lp64
march=rv64imafdc/mabi=lp64d
march=rv64gc/mabi=lp64d
注意:上述有效組合來自于本文撰寫時的信息。隨著時間推移,新發布的riscv-none-embed工具可能會支持更多的組合,請讀者以其最新的發布說明(Release Notes)為準。
4 RISC-V GCC工具鏈的(–mcmodel=)選項
目前RISC-V GCC工具鏈認為,在實際的情形中,一個程序的大小一般不會超過4GB的大小,因此在程序內部的尋址空間不能超過4GB的空間。而在64位的架構中,地址空間的大小遠遠的大于4GB的空間,因此針對RV64架構而言,RISC-V GCC工具鏈定義了(–mcmodel=)選項用于指定尋址范圍的模式,使得編譯器在編譯階段能夠按照相應的策略編譯生成代碼。其有效的選項值如下:
-mcmodel=medlow
-mcmodel=medany
注意:
在RV32架構中,整個地址空間的大小就是4GB,因此(–mcmodel=)選項的任何值對于編譯的結果都無影響。
RISC-V GCC工具鏈在未來可能也會支持大于4GB的尋址空間。
medlow和medany兩個選項的含義分別解釋如下。
(-mcmodel=medlow)選項
(-mcmodel==medlow)選項用于指示該程序的尋址范圍固定只能在-2GB至+2GB的空間內。注意:地址區間沒有負數可言,-2GB是指整個64位地址空間最高2GB地址區間。由于此模式的尋址空間是固定的-2GB至+2GB的空間內,因此編譯器能夠相對生成比較高效的代碼,但是由于尋址空間固定,對于整個64位的大多數地址空間都無法訪問到,用戶需小心使用。
(-mcmodel=medany)選項
(-mcmodel==medlow)選項用于指示該程序的尋址范圍可以在任意的一個4G空間內。由于此模式的尋址空間不是固定的,所以相對比較靈活。
5 RISC-V GCC工具鏈的其他選項
本章僅介紹了RISC-V GCC工具鏈幾個特別的選項,有關RISC-V GCC工具鏈的完整選項列表和解釋,感興趣的讀者可以在谷歌輸入“gcc/RISC-V-Options”關鍵字進行搜索進入相關網頁查詢,如圖3中所示。
圖3 RISC-V GCC工具鏈的完整選項列表和解釋
6 RISC-V GCC工具鏈的預定義宏
RISC-V GCC會根據編譯生成若干預定義的宏,在Linux操作環境中可以使用如下方法查看和RISC-V相關的宏:
//首先創建一個空文件touch empty.h//使用RISC-V GCC的-E選項對empty.h進行預處理,有關“預處理”的背景知識請參見本號文章《編譯過程簡介》//通過grep命令對于處理后的文件搜索riscv的關鍵字//如果使用-march=rv32imac -mabi=ilp32選項可以看出生成如下預定義宏riscv-none-embed-gcc -march=rv32imac -mabi=ilp32 -E -dM empty.h | grep riscv#define __riscv 1#define __riscv_atomic 1#define __riscv_cmodel_medlow 1#define __riscv_float_abi_soft 1#define __riscv_compressed 1#define __riscv_mul 1#define __riscv_muldiv 1#define __riscv_xlen 32#define __riscv_div 1//如果使用-march=rv32imafdc -mabi=ilp32f選項可以看出生成如下預定義宏riscv-none-embed-gcc -march=rv32imafdc -mabi=ilp32f -E -dM empty.h | grep riscv #define __riscv 1#define __riscv_atomic 1#define __riscv_cmodel_medlow 1#define __riscv_float_abi_single 1#define __riscv_fdiv 1#define __riscv_flen 64#define __riscv_compressed 1#define __riscv_mul 1#define __riscv_muldiv 1#define __riscv_xlen 32#define __riscv_fsqrt 1#define __riscv_div 1
7 RISC-V GCC工具鏈使用實例
本號后續發文《基于HBird-E-SDK平臺的軟件開發與運行》將結合HBird-E-SDK平臺的實例了解如何使用RISC-V GCC工具鏈進行嵌入式程序的開發與編譯。
-
嵌入式開發
+關注
關注
18文章
1028瀏覽量
47563 -
RISC-V
+關注
關注
45文章
2270瀏覽量
46129
原文標題:RISC-V嵌入式開發入門篇1:RISC-V GCC工具鏈的介紹
文章出處:【微信號:real_farmer,微信公眾號:硅農亞歷山大】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論