版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
Cortex-m3的指令系統(tǒng)
與匯編程序設(shè)計(jì)3.1CM3指令的結(jié)構(gòu)3.2CM3指令的尋址方式3.3CM3指令集3.4ARM匯編程序設(shè)計(jì)基礎(chǔ)組習(xí)題3
本章要點(diǎn)
☆CM3指令的結(jié)構(gòu)
☆CM3指令的尋址方式
☆CM3指令集
☆A(yù)RM匯編程序設(shè)計(jì)基礎(chǔ)
3.1CM3指令的結(jié)構(gòu)
3.1.1Thumb2指令集CUP依靠指令來完成計(jì)算和控制任務(wù),每款CUP在設(shè)計(jì)時(shí)就規(guī)定了一系列與其硬件電路相匹配的指令系統(tǒng)。指令系統(tǒng)的強(qiáng)弱是CUP的重要指標(biāo),是提高微處理器效率的最有效工具之一。
ARM指令集為32位指令集,可以實(shí)現(xiàn)ARM架構(gòu)下的所有功能。Thumb指令集是對(duì)32位ARM指令集的擴(kuò)充,它的目標(biāo)是為了實(shí)現(xiàn)更高的代碼密度。Thumb指令集實(shí)現(xiàn)的功能只是32位ARM指令集的子集,它僅僅把常用的ARM指令壓縮成16位的指令編碼方式。
Thumb-2技術(shù)改善了Thumb指令集的性能,它在原有的Thumb指令的基礎(chǔ)上進(jìn)行了如下的擴(kuò)充:增加了一些新的16位Thumb指令來改進(jìn)程序的執(zhí)行流程,增加了一些新的32位Thumb指令以實(shí)現(xiàn)一些ARM指令的專有功能,解決了之前Thumb指令集不能訪問協(xié)處理器、特權(quán)指令和特殊功能指令的局限。Thumb-2指令集可以實(shí)現(xiàn)所有的功能,這樣就不需要在ARM/Thumb狀態(tài)之間反復(fù)切換了,代碼密度和性能得到了顯著的提高,但值得注意的是Thumb-2并不支持32位ARM指令集。
如圖3.1所示,Cortex-m3處理器支持Thumb2指令集,但并不支持所有的Thumb-2指令,架構(gòu)于ARMv7上的Cortex-m3只要求實(shí)現(xiàn)Thumb2的一個(gè)子集。圖3.1Thumb2指令集與Thumb指令集的關(guān)系
例程3.1寄存器相加。
3.1.2CM3指令的格式
指令是構(gòu)成程序的基本單元,程序是指令的有序集合。指令的基本格式如下:
<指令助記符>{<執(zhí)行條件>}{S}{P}<目標(biāo)寄存器>,<操作數(shù)1的寄存器>{,<操作數(shù)2>}<pcode>{<cond>}
{S}
{P}<Rd>,<Rn>{,<operand2>}其中,<>內(nèi)的項(xiàng)是必需的,{
}內(nèi)的項(xiàng)是可選的。如<opcode>指令助記符是必須書寫的;{cond}為指令執(zhí)行條件,是可選項(xiàng),若不書寫則使用默認(rèn)的條件AL(無條件執(zhí)行)。
opcode:指令助記符,如LDR、STR等,表示了該指令需要執(zhí)行的動(dòng)作。
cond:條件后綴,當(dāng)后綴條件滿足時(shí)指令被執(zhí)行,如EQ、NR等,參考表3.1。
S:S后綴,表明是否更新APSR狀態(tài)寄存器的值,書寫時(shí)指令執(zhí)行結(jié)果影響APSR。
P:P后綴,指定指令的編碼類型,其定義如下:
(1)當(dāng)指定P為.N時(shí),則該指令指定編譯為16位Thumb2編碼指令,且其前提是該指令支持16位長度編碼,若不支持將導(dǎo)致編譯錯(cuò)誤。
(2)當(dāng)指定P為.W時(shí),則該指令指定編譯為32位Thumb2編碼指令,且其前提是該指令支持32位長度編碼,若不支持將導(dǎo)致編譯錯(cuò)誤。
(3)若未指定指令編碼類型,則由編譯器自動(dòng)選擇指令的類型,且根據(jù)指令存在的編碼類型優(yōu)先選擇16位指令,實(shí)際編程時(shí)一般不指定指令的編碼類型。
例程3.2指令格式舉例。
3.1.3CM3指令的后綴
在Cortex-m3處理器中,指令可以帶后綴,后綴主要有條件后綴、S后綴和P后綴,S后綴和P后綴前面已介紹過,這里主要介紹條件后綴。
例程3.3條件后綴應(yīng)用示例。
在Coetex-m3中,下列指令將會(huì)更新APSR中的標(biāo)志位:
(1)16位算術(shù)邏輯指令;
(2)32位帶S后綴的算術(shù)邏輯指令;
(3)比較指令和測(cè)試指令;
(4)直接操作APSR指令(MSR指令)。
3.2CM3指令的尋址方式
從存放的物理位置來看,操作數(shù)存放在程序空間、寄存器空間和主存儲(chǔ)器空間三處地方,如圖3.2所示。所謂尋址就是尋找操作數(shù)的方式,為方便地尋找存放于不同空間的操作數(shù),產(chǎn)生了諸多的尋址方式。
3.2.1立即操作數(shù)的尋址
立即操作數(shù)作為指令的一個(gè)部分存在于程序空間。在取出指令的同時(shí)也就取出了這個(gè)可以立即使用的操作數(shù)(也稱為立即數(shù))。立即數(shù)實(shí)際上就是程序中的常數(shù),用于給變量賦初值。除非修改程序,常數(shù)性質(zhì)的立即數(shù)是不會(huì)發(fā)生變化的,這種尋址方式通常稱為立即尋址。
例程3.4立即尋址應(yīng)用示例。
說明:前綴“#”表示立即數(shù),“0x”表示16進(jìn)制數(shù)值。
從表3.2可以看出,ARM將32位指令分為兩個(gè)部分。
立即數(shù)要滿足一定的生成規(guī)則:即每個(gè)立即數(shù)由一個(gè)8位的常數(shù)循環(huán)右移偶數(shù)位得到,其中循環(huán)右移的位數(shù)用一個(gè)4位二進(jìn)制數(shù)的兩倍表示。如果立即數(shù)記作<immediate>,8位常數(shù)記作immed_8,4位的循環(huán)右移值記作rotate_imm,則有
ARM匯編編譯器按照下面的規(guī)則生成立即數(shù)的編碼。
(1)當(dāng)立即數(shù)數(shù)值在0~0xFF范圍時(shí),rotate_imm=
0。
(2)其他情況下,匯編編譯器選擇使rotate_imm數(shù)值最小的編碼方式。
判斷一個(gè)數(shù)是否為合法的立即數(shù),首先將這個(gè)數(shù)轉(zhuǎn)換為32位的十六進(jìn)制形式,例如
218=0xDA=0x0000_00DA,并按下面規(guī)則判斷。
(1)除零外,僅有一位數(shù)的為合法立即數(shù)。
(2)除零外,僅有兩位數(shù),并且相鄰(包括首尾,如0x1000000A)的為合法立即數(shù)。
(3)除零外,僅有三位數(shù),并且相鄰(包括中間有0,例如0x10800000;包括首尾相鄰,例如0x14000003),這三位數(shù)中,最高位取值僅能為1、2、3,最低位取值僅能為4、8、C,中間位0x0~0xF。這種組合的為合法立即數(shù)。
除以上三種外,其他基本是無法滿足生成規(guī)則的非法立即數(shù)。
3.2.2寄存器操作數(shù)的尋址
1.寄存器尋址
當(dāng)操作數(shù)位于寄存器中,指令中的地址碼字段指出的是寄存器編號(hào),指令執(zhí)行時(shí)直接取出寄存器值來操作。寄存器尋址方式是一種簡單快捷的尋址方式,執(zhí)行效率高,源和目的操作數(shù)都可以位于寄存器中。
2.寄存器移位尋址
寄存器移位尋址是Cortex-M3指令集特有的尋址方式。
可用的移位操作如下:
·LSL:邏輯左移,寄存器中數(shù)據(jù)位低端空出的位補(bǔ)0。
·LSR:邏輯右移,寄存器中數(shù)據(jù)位高端空出的位補(bǔ)0。
·ASR:算術(shù)右移,移位過程中保持符號(hào)位不變,即若源操作數(shù)為正數(shù),則數(shù)據(jù)位的高端空出的位補(bǔ)0,否則補(bǔ)1。
·ROR:循環(huán)右移(RotateRight),從數(shù)據(jù)位低端移出的位填入數(shù)據(jù)位高端空出的位。
·RRX:帶擴(kuò)展的循環(huán)右移,操作數(shù)右移一位,高端空出的位用原C標(biāo)志值填充。
算術(shù)左移與邏輯左移的規(guī)則完全相同。各種移位操作如圖3.3所示。圖3.3移位操作示意圖
3.多寄存器尋址
多寄存器尋址即一次可傳送幾個(gè)寄存器值,允許一條指令傳送16個(gè)寄存器的任何子集或所有寄存器。
例程3.7多寄存器尋址應(yīng)用示例。
3.2.3存儲(chǔ)器操作數(shù)的尋址
1.寄存器間接尋址
指令中的地址碼給出的是一個(gè)通用寄存器的編號(hào),所需的操作數(shù)保存在寄存器指定地址的存儲(chǔ)單元中,即寄存器為操作數(shù)的地址指針。
例程3.8寄存器間接尋址應(yīng)用示例。
2.基址尋址
1)基址尋址
基址尋址就是將基址寄存器的內(nèi)容與指令中給出的偏移量相加,形成操作數(shù)的有效地址。
例程3.9基址尋址應(yīng)用示例。
2)相對(duì)尋址
相對(duì)尋址是基址尋址的一種變通。由程序計(jì)數(shù)器(PC)提供基準(zhǔn)地址,指令中的地址碼字段作為偏移量,兩者相加后得到的地址即為操作數(shù)的有效地址。
例程3.10相對(duì)尋址應(yīng)用示例。
3.堆棧尋址
堆棧是按照“先進(jìn)后出”規(guī)則管理的存儲(chǔ)器區(qū)域,無論是傳統(tǒng)的ARM7還是現(xiàn)在的Cortex-m3,對(duì)堆棧操作都是通過堆棧指針(SP)來進(jìn)行的,隨著堆棧內(nèi)容的增減,堆棧指針也進(jìn)行相應(yīng)的移動(dòng)。如圖3.4所示,一般情況下對(duì)于嵌入式處理器支持兩種堆棧指針的移動(dòng)方向,即“堆棧的生長方向”。圖3.4堆棧的生長方向
向上生長:在向堆棧寫入數(shù)據(jù)后,堆棧指針的值變大,也就是向高地址方向生長,稱之為“遞增堆?!?。
向下生長:在向堆棧寫入數(shù)據(jù)后,堆棧指針的值變小,也就是向低地址方向生長,稱之為“遞減堆?!薄?/p>
除了要考慮堆棧指針的增長方向之外,還要考慮堆棧指針指向的存儲(chǔ)單元是否已經(jīng)保存有堆棧數(shù)據(jù),或者說在入棧時(shí)是否可以直接向堆棧指針指向的存儲(chǔ)單元寫入數(shù)據(jù)。一般的ARM處理器將此種情況分為“滿堆?!焙汀翱斩褩!?,如圖3.5所示。圖3.5堆棧的空滿特性
滿堆棧:堆棧指針指向最后壓入棧的有效數(shù)據(jù)項(xiàng),此種堆棧的入棧操作要先調(diào)整指針再寫入數(shù)據(jù)。
空堆棧:堆棧指針指向下一個(gè)待壓入數(shù)據(jù)的空位置,此種堆棧的入棧操作要先寫入數(shù)據(jù)再調(diào)整指針。
綜合前面的堆棧生長方向和空滿特性,一共可以得到四種堆棧類型,分別為:
滿遞增:堆棧通過增大存儲(chǔ)器的地址向上增長,棧頂指向含有效數(shù)據(jù)的最高地址;
空遞增:堆棧通過增大存儲(chǔ)器的地址向上增長,棧頂指向堆棧上的第一個(gè)空位置;
滿遞減:堆棧通過減小存儲(chǔ)器的地址向下增長,棧頂指向含有效數(shù)據(jù)的最低地址;
空遞減:堆棧通過減小存儲(chǔ)器的地址向下增長,棧頂指向堆棧下的第一個(gè)空位置。
例程3.11堆棧尋址應(yīng)用示例。
3.3CM3指令集
3.3.1存儲(chǔ)器訪問指令Cortex-m3處理器對(duì)存儲(chǔ)器的訪問只能通過加載和存儲(chǔ)指令來實(shí)現(xiàn)。加載指令LDR是把存儲(chǔ)器中的內(nèi)容加載到寄存器中,而存儲(chǔ)指令STR則是把寄存器內(nèi)容存儲(chǔ)至存儲(chǔ)器中,其指令傳送過程中的數(shù)據(jù)類型實(shí)現(xiàn)了字節(jié)、半字、字和雙字的操作。此外,多寄存器加載和存儲(chǔ)指令可以實(shí)現(xiàn)一條指令加載和存儲(chǔ)多個(gè)寄存器的內(nèi)容,且大大提高數(shù)據(jù)操作效率。
例如通常情況下,如果要讀取4個(gè)地址連續(xù)的存儲(chǔ)單元的內(nèi)容,若采用LDR指令,可能需要8個(gè)周期,而若采用多寄存器的LDM加載指令,則只需要5個(gè)周期。Thumb-2存儲(chǔ)器訪問指令如表3.3所示。
1.LDR和STR指令——加載和存儲(chǔ)指令
LDR指令用于從存儲(chǔ)器中讀取數(shù)據(jù)放入寄存器中;STR指令用于將寄存器中的數(shù)據(jù)保存到存儲(chǔ)器。
例程3.12常用指令。
地址偏移量可以有以下三種格式:
(1)立即數(shù)。立即數(shù)可以是一個(gè)無符號(hào)的數(shù)值,這個(gè)數(shù)據(jù)可以加到基址寄存器,也可以從基址寄存器中減去這個(gè)數(shù)值。
(2)寄存器。寄存器中的數(shù)值可以加到基址寄存器中,也可以從基址寄存器中減去這個(gè)數(shù)值。
(3)寄存器及移位常數(shù)。寄存器移位后的值可以加到基址寄存器,也可以從基址寄存器中減去這個(gè)數(shù)值。
按照尋址方式的地址計(jì)算方法分,加載和存儲(chǔ)指令可以有以下四種形式。
(1)零偏移。Rn的值作為傳送數(shù)據(jù)的地址,即地址偏移量為0。
例程3.16零偏移應(yīng)用示例。
(2)前索引偏移。在數(shù)據(jù)傳送之前,將偏移量加到Rn中,其結(jié)果作為數(shù)據(jù)傳送的存儲(chǔ)地址。若使用后綴“!”,則結(jié)果回寫到Rn中,且Rn的值不允許為R15。
例程3.17前索引偏移應(yīng)用示例。
(3)后索引偏移。Rn的值用做傳送數(shù)據(jù)的存儲(chǔ)地址。在數(shù)據(jù)傳送后,將偏移量與Rn相加,結(jié)果寫回Rn中,Rn不允許是R15。
例程3.18后索引偏移應(yīng)用示例。
(4)程序相對(duì)偏移。程序相對(duì)偏移是前索引形式的另一個(gè)版本。匯編器由PC寄存器計(jì)算偏移量,并將PC寄存器作為Rn生成前索引指令。不能使用后綴“!”。
例程3.19程序相對(duì)偏移應(yīng)用示例。
2.LDM和STM指令——多寄存器加載/存儲(chǔ)指令
LDM/STM的主要用途是較大數(shù)據(jù)量的復(fù)制、參數(shù)傳遞等。其常用的指令主要有:
指令支持的模式說明:
以上四種傳輸模式都是小端模式,其傳輸都是高地址數(shù)據(jù)加載到高寄存器,低地址數(shù)據(jù)加載到低寄存器,高寄存器存儲(chǔ)到高地址,低寄存器存儲(chǔ)到低地址。
指令格式中,寄存器Rn為基址寄存器,裝有傳送數(shù)據(jù)的初始地址,Rn不允許為R15;后綴“!”表示最后的地址回寫到Rn中。寄存器reglist
可包含多于一個(gè)寄存器或包含寄存器范圍,使用“,”分開,如{R1,R2,R6-R9},寄存器由小到大排列。
例程3.20多寄存器傳送指令應(yīng)用示例。
多寄存器傳送指令示意圖如圖3.6所示,其中R1為指令執(zhí)行前的基址寄存器,R1′則為指令執(zhí)行完后的基址寄存器。圖3.6多寄存器傳送示意
STM/LDM與PUSH/POP的區(qū)別:
(1)STM/LDM能對(duì)任意的地址空間進(jìn)行操作,而PUSH/POP只能對(duì)堆棧空間進(jìn)行操作;
(2)STM/LDM同時(shí)支持向上和向下兩種生長方式,而PUSH/POP只能支持向上生長;
(3)當(dāng)兩對(duì)指令的操作數(shù)都為SP時(shí),STM/LDM可以選擇是否回寫修改SP,而PUSH/POP指令會(huì)自動(dòng)修改SP值。
3.3.2數(shù)據(jù)處理運(yùn)算指令
數(shù)據(jù)處理運(yùn)算指令可分為以下幾類:數(shù)據(jù)傳送指令,算術(shù)邏輯運(yùn)算指令,位段處理指令,字節(jié)序反轉(zhuǎn)指令,有符號(hào)擴(kuò)展指令,比較指令以及乘除法和飽和運(yùn)算指令。
以下的指令列表中,僅支持32位編碼的指令,其后綴.W可以省略。各個(gè)指令列表中上標(biāo)有以下含義。
[1]表示指令中的參數(shù)目的寄存器RD如果被忽略,則Rn將變成目的寄存器。
[2]表示指令中的參數(shù)lsb,其取值范圍為0≤lsb≤31;參數(shù)width,其取值范圍為:
1≤width≤(32-lsb)。
[3]表示指令中的參數(shù)rotation,其取值只能為ROR#8、ROR#16、ROR#24中的一個(gè)。
1.數(shù)據(jù)傳送指令
MOV指令可以用于寄存器間的數(shù)據(jù)傳輸,也能用于加載立即數(shù)。Thumb-2數(shù)據(jù)傳送指令如表3.4所示。
例程3.21數(shù)據(jù)傳送指令應(yīng)用示例。
2.算術(shù)邏輯運(yùn)算指令
算術(shù)邏輯運(yùn)算指令主要包括加法指令、減法指令以及移位操作指令。Thumb-2算術(shù)邏輯運(yùn)算指令如表3.5所示。
例程3.22算術(shù)邏輯運(yùn)算指令應(yīng)用示例。
3.位段處理指令
位段處理指令主要包括位段清零、位段插入以及位反轉(zhuǎn)等指令,其對(duì)位處理特別是I/O處理的效率比較高。Thumb-2位段處理指令如表3.6所示。
4.字節(jié)序反轉(zhuǎn)指令
字節(jié)序反轉(zhuǎn)指令專門服務(wù)于小端模式和大端模式的轉(zhuǎn)換,最常見于網(wǎng)絡(luò)應(yīng)用程序中(網(wǎng)絡(luò)字節(jié)序是大端,主機(jī)字節(jié)序常是小端的)。Thumb-2字節(jié)序反轉(zhuǎn)指令如表3.7所示。
例程3.24字節(jié)序反轉(zhuǎn)指令應(yīng)用示例(假設(shè)此處的R2=0x12345687)。
5.有符號(hào)擴(kuò)展指令
有符號(hào)擴(kuò)展指令主要包括有符號(hào)擴(kuò)展一個(gè)字節(jié)、有符號(hào)擴(kuò)展一個(gè)半字以及相應(yīng)的無符號(hào)擴(kuò)展指令,主要用于提取字中的某個(gè)字節(jié)信息或半字信息,是為優(yōu)化C語言的強(qiáng)制類型轉(zhuǎn)換而設(shè)的,可把數(shù)據(jù)寬度轉(zhuǎn)換成處理器喜歡的32位長度。Thumb-2有符號(hào)擴(kuò)展指令如表3.8所示。
例程3.25有符號(hào)擴(kuò)展指令應(yīng)用示例(假設(shè)此處的R2=0x12348756)。
6.比較指令
比較指令主要包括比較指令和測(cè)試指令。該類指令自動(dòng)更新APSR的標(biāo)志位。由于其用法簡單,在此不再做詳細(xì)介紹。Thumb-2比較指令如表3.9所示。
7.硬件乘除法和飽和運(yùn)算指令
硬件乘除法指令主要包括乘加、乘減指令和飽和運(yùn)算指令,并能產(chǎn)生64位積。Thumb-2硬件乘除法和飽和運(yùn)算指令如表3.10所示。
例程3.26硬件乘除法指令應(yīng)用示例。
3.3.3分支轉(zhuǎn)移指令
在Cortex-M3中有兩種方法可以實(shí)現(xiàn)程序的跳轉(zhuǎn),一種是使用分支轉(zhuǎn)移指令實(shí)現(xiàn),另一種則是向PC寄存器直接賦值實(shí)現(xiàn)。Thumb-2分支轉(zhuǎn)移指令如表3.11所示,主要包括B轉(zhuǎn)移指令、比較轉(zhuǎn)移指令、IF-THEN指令塊和查表轉(zhuǎn)移指令等。以上的指令列表中僅支持32位編碼的指令,其后綴.W可以省略。
1.B
轉(zhuǎn)移指令
B
指令是跳轉(zhuǎn)到指定的地址執(zhí)行程序,若是帶鏈接的B指令,則還需要將B
指令的下一條指令地址拷貝到LR
鏈接寄存器中,然后跳轉(zhuǎn)到指定地址運(yùn)行程序。
2.比較轉(zhuǎn)移指令
比較轉(zhuǎn)移指令是根據(jù)比較寄存器的內(nèi)容來決定是否進(jìn)行程序的跳轉(zhuǎn)轉(zhuǎn)移。
3.IF-THEN指令塊
IT(F-THEN)指令塊是圍起一個(gè)指令塊,塊里面最多可以有四條指令,且圍起來的指令必須都是條件執(zhí)行的。
T指令的使用形式如下:
IT指令并不影響APSR的標(biāo)志位,且其指令塊中不允許有任何的程序跳轉(zhuǎn)指令,除了出現(xiàn)異常返回。另外IT
指令塊中不允許存在更新APSR標(biāo)志的指令,因此指令塊中不可以包含CMP、CMN
和TST
指令以及含有更新APSR標(biāo)志的指令形式。
例程3.29IT指令應(yīng)用示例。
4.查表轉(zhuǎn)移指令
查表轉(zhuǎn)移指令TBB
和TBH分別用于從一個(gè)字節(jié)/半字?jǐn)?shù)組表中查找轉(zhuǎn)移地址。
例程3.30查表轉(zhuǎn)移指令應(yīng)用示例。
3.3.4其他指令
Cortex-M3的其他指令如表3.12所示。
1.系統(tǒng)服務(wù)指令
系統(tǒng)服務(wù)指令主要包括軟中斷指令、斷點(diǎn)指令、CPS指令和操作特殊功能寄存器指令。
2.睡眠控制指令
WFI:該指令等待中斷異常發(fā)生。程序運(yùn)行該指令后程序掛起,不再繼續(xù)執(zhí)行,直到發(fā)生中斷異常喚醒CUP。
WFE:該指令等待事件喚醒,用于多核的處理器系統(tǒng)中。
SEV:該指令發(fā)送事件喚醒CUP,主要用于多核的處理器系統(tǒng)中。
3.同步隔離指令
DMB:僅當(dāng)所有在它前面的存儲(chǔ)器訪問都執(zhí)行后,才提交它后面的存儲(chǔ)器訪問動(dòng)作。
DSB:僅當(dāng)所有在它前面的存儲(chǔ)器訪問都執(zhí)行完畢后,才執(zhí)行它后面的指令。
ISB:清空流水線緩沖區(qū),以保證所有在它前面的指令都執(zhí)行完畢之后,才執(zhí)行它后面的指令。
3.3.5偽指令
偽指令不是指令集中的指令,但是可以像其他ARM指令一樣使用,只是在匯編時(shí)將這些偽指令解釋為相應(yīng)指令的組合。Cortex-M3的偽指令如表3.13所示。
1.ADR——小范圍地址讀取偽指令
ADR指令將基于PC相對(duì)偏移的地址值讀取到寄存器中。其偏移量必須是正數(shù)并小于1KB。在用ADR
偽指令將一個(gè)地址裝載到一個(gè)寄存器時(shí),不是裝載地址的絕對(duì)值,而是裝載地址和PC寄存器的差值,即相對(duì)地址。
2.LDR——大范圍地址讀取偽指令
LDR偽指令用于加載32位立即數(shù)或一個(gè)地址值到指定寄存器。且如果匯編器發(fā)現(xiàn)要產(chǎn)生的立即數(shù)是一個(gè)程序地址,它會(huì)自動(dòng)將LSB
置位,若是數(shù)據(jù)地址,則不會(huì)自動(dòng)置位LSB。
3.NOP偽指令
NOP偽指令是空操作(無操作)指令。指令執(zhí)行后不影響任何寄存器和內(nèi)存單元,只是消耗了CUP的一點(diǎn)時(shí)間。NOP偽指令在匯編后,也會(huì)生成一條類似于MOVR0,R0的指令。
指令格式如下:NOP
NOP多用于軟件延遲,且NOP指令不改變ALU
狀態(tài)標(biāo)志。
3.4ARM匯編程序設(shè)計(jì)基礎(chǔ)
3.4.1ARM匯編指示命令在ARM匯編語言程序里,有一些特殊指令助記符,這些助記符與指令系統(tǒng)的助記符不同,沒有相對(duì)應(yīng)的操作碼,通常將這些特殊指令助記符稱為匯編指示命令,與x86所稱的偽指令相對(duì)應(yīng)。
在ARM的匯編程序中,有如下幾種匯編指示命令:
·符號(hào)定義匯編指示命令。
·數(shù)據(jù)定義匯編指示命令。
·匯編控制匯編指示命令。
·結(jié)構(gòu)描述匯編指示命令。
·報(bào)告匯編指示命令。
·其他匯編指示命令。
1.符號(hào)定義匯編指示命令
符號(hào)定義匯編指示命令用于定義ARM匯編程序的變量,對(duì)變量進(jìn)
行賦值及定義寄存器名稱。該類主要的匯編指示命令如下:
·全局變量聲明:GBLA、GBLL
和GBLS。
·局部變量聲明:LCLA、LCLL
和LCLS。
·變量賦值:SETA、SETLL
和SETS。
·為一個(gè)通用寄存器列表定義名稱:RLIST。
1)GBLA、GBLL和GBLS
GBLA、GBLL和GBLS匯編指示命令用于聲明一個(gè)ARM程序的全局變量,并將其初始化。
GBLA
匯編指示命令用于聲明一個(gè)全局的算術(shù)變量,并將其初始化為0。
GBLL
匯編指示命令用于聲明一個(gè)全局的邏輯變量,并將其初始化為{FALSE}。
GBLS
匯編指示命令用于聲明一個(gè)全局的字符串變量,并將其初始化為空字符串“”。
2)LCLA、LCLL
和LCLS
LCLA、LCLL
和LCLS
匯編指示命令用于聲明一個(gè)ARM程序的局部變量,并將其初始化。
LCLA匯編指示命令用于聲明一個(gè)局部的算術(shù)變量,并將其初始化為0。
LCLL
匯編指示命令用于聲明一個(gè)局部的邏輯變量,并將其初始化為{FALSE}。
LCLS
匯編指示命令用于聲明一個(gè)局部的字符串變量,并將其初始化為空字符串“”。
3)SETA、SETL
和SETS
SETA,SETL
和SETS
匯編指示命令用于給一個(gè)ARM程序中的變量賦值。
SETA
匯編指示命令用于給一個(gè)全局/局部的算術(shù)變量賦值。
SETL
匯編指示命令用于給一個(gè)全局/局部的邏輯變量賦值。
SETS
匯編指示命令用于給一個(gè)全局/局部的字符串變量賦值。
4)RLIST
RLIST
為一個(gè)通用寄存器列表定義名稱。使用該匯編指示命令定義的名稱可在ARM指令LDM/STM中使用。在LDM/STM指令中,列表中的寄存器訪問次序根據(jù)寄存器的編號(hào)由低到高,而與列表中的寄存器排列次序無關(guān)。
2.數(shù)據(jù)定義匯編指示命令
數(shù)據(jù)定義匯編指示命令用于數(shù)據(jù)表定義、文字池定義、數(shù)據(jù)空間分配等。該類匯編指示命令如下:
·聲明一個(gè)文字池:LTORG。
·定義一個(gè)結(jié)構(gòu)化的內(nèi)存表中的首地址:MAP。
·定義結(jié)構(gòu)化內(nèi)存表中的一個(gè)數(shù)據(jù)域:FLELD。
·分配一塊內(nèi)存單元,并用0初始化:SPACE。
·分配一段字節(jié)的內(nèi)存單元,并用指定的數(shù)據(jù)初始化:DCB。
·分配一段字的內(nèi)存單元,并用指定的數(shù)據(jù)初始化:DCD
和DCDU。
·分配一段字的內(nèi)存單元,將每個(gè)單元的內(nèi)容初始化為該單元相對(duì)于靜態(tài)基址寄存器的偏移量:DCDO。
·分配一段字的內(nèi)存單元,并用雙精度的浮點(diǎn)數(shù)據(jù)初始化:DCFD和DCFDU。
·分配一段字的內(nèi)存單元,并用單精度的浮點(diǎn)數(shù)據(jù)初始化:DCFS
和DCFSU。
·分配一段字的內(nèi)存單元,并用單精度的浮點(diǎn)數(shù)據(jù)初始化,指定內(nèi)存單元存放的是代碼,而不是數(shù)據(jù):DCI。
·分配一段雙字的內(nèi)存單元,并用64位的整數(shù)數(shù)據(jù)初始化:DCQ和DCQU。
·分配一段半字的內(nèi)存單元,并用指定的數(shù)據(jù)初始化:DCW和DCWU。
1)LTORG
LTORG
用于聲明一個(gè)文字池,在使用LDR偽指令時(shí),匯編器會(huì)將偽指令中的32位立即數(shù)(或地址)存入文字池。若沒有使用LTORG
聲明文字池,則匯編器會(huì)在程序末尾自動(dòng)聲明。
2)MAP
MAP
用于定義一個(gè)結(jié)構(gòu)化的內(nèi)存表的首地址。此時(shí),內(nèi)存表的位置計(jì)數(shù)器{VAR}設(shè)置為該地址值,{VAR}為匯編器的內(nèi)置變量,“”與MAP
同義。
3)FLELD
FLELD
用于定義結(jié)構(gòu)化內(nèi)存表中的一個(gè)數(shù)據(jù)域?!埃!迸cFLELD
同義。
FLELD匯編指示命令常與MAP
匯編指示命令配合使用,用來定義結(jié)構(gòu)化的內(nèi)存表。MAP
匯編指示命令定義內(nèi)存表的首地址;FLELD
匯編指示命令定義內(nèi)存表中的各個(gè)數(shù)據(jù)域,并可以為每個(gè)數(shù)據(jù)域指定一個(gè)標(biāo)號(hào)供其他的指令引用。
注意,
MAP
和FLELD
匯編指示命令僅用于定義數(shù)據(jù)結(jié)構(gòu),并不實(shí)際分配存儲(chǔ)單元。
4)SPACE
SPACE用于分配一塊內(nèi)存單元,并用0初始化?!埃ァ迸cSPACE同義。
5)DCB
DCB用于分配一段字節(jié)的內(nèi)存單元,并用DCB命令中的expr初始化,一般可用來定義數(shù)據(jù)表格或字符串。“=”與DCB同義。
6)DCD
DCD
用于分配一段字的內(nèi)存單元,并用匯編指示命令中的expr初始化。DCD
匯編指示命令分配的內(nèi)存需要字對(duì)齊,一般可用來定義數(shù)據(jù)表格或其他常數(shù)?!?”與DCD
同義。必要時(shí),匯編程序在定義的第一個(gè)數(shù)字前最多插入3個(gè)填充字節(jié),以實(shí)現(xiàn)4字節(jié)的對(duì)齊。
7)DCI
在ARM代碼中,DCI用于分配一段字節(jié)的內(nèi)存單元,用指定的數(shù)據(jù)expr初始化,指定內(nèi)存單元存放的是代碼,而不是數(shù)據(jù)。
在Thumb代碼中,DCI用于分配一段半字節(jié)的內(nèi)存單元,用指定的數(shù)據(jù)expr初始化,指定內(nèi)存單元存放的是代碼,而不是數(shù)據(jù)。
3.其他常用匯編指示命令
在匯編程序中還有一些其他的匯編指示命令經(jīng)常會(huì)被使用。
·邊界對(duì)齊:ALIGN。
·段定義:AREA。
·匯編結(jié)束:END。
·程序入口:ENTRY。
·常量定義:EQU。
1)ALIGN
ALIGN
匯編指示命令通過添加補(bǔ)丁字節(jié)使當(dāng)前位置滿足一定的對(duì)齊方式。
2)AREA
AAREA匯編指示命令用于定義一個(gè)代碼段或數(shù)據(jù)段。ARM匯編程序設(shè)計(jì)采用分段式設(shè)計(jì),一個(gè)ARM源程序至少需要一個(gè)代碼段,大的程序可以包含多個(gè)代碼段及數(shù)據(jù)段。
3)END
END匯編指示命令用于指示匯編編譯器源文件結(jié)朿。每個(gè)匯編源文件均要使用一個(gè)END匯編指示命令,指示本源程序結(jié)束。
4)ENTRY
ENTRY匯編指示命令用于指定程序的入口點(diǎn)。
5)EQU
EQU匯編指示命令為數(shù)字常量,基于寄存器的值和程序中的標(biāo)號(hào)定義一個(gè)名稱。“?”與EQU同義。它的作用類似于C語言中的#define
用來為一個(gè)常量定義名稱。
3.4.2ARM匯編語句格式
ARM(Thumb)匯編語言的語句格式如下:
在ARM匯編語句中,所有標(biāo)號(hào)必須在一行的頂格寫,而所有指令均不能頂格寫。ARM匯編器對(duì)標(biāo)識(shí)符大小寫敏感,書寫符號(hào)及指令時(shí)字母大小寫要一致。
1.常用符號(hào)
在ARM匯編語句中,符號(hào)可以代表地址、變量和數(shù)字常量。
符號(hào)的命名規(guī)則如下:
·符號(hào)由大小寫字母、數(shù)字及下劃線組成。
·除局部標(biāo)號(hào)以數(shù)字開頭外,其他的符號(hào)不能以數(shù)字開頭。
·符號(hào)區(qū)分大小寫,且所有字符都是有意義的。
·符號(hào)在其作用域范圍內(nèi)必須唯一。
·符號(hào)不能與系統(tǒng)內(nèi)部或者系統(tǒng)預(yù)定義的符號(hào)同名。
·符號(hào)不能與助記符、匯編指示命令同名。
1)變量
程序中的變量是指其值在程序的運(yùn)行過程中可以改變的量。ARM(Thumb)匯編程序所支持的變量有數(shù)字變量、邏輯變量和字符串變量。
數(shù)字變量用于在程序的運(yùn)行中保存數(shù)字值,但注意數(shù)字值的大小不應(yīng)超出數(shù)字變量所能表示的范圍。
邏輯變量用于在程序的運(yùn)行中保存邏輯值,邏輯值只有兩種取值情況:真或假。
2)數(shù)字常量
3)變量替換
程序中的變量可通過代換操作取得一個(gè)常量。代換操作符為“$
”。
如果在數(shù)字變量前面有一個(gè)代換操作符“$
”,編譯器會(huì)將該數(shù)字變量的值轉(zhuǎn)換為十六進(jìn)制的字符串,并用該十六進(jìn)制的字符串代換“$
”后的數(shù)字變量。
如果在邏輯變量前面有一個(gè)代換操作符“$
”,編譯器會(huì)將該邏輯變量代換為它的取值(真或假)。
如果在字符串變量前面有一個(gè)代換操作符“$
”,編譯器會(huì)將該字符串變量代換為已經(jīng)賦值給它的字符串。
4)標(biāo)號(hào)
標(biāo)號(hào)是表示程序中的指令或者數(shù)據(jù)地址的符號(hào)。標(biāo)號(hào)的生成方式可以有以下三種:
(1)基于PC的標(biāo)號(hào)。基于PC的標(biāo)號(hào)是指位于目標(biāo)指令前的標(biāo)號(hào)或程序中的數(shù)據(jù)定義匯編指示命令前的標(biāo)號(hào)。
(2)基于寄存器的標(biāo)號(hào)。
(3)絕對(duì)地址。
2.表達(dá)式和運(yùn)算符
表達(dá)式是由符號(hào)、數(shù)值、單目或多目操作符以及括號(hào)組成的。在一個(gè)表達(dá)式中,各種元素的優(yōu)先級(jí)如下所示:
·括號(hào)內(nèi)的表達(dá)式優(yōu)先級(jí)最髙。
·各種操作符有一定的優(yōu)先級(jí)。
·相鄰的單目操作符的執(zhí)行順序?yàn)樽杂蚁蜃?,單目操作符?yōu)先級(jí)髙于其他操作符。
·優(yōu)先級(jí)相同的雙目操作符的執(zhí)行順序?yàn)樽宰笙蛴摇?/p>
1)數(shù)字表達(dá)式
數(shù)字表達(dá)式一般由數(shù)字常量、數(shù)字變量、運(yùn)算符和括號(hào)構(gòu)成。
(1)數(shù)字常量。數(shù)字常量分為整數(shù)數(shù)字量和浮點(diǎn)數(shù)字量。浮點(diǎn)數(shù)字量有單精度和雙精度浮點(diǎn)數(shù)之分。
(2)數(shù)字變量。數(shù)字變量用匯編指示命令GBLA或LCLA
聲明,用SETA
賦值,代表32位數(shù)字量。
(3)運(yùn)算符。與數(shù)字表達(dá)式相關(guān)的運(yùn)算符如下:
①“+”、“-”、“×”、“/”及“MOD”算術(shù)運(yùn)算符。
以上的算術(shù)運(yùn)算符分別代表加、減、乘、除和取余數(shù)運(yùn)算。例如,以x和Y表示兩個(gè)數(shù)字表達(dá)式,則:
x+Y表示x與Y的和。
x-Y表示x與Y的差。
x×Y表示x與Y的乘積。
x/Y表示x除以Y的商。
x∶MOD∶Y表示x除以Y的余數(shù)。
②“ROL”、“ROR”、“SHL”及“SHR”移位運(yùn)算符。
以x和Y表示兩個(gè)數(shù)字表達(dá)式,以上移位運(yùn)算符代表的運(yùn)算如下:
x∶ROL∶Y表示將x循環(huán)左移Y位。
x∶ROR∶Y表示將x循環(huán)右移Y位。
x∶SHL∶Y表示將x左移Y位。
x∶SHR∶Y表示將x右移Y位。
③“AND”、“OR”、“NOT”及“EOR”按位邏輯運(yùn)算符。
以x和Y表示兩個(gè)數(shù)字表達(dá)式,以上按位邏輯運(yùn)算符代表的運(yùn)算如下:
x∶AND∶Y表示將x和Y按位作邏輯與的操作。
x∶OR∶Y表示將x和Y按位作邏輯或的操作。
∶NOT∶Y表示將Y按位作邏輯非的操作。
x∶EOR∶Y表示將x和Y按位作邏輯異或的操作。
2)邏輯表達(dá)式
邏輯表達(dá)式由邏輯常量(TRUE
或者FALSE)、邏輯運(yùn)算符、關(guān)系操作符和括號(hào)組成,取值為{FALSE}或{TRUE}。
(1)關(guān)系操作符。
以x和Y表示兩個(gè)邏輯表達(dá)式,以上運(yùn)算符代表的運(yùn)算如下:
x=Y表示x等于Y。
x>Y表示x大于Y。
x<Y表示x小于Y。
x>=Y表示x大于或等于Y。
x<=Y表示x小于或等于Y。
x/=Y表示x不等于Y。
x<>Y表示x不等于Y。
(2)邏輯運(yùn)算符。“LAND”、“LOR”、“LNOT”及“LEOR”運(yùn)算符。
以x和Y表示兩個(gè)邏輯表達(dá)式,以上邏輯運(yùn)算符代表的運(yùn)算如下:
x∶LAND
∶Y表示將x和Y作邏輯與的操作。
x∶LOR
∶Y表示將x和Y作邏輯或的操作。
∶LNOT
∶Y表示將Y作邏輯非的操作。
x∶LEOR∶Y表示將x和Y作邏輯異或的操作。
3)字符串表達(dá)式
字符串表達(dá)式由字符串、字符串常量、運(yùn)算符和括號(hào)組成。字符串的最大長度為512字節(jié),最小長度為0字節(jié)。
(1)字符串。
(2)字符串常量。
(3)運(yùn)算符。
常用的與字符串表達(dá)式相關(guān)的運(yùn)算符如下:
①“LEN”運(yùn)算符。
②“CHR”運(yùn)算符。
③“STR”運(yùn)算符。
④“LEFT”運(yùn)算符。
⑤“Right”運(yùn)算符。
⑥“CC”運(yùn)算符。
4)基于寄存器和PC的表達(dá)式
基于寄存器的表達(dá)式表示某個(gè)寄存器的值加上或減去一個(gè)數(shù)字表達(dá)式。
基于PC的表達(dá)式表示PC寄存器的值加上或減去一個(gè)數(shù)字表達(dá)式?;赑C的表達(dá)式通常由程序中的標(biāo)號(hào)與一個(gè)數(shù)字表達(dá)式組成。
3.4.3ARM匯編語言格式
在ARM(Thumb)匯編語言程序中,以程序段為單位組織代碼。段是相對(duì)獨(dú)立的指令或數(shù)據(jù)序列,具有特定的名稱。段可分為代碼段和數(shù)據(jù)段,代碼段的內(nèi)容為執(zhí)行代碼,數(shù)據(jù)段存放代碼運(yùn)行時(shí)需要用到的數(shù)據(jù)。
可執(zhí)行映像文件通常由以下幾部分構(gòu)成:
·一個(gè)或多個(gè)代碼段,代碼段的屬性為只讀。
·零個(gè)或多個(gè)包含初始化數(shù)據(jù)的數(shù)據(jù)段,數(shù)據(jù)段的屬性為可讀寫。
·零個(gè)或多個(gè)不包含初始化數(shù)據(jù)的數(shù)據(jù)段,數(shù)據(jù)段的屬性為可讀寫。
鏈接器根據(jù)系統(tǒng)默認(rèn)或用戶設(shè)定的規(guī)則,將各個(gè)段安排在存儲(chǔ)器中的相應(yīng)位置。因此源程序中段之間的相對(duì)位置與可執(zhí)行的映像文件中段的相對(duì)位置一般不會(huì)相同。
3.4.4ARM匯編語言基本結(jié)構(gòu)程序設(shè)計(jì)方法
1.順序結(jié)構(gòu)設(shè)計(jì)方法
順序結(jié)構(gòu)表示程序中的各操作是按照它們出現(xiàn)的先后順序執(zhí)行的,其流程如圖3.7所示。圖3.7順序結(jié)構(gòu)
【例3.1】兩個(gè)32位數(shù)相加,并將結(jié)果儲(chǔ)存到存儲(chǔ)器單元。
解:兩個(gè)32位數(shù)保存在內(nèi)存value1和value2單元。先用偽指令LDR取出第一個(gè)操作數(shù)的地址,再通過間接尋址取出操作數(shù)。以后的操作數(shù)地址都是通過加法(加4)來取得,而不是通過偽指令LDR。這樣的選擇,使指令的執(zhí)行會(huì)更快一些。最后用一條跳轉(zhuǎn)指令結(jié)束程序。使用這段代碼時(shí),可以根據(jù)所使用的匯編環(huán)境再行修改。
【例3.2】查表程序。通過查表來求0~8的階乘。
解:查表程序是一種典型的順序程序。查表可以避免大量的計(jì)算,快捷地得到所需的結(jié)果。一般情況下,通過基址和變址尋址就可以獲得查表的結(jié)果。
·把表格的首地址存入基址寄存器。
·通過查表項(xiàng)得到偏移量,有時(shí)需要簡單計(jì)算。
·通過適當(dāng)?shù)募虞d指令就可以得到查表的結(jié)果。
整個(gè)程序安排了兩個(gè)段:代碼段和數(shù)據(jù)段。數(shù)據(jù)段里是要查的表格,當(dāng)然還有查表項(xiàng)和結(jié)果項(xiàng)。在查表以前,對(duì)查表項(xiàng)要作“乘4”的處理。因?yàn)槊總€(gè)表格項(xiàng)都是32位數(shù)據(jù)(4個(gè)字節(jié)),查表項(xiàng)加1,查表的地址要加4。查表項(xiàng)乘4才是要查表的位置。程序中通過左移兩位來實(shí)現(xiàn)“乘4”。程序中還使用了以R1為第二操作數(shù)的基址變址尋址,執(zhí)行一條指令就得到查表的結(jié)果。程序代碼如下:
2.選擇結(jié)構(gòu)設(shè)計(jì)方法
選擇結(jié)構(gòu)表示程序的處理步驟出現(xiàn)了分支,它需要根據(jù)某一特定的條件選擇其中的一個(gè)分支執(zhí)行。選擇結(jié)構(gòu)有單選擇、雙選擇和多選擇三種形式,如圖3.8所示。圖3.8選擇結(jié)構(gòu)
ARM指令的條件碼可以分為兩類。一類是從標(biāo)志出發(fā),4個(gè)標(biāo)志對(duì)應(yīng)8個(gè)條件;另一類是從數(shù)的比較出發(fā),根據(jù)有符號(hào)數(shù)、無符號(hào)數(shù)的比較有10種情況,對(duì)應(yīng)了10個(gè)條件碼。當(dāng)然,這兩類條件碼有重復(fù)。例如,條件
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 回復(fù)紀(jì)委的回復(fù)函
- 二零二五年度電子商務(wù)專業(yè)校企合作人才培養(yǎng)專項(xiàng)協(xié)議3篇
- 學(xué)校一崗雙責(zé)工作制度范文
- 二零二五年度物業(yè)服務(wù)合同服務(wù)內(nèi)容2篇
- 2024版特許經(jīng)營合同的經(jīng)營區(qū)域界定
- 二零二五年度廚師勞務(wù)聘用及餐飲品牌推廣合同3篇
- 二零二五年度綠色節(jié)能辦公設(shè)備采購合同6篇
- 《出口貨物托運(yùn)手續(xù)》課件
- 電器行業(yè)安全生產(chǎn)工作總結(jié)
- 二零二五年度幼兒園教師崗位績效獎(jiǎng)金發(fā)放合同3篇
- JTG 3441-2024公路工程無機(jī)結(jié)合料穩(wěn)定材料試驗(yàn)規(guī)程
- 羊肉銷售人員工作匯報(bào)
- 律所標(biāo)書模板
- 安徽省合肥市包河區(qū)四十八中學(xué)2023-2024學(xué)年數(shù)學(xué)七年級(jí)第一學(xué)期期末學(xué)業(yè)質(zhì)量監(jiān)測(cè)試題含解析
- 美術(shù)概論-課件
- 危險(xiǎn)化學(xué)品安全監(jiān)管執(zhí)法培訓(xùn)課件
- 保潔供方管控要點(diǎn)
- 空氣源熱泵冷暖空調(diào)、熱水項(xiàng)目施工方案
- 《行政組織學(xué)》期末復(fù)習(xí)指導(dǎo)
- 基于深度學(xué)習(xí)的醫(yī)學(xué)圖像增強(qiáng)與生成
- 2023《樓體亮化工程施工合同》電子版
評(píng)論
0/150
提交評(píng)論