NDS32 程式設計指南
綱要
工具鏈
NDS32 組合語言語法
指引指令 (提供組譯器)
假指令 (機械碼)
巨集
行內組合語言
C 和 易變(volatile)的關鍵字
綱要
工具鏈
NDS32 組合語言語法
指引指令 (提供組譯器)
假指令 (機械碼)
巨集
行內組合語言
C 和 易變的關鍵字
工具鏈
環境變數 $PATH
新增nds32-elf-as 和其他 GNU 工具鏈執行檔的路徑至環境變數
$PATH 變數值
• PATH=/home/users/yourdir/bin:$PATH
c/c++ 編譯器
nds32-elf-gcc
組譯器
nds32-elf-as
連結器
nds32-elf-ld
編譯器選項
用法: nds32-elf-gcc [選項] 檔名...
選項:
-Wa,<選項> :傳送以逗號分隔的<選項>給組譯器
-Wp,<選項> :傳送以逗號分隔的<選項>給前置處理器
-Wl,<選項> :傳送以逗號分隔的<選項>給連結器
-Xassembler <arg> :傳送參數 <arg>給組譯器
-Xpreprocessor <arg>:傳送參數 <arg>給前置處理器
-Xlinker <arg>:傳送參數 <arg>給連結器
-E 只作前置處理; 不會編譯、組譯或連結
-S 只用編譯; 不會組譯或連結
-c 編譯和組譯,但是不會連結
-o <檔案名稱> 指定輸出檔案名稱>
-B <目錄> 加入 <目錄> 讓編譯器搜尋路徑
編譯器選項
選項:
-x <language> 指定輸入文件使用的程式語言,可用的語言為:C、
C++、Assembler,若無指定語言則恢復預設操作,以檔案副檔名 為語言的判定基準。
-mno-16bit 不產生16位元的指令
-m16bit 產生16位元的指令
-mel 使用 little-endian 位元組順序
-meb 使用 big-endian 位元組順序
-mmw-count= 4~8,指定編譯多重載入/儲存指令時最大移動的 字組個數。預設為4。
-mcache-line-size= 指定快取大小為 2 的次方個位元組。數值範 圍從 2 到 9。 預設是 2^4 (16) 位元組。
編譯器選項
選項:
-mcpu= 指定由哪一顆CPU產生程式碼: n1213-43u1h, n12, n10。
預設為 n12。
-mlib= 指定連接 C 語言的哪一個程式庫: glibc 或 newlib。預設為 glibc。
-g 在當前的操作系統格式產生除錯資訊(stabs、 COFF、XCOFF、
或 DWARF 2)。
-EL 或 -little 產生 little endian 資料
-EB 或 –big 產生 big endian 資料
-O 或 -On 指定優化程度,其中 n=1-6。
-Os 機器碼空間優化。
-cpu 或 -mcpu=<cpuname> 指定CPU。
-mno-16bit 不產生16位元指令
-mfpu 支援浮點運算處理指令
-mno-fpu 不支援浮點運算處理指令
組譯器選項
nds32-elf-as [選項...] [組譯檔案...]
選項:
-D 產生組譯除錯訊息
-g --gen-debug 生成除錯訊息
-W --no-warn 不產生警告訊息(warnings)
• --warn
警告訊息
(warnings)-EL 或 -little 產生 little endian 資料
-EB 或 -big 產生 big endian 資料
-x assembler-with-cpp
• 指定原始檔語言: C、C++、Objective-C、或 assembly。
-O or -On 指定優化程度,其中 n=1-6。
-Os 作空間優化。
-cpu or -mcpu=<cpuname>指定CPU
-mno-16bit 不產生 16 位元指令
-mfpu支援浮點運算處理指令
-mno-fpu不支援浮點運算處理指令
概要
工具鏈
NDS32 組合語言語法
指引指令 (提供組譯器)
假指令 (機械碼)
巨集
行內組合語言
C 和 易變的關鍵字
NDS32組合語言語法
‘#’和 ‘!’皆為註解符號, 但‘#’ 須在每列的第1行, ‘!’ 在任何地方 (除了括號內)皆可,後面的文字到行尾皆為註解。
支援一行多個指令,但不建議使用,且每兩個指令間應該用 “;” 分開。
一個整數可以指定為十進制、八進制(數值前需用 0 開頭)、十六進制 (數值前需用 0x 開頭)和二進制(數值前需用 0b 開頭)。例如:128、
#128、0200、#0200、0x80、#0x80、0b10000000、和
#0b10000000 都是相同。可選擇數值前是否加上 ‘#’ 符號。
一個浮點數使用 ’e’ 和 ‘E’ 指定指數的部分,‘f’ 和 ‘F’ 為單精準 浮點數,以及 ‘d’ 和 ‘D’ 為倍精度浮點數。例如, 0f12.345 或 0d1.2345e12。
組合語言指令是與大小寫無關,除非是使用者所定義的標籤。 例如:
“jral F1” 與 “jral f1” 這兩者是不相同的,但 “JRAL F1” 和第一個 指令是相同的。
暫存器 暫存器 暫存器 暫存器
通用暫存器 通用暫存器 通用暫存器 通用暫存器 (GPR)
所有 $r0-$r31 都用5個位元定址。
4個位元定址的是 $h0-$h15,這些對應到 $r0-$r11 和 $r16-
$r19 。
3個位元定址的是 $o0-$o7,對應到 $r0-$r7 。
$ta是組譯器預留的暫存器
由假指令轉譯時經常使用到$ta
隱含指令暫存器 隱含指令暫存器 隱含指令暫存器 隱含指令暫存器
暫存器 $r5: BEQS38 和 BNES38會將$r5當成運算元
暫存器 $ta ($r15) : SLTI45、SLTSI45、SLT45、SLTS45、
BEQZS8 和 BNEZS8等會將$r15當成運算元
暫存器 $fp ($r28): LWI37 和 SWI37會將$r28當成運算元
當前系統預留的暫存器 當前系統預留的暫存器 當前系統預留的暫存器 當前系統預留的暫存器 $p0 和 和 和 和 $p1
概要
工具鏈
NDS32 組合語言語法
指引指令 (提供組譯器使用)
假指令 (機械碼)
巨集
行內組合語言
C 和 易變的關鍵字
概要
工具鏈
NDS32 組合語言語法
指引指令 (提供組譯器)
假指令 (機械碼)
巨集
行內組合語言
C 和 易變的關鍵字
指引指令 (組譯器指令)
GNU預設支援指引指令的部份 預設支援指引指令的部份 預設支援指引指令的部份 預設支援指引指令的部份
.data subsec 資料節區。
.text subsec 程式碼節區。
.bss subsec 未初始化資料節區。
.section 使用者自行定義的部份。
Andes支援指引指令的部份 支援指引指令的部份 支援指引指令的部份 支援指引指令的部份
.sdata_d 倍字組大小 (8-byte) 的小型資料節區。
.sdata_w 字組大小 (4-byte) 的小型資料節區。
.sdata_h 半字組大小 (2-byte) 的小型資料節區。
.sdata_b 位元組大小的小型資料節區。
.sbss_d未初始化雙倍字組大小 (8-byte) 的小型資料節區。
.sbss_w未初始化字組大小 (4-byte) 的小型資料節區。
.sbss_h未初始化半字組大小 (2-byte) 的小型資料節區。
.sbss_b未初始化位元組大小的小型資料節區。
指引指令 (組譯器指令)
GNU 預設 預設 預設 預設 指引指令(符合 ELF)
. align 種類、填滿、最大對齊種類
.ascii 宣告“…” 字串常數
.asciz宣告“…” 字串常數(以0作為結尾)
.byte宣告位元資料
.2byte宣告2位元組資料。 (非強制對齊)
.4byte宣告4位元組資料。 (非強制對齊)
.8byte宣告8位元組資料。 (非強制對齊)
.double宣告倍精準精浮點常數。
.equ symbol,expr 定義 符號 = expr運算式。
.equiv symbol,expr 和 .equ 語法一樣,除非重複一個錯誤。
.global symbol 定義整體符號常數。
.globl symbol 和 .global 語法一樣。
指引指令 (組譯器指令)
GNU 預設 預設 預設 預設 指引指令(符合 ELF)
.if expr 判斷式成立則組譯。
.else 有條件的組譯。
.elseif 有條件的組譯。
.endif 有條件組譯結束。
.equ symbol,expr 定義 expr 數值。
.equiv symbol,expr 和 .equ 語法一樣,除非重複一個錯誤。
.def symbol 定義符號。
.endef結束符號定義
.ifdef symbol有條件的組譯
.ifndef symbol 有條件的組譯。
.end 程式結束
指引指令 (組譯器指令)
GNU 預設 預設 預設指引指令支援 預設 支援 支援 支援 ELF
.macro macname [macargs ...] 定義呼叫巨集呼叫的名稱。
.endm 結束巨集定義的標誌。
.exitm 提前離開當前的巨集定義。
資料類型宣告的 資料類型宣告的 資料類型宣告的 資料類型宣告的指引指令
.half 強制2位元組對齊。
.int, .float, .long, .single, and .word: 強制2位元對齊。
.double and .dword: 強制8位元對齊
.qword: 強制16位元對齊
如不想強制對齊,則使用以下方式
• .dc.h 或 .2byte for .half and .hword.
• .dc、.dc.l 和 .dc.w 或 .4byte for .int, .long, and .word.
• .dc.s 或 .4byte for .float and .single.
• .dc.d 或 .8byte for .double.
• .dc.x 或 extended (12-byte) 浮點數。
指引指令 (組譯器指令)
空間類型宣告的 空間類型宣告的 空間類型宣告的 空間類型宣告的指引指令
.dcb、.dcb.d、.dcb.h、dcb.l、dcb.s、dcb.w 和 .dcb.x。
.ds、 .ds.d、.ds.h、.ds.l、ds.s 和 .ds.w。
.space.
.skip.
.zero.
.fill – 將指定填充的值放入填充資料區域。
概要
工具鏈
NDS32 組合語言語法
指引指令 (組譯器指令)
假指令 (機械碼)
巨集
行內組合語言
C 和 易變的關鍵字
假指令
載入32位元的數值/位址
li rt5,imm_32 載入imm_32整數值到暫存器 rt5。
• sethi rt5,hi20(imm_32) 然後 ori rt5,reg,lo12(imm_32)
la rt5,var 載入變數var的32位元位址到暫存器 rt5。
• sethi rt5,hi20(var) 然後 ori reg,rt5,lo12(var)
載入/儲存 變數
l.{bhw} rt5,var 載入變數var的值到暫存器 rt5.
• sethi $ta,hi20(var) 然後 l{bhw}i rt5,[$ta+lo12(var)]
l.{bh}s rt5,var 載入有號數變數var的值到暫存器 rt5.
• sethi $ta,hi20(var) 然後 l{bh}si rt5,[$ta+lo12(var)]
l.{bhw}p rt5,var,inc 載入變數var的值到暫存器 rt5 後,把inc加到
$ta
• la $ta,var 然後 l{bhw}i.p rt5,[$ta],inc
l.{bhw}pc rt5,inc 持續載入變數var的值到暫存器 rt5 後,把inc加到
$ta
• l{bhw}i.bi $rt5,[$ta], inc
假指令
載入/儲存 變數
s.{bhw}p rt5,var,inc 將暫存器 rt5 的值儲存到 var 後,把inc加 到 $ta。
• la $ta,var 然後 s{bhw}i.p rt5,[$ta],inc
s.{bhw}pc rt5,inc 持續的將暫存器 rt5的值儲存到 var 後,把inc 加到 $ta。
• s{bhw}i.p rt5,[$ta],inc
l.{bh}sp rt5,var,inc 載入變數var的值到暫存器 rt5 後,把inc加到
$ta。
• la $ta,var 然後 l{bh}si.p rt5,[$ta],inc
l.{bh}spc rt5,inc 持續的載入變數var的值到暫存器 rt5後,把inc 加到 $ta。
• l{bh}si.p rt5,[$ta],inc.
s.{bhw} rt5,var 將暫存器 rt5的值儲存到 var 。
• sethi $ta,hi20(var) and then s{bhw}i rt5,[$ta+lo12(var)]
假指令
反相
not rt5,ra5 也能寫成 nor rt5,ra5,ra5 (取1的補數)
neg rt5,ra5 也能寫成 subri rt5,ra5,0(取2的補數)
跳躍至 標籤位址
br rb5 也能寫成 jr rb5
• 取決於如何組譯,可以組譯成 “jr5 rb5” 或 “jr rb5”.
b label 跳躍到 label
• 取決於如何組譯,可以組譯成
“j8 label”、“j label” 或 “la$ta,label; br $ta”.
beq rt5,ra5,label 或 beqz rt5,label 相等或等於0則跳躍
bne rt5,ra5,label 或 bnez rt5,label 不相等或不等於0則跳躍
bge{s} rt5,ra5,label 或 bgez rt5,label 大於或等於則跳躍
bgt{s} rt5,ra5,label 或 bgtz rt5,label 大於則跳躍
blt{s} rt5,ra5,label 或 bltz rt5,label 小於則跳躍
ble{s} rt5,ra5,label 或 blez rt5,label 小於或等於則跳躍
假指令
函數呼叫
bral rb5 也能寫成 jral br5
• 取決於如何組譯,可以組譯成 “jral5 rb5” 或 “jral rb5”.
bal fname 也能寫成 jal fname
• 取決於如何組譯,可以組譯成 “jal fname” 或 “la $ta,fname; bral
$ta”.
call fname 和 call function fname
• 都是相同的 “jal fname”.
bgezal rt5,fname 大於等於0則呼叫函式
bltzal rt5,fname 小於0則呼叫函式
假指令
搬移
move rt5,ra5
• 16位元指令用法:等同 mov55 rt5,ra5
• 不使用16位元指令用法:等同 ori rt5,ra5,0
move rt5,var 等同 l.w rt5,var
move rt5,imm_32等同li rt5,imm_32
推入/取出
pushm ra5,rb5 將 ra5 ~ rb5的值 放入堆疊(SP)。
push ra5 將 ra5 放入堆疊(SP)。(也可寫成 pushm ra5,ra5)
push.d var 將雙字組大小的變數 var 放入堆疊。
push.w var 將單字組大小的變數 var 放入堆疊。
push.h var 將半字組大小的變數 var 放入堆疊。
+
假指令
推入/取出
push.b var 將位元組大小的變數 var 放入堆疊。
pusha var 將變數 var的32位元記憶體址值放入堆疊。
pushi imm_32 將32位元立即值放入堆疊。
popm ra5,rb5 將堆疊頂端的數值放入 ra5 ~ rb5。
pop rt5 將堆疊頂端的數值放入 rt5。(也可寫成 popm rt5,rt5)
pop.d var,ra5 從堆疊頂端取出雙字組,第二個字組放入 ra5,第 二個字組放入ta
pop.w var,ra5 從堆疊暫存器取出一個字組放入ra5。
pop.h var,ra5 從堆疊暫存器取出半個字組放入ra5。 。
pop.b var,ra5 從堆疊暫存器取出一個位元組放入ra5。 。
內建運算函數
以下內建運算函數可以用在任何組合語言指令:
hi20(var) 取出變數var記憶體位址的最高20個位元
lo12(var) 取出變數var記憶體位址的最低12個位元
sda(var) 取出變數var距離小型資料區15位元的位移量
概要
工具鏈
NDS32 組合語言語法
指引指令 (組譯器指令)
假指令 (機械碼)
巨集
行內組合語言
C 和 易變的關鍵字
巨集
假運算元:
.macro: 開始定義巨集
.endm: 結束定義巨集
.exitm: 離開定義巨集
通用暫存器 $r15 ($ta) 是組譯器預留給巨集擴展和其他 用途所使用的。
所有假指令(pseudo-codes)皆是以巨集實現
“li rt5,imm32”
.macro load_imm32 rt5,imm32
!Copyright c 2006-2007 Andes Technology Corporation 33 .if ((imm32 <= 0x7ffff) && (imm32 >= -0x80000))
movi rt5,imm32
.elseif (imm32 & 0x00000fff == 0x0) sethi rt5,hi20(imm32)
.else
sethi rt5,hi20(imm32) ori rt5,rt5,lo12(imm32)
.endif
.endm
概要
工具鏈
NDS32 組合語言語法
指引指令 (組譯器指令)
假指令 (機械碼)
巨集
行內組合語言
C 和 易變的關鍵字
概要
工具鏈
NDS32 組合語言語法
指引指令 (組譯器指令)
假指令 (機械碼)
巨集
行內組合語言
行內組合語言
可以減少因呼叫函數產生的多餘的程式碼
有助於系統程式的編寫
中斷處理程式
存取系統暫存器
程式碼優化
基本的行內組合語言
asm (“statements”); 或 __asm__ ("statements");
asm (“statement1
\n\t”
“statement2\n\t”
“statement3”);
asm( “jal 4 \n\t”
“move $r6, $lp\n\t\”
“jr $r6”
) ;
行內組合語言
擴充的行內組合語言
asm ( assembler template
: output operands /* optional */
: input operands /* optional */
: list of clobbered registers /* optional */
);
int num1=10, num2=20, sum;
asm (
"add %0, %1, %2"
:"=r"(sum)
:"r" (num1), "r" (num2) );
int num1=10, num2=20, sum;
asm (
"add %[summary], %[intg1], %[intg2]"
:[summary]"=r"(sum)
:[intg1] "r" (num1), [intg2]"r" (num2)
);
行內組合語言
規範 規範 規範
規範 用法用法用法用法
l $d0.lo 或 $d1.lo
h $d0.hi 或 $d1.hi
x $d0 或 $d1
A $d0.lo
B $d0.hi
C $d1.lo
D $d1.hi
r 通用暫存器
Modifier
意義= 只能寫入的動作,通常用於所有輸出的動作
+ 讀寫動作,必須被列為輸出的動作
& 一個暫存器,只能用於輸出作用
概要
工具鏈
NDS32 組合語言語法
指引指令 (組譯器指令)
假指令 (機械碼)
巨集
行內組合語言
C 和 易變的關鍵字
易變的關鍵字
如果變數宣告時加上volatile 關鍵字時,等同告訴編譯器 這是一個可能會在任何時間改變數值的變數 (即使編譯器 從程式碼中找不到任何這變數的程式碼 )。
三種類型的變數可能會隨時更動:
1. 記憶體映射的周邊暫存器
2. 會受中斷服務程式修改的全域變數
3. 在多執行緒應用程式中多個執行續存取的全域變數
上述類型的變數應該被相同的宣告為 “volatile”。
變數宣告沒有 volatile 關鍵字
#define inw(reg) (*((unsigned int *) (reg)))
#define outw(reg, data) ((*((unsigned int *)(reg)))=(unsigned int)(data)) /* GPIO controller */
#define GPIO_BASE 0x98100000 /* GPIO base address */
#define GPIO_DIN_OFFSET 0x4
int main(void) {
int j;
while (inw(GPIO_BASE + GPIO_DIN_OFFSET)==0) j=1;
return 1;
} 000082ac <main>:
82ac: 51 ff ff f8 addi $sp,$sp,#-8 82b0: 15 cf 80 01 swi $fp,[$sp+#4]
82b4: 83 9f mov55 $fp,$sp 82b6: 46 59 81 00 sethi $r5,#622848 82ba: 58 52 80 04 ori $r5,$r5,#0x4 82be: b4 a5 lwi450 $r5,[$r5]
82c0: 84 60 movi55 $r3,#0
82c2: db 02 bnes38 $r3,82c6 <main+0x1a>
82c4: c5 00 beqz38 $r5,82c4 <main+0x18>
82c6: 84 01 movi55 $r0,#1 82c8: 83 fc mov55 $sp,$fp 82ca: 05 ce 00 01 lwi $fp,[$fp+#4]
82ce: 51 ff 80 08 addi $sp,$sp,#8 82d2: dd 9e ret5 $lp
用 volatile 關鍵字宣告變數
#define inw(reg) (*((volatile unsigned int *) (reg)))
#define outw(reg, data) ((*((volatile unsigned int *)(reg)))=(unsigned int)(data)) /* GPIO controller */
#define GPIO_BASE 0x98100000 /* GPIO base address */
#define GPIO_DIN_OFFSET 0x4
int main(void) {
int j;
while (inw(GPIO_BASE + GPIO_DIN_OFFSET)==0) j=1;
return 1;
} 000082ac <main>:
82ac: 51 ff ff f8 addi $sp,$sp,#-8 82b0: 15 cf 80 01 swi $fp,[$sp+#4]
82b4: 83 9f mov55 $fp,$sp 82b6: 46 49 81 00 sethi $r4,#622848 82ba: 58 42 00 04 ori $r4,$r4,#0x4 82be: b4 a4 lwi450 $r5,[$r4]
82c0: c5 ff beqz38 $r5,82be <main+0x12>
82c2: 84 01 movi55 $r0,#1 82c4: 83 fc mov55 $sp,$fp 82c6: 05 ce 00 01 lwi $fp,[$fp+#4]
82ca: 51 ff 80 08 addi $sp,$sp,#8 82ce: dd 9e ret5 $lp