《微機原理與嵌入式系統基礎》課件第3章_第1頁
《微機原理與嵌入式系統基礎》課件第3章_第2頁
《微機原理與嵌入式系統基礎》課件第3章_第3頁
《微機原理與嵌入式系統基礎》課件第3章_第4頁
《微機原理與嵌入式系統基礎》課件第3章_第5頁
已閱讀5頁,還剩161頁未讀 繼續免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

第3章ARM7TDMI指令系統3.1ARM7TDMI編程模型3.2ARM7TDMI的尋址方式3.3ARM7TDMI指令的條件執行3.4ARM指令集3.5Thumb指令集本章小結習題

3.1ARM7TDMI編程模型

簡單地講,編程模型就是程序員看到的計算機工作模型。編程模型屏蔽了計算機硬件的具體細節,是計算機硬件在工作原理層和編程應用層的抽象模型。它既屏蔽了硬件電路的細節,又準確細致地表示了計算機的工作原理和過程。

ARM處理器的指令集定義了各種指令。程序員可以用這些指令完成各種運算處理。每一條指令的執行,都可看做是從指令執行前的數據狀態到指令完成后的數據狀態的轉換。ARM處理器中有37個程序可訪問寄存器,分屬于7種不同的模式,處理器任何時刻只能訪問當前模式下的寄存器(參見表2-2)。對于程序員來說,編寫的程序都是建立在當前模式下寄存器基礎之上的,這些可訪問寄存器構成了應用程序的編程模型。

3.2ARM7TDMI的尋址方式

匯編指令中對尋址方式的理解有助于設計更高效的匯編程序。所謂尋址方式,就是指令中尋址被操作數據的方式或方法,其關鍵在于如何映射出該操作數的地址。

ARM處理器基于RISC結構,所有的數據運算類指令只能對CPU內部的數據進行處理。如果待處理的數據不在處理器中,例如存儲器數據,則必須預先加載到CPU后才能被運算,運算后再將結果寫回到存儲器。

ARM處理器尋址方式可以分為兩大類:數據處理指令操作數尋址方式和存儲器訪問指令操作數尋址方式,共8種基本尋址方式。3.2.1數據處理指令操作數尋址方式

數據處理指令操作數的尋址方式又可分為立即數尋址方式、寄存器尋址方式和寄存器移位尋址方式3種類型。

1.立即數尋址方式

立即數尋址方式的操作數直接包含在指令中,也就是說,取出指令的同時也就取出了對應的操作數(這樣的操作數稱為立即數操作數,簡稱為立即數)。

應用示例:

MOV R0,

#0 ;將立即數0送入R0

SUB

R0,R0,#1 ;?R0的值減立即數1,然后將結果

送回R0

MOV R0,#0xFF000;將立即數0xFF000送入R0前綴“#”號表示立即數,“0x”表示十六進制數值。

由于ARM的指令機器碼長度為固定的32?bit,其中除了有操作數外還有操作碼,因此對含在指令中的立即數有特殊的要求,ARM規定:指令中的立即數必須可由一個8?bit的常數經過循環右移偶數位(0,2,4,…,26,28,30)得到。符合這種特征的立即數也稱作8位位圖立即數,簡稱8位圖數據。對于不符合8位圖格式的數據,只能使用“文字池”方式,通過存儲器訪問指令加載,詳見后文。合法的8位圖數據如0x3FC(0xFF<<2)、0、0xF0000000(0xF0<<24)、200(0xC8)、0xF0000001(0x1F<<28)等,非法的8位圖數據如0x1FE、511、0xFFFF、0x1010、0xF0000010等,這些數據不能由一個8位的常數循環右移偶數位得到。

2.寄存器尋址方式

當指令執行的操作數是ARM處理器某個寄存器中的數據時,可在指令中直接指定該寄存器,使用其中的數據作為操作數,這種尋址方式稱為寄存器尋址方式。應用示例:

MOV R0,R1 ;將R1中的值送入R0

SUB

R0,R1,R2 ;將R1中的值減去R2的值,結果

保存到R0中

寄存器尋址方式下,操作數在ARM處理器的內部寄存器中,不需要訪問存儲器,因而可以獲得較高的運行速度。

3.寄存器移位尋址方式

寄存器移位尋址是ARM指令集特有的尋址方式,即ARM指令中源寄存器操作數在送往ARMALU(算術邏輯單元)執行時,先經過桶形移位處理的方式,目的是增加代碼的執行效率。應用示例:

MOV R0,R1,LSL#3 ;?R1的值邏輯左移3位,

結果放入R0無溢出時,

即是R0=R1×8

MOV R0,R1,RORR2 ;?R1的值循環右移R2位,

然后放入R0

AND R0,R1,R2,LSLR3 ;

R2的值邏輯左移R3位,

再和R1的值相“與”,

結果放入R03.2.2存儲器訪問指令操作數尋址方式

對存儲器操作數尋址的主要問題是如何產生操作數的訪問地址。該方式又可以分為寄存器間接尋址、基址變址尋址、相對尋址、多寄存器尋址(塊拷貝尋址)和堆棧尋址5種類型。

1.寄存器間接尋址

ARM指令的操作數存儲在ARM處理器的某個寄存器指向的存儲單元中。也就是說,該寄存器中的內容是該操作數在存儲器中的存儲單元地址,即寄存器用作操作數的地址指針,真實的操作數是存儲在存儲器單元中的數據。

也可以這樣理解:操作數本身存儲在存儲器中,而操作數的存儲地址存儲在ARM的某個寄存器中,通過該寄存器指針,指令從存儲器中找到操作的數據。注意寄存器間接尋址方式和寄存器尋址方式的差別,如圖3-1所示。圖3-1LDR指令與MOV指令的差別應用示例:

LDRR0,[R1] ;將R1指向的存儲器單元中的數據讀出,

保存在R0中

MOVR0,R1 ;?R1的值復制到R0

2.基址變址尋址

基址變址尋址就是將作為基地址的寄存器(簡稱基址寄存器)中的內容與指令中給出的地址偏移量相加,形成操作數的存儲器地址的一種尋址方式。基址變址尋址用于訪問基址附近的存儲單元,常用于查表、數組操作、功能部件寄存器訪問等。基址變址尋址方式又分為基址加偏移量和基址加索引兩種尋址方式。

(1)基址加偏移量尋址中,最大偏移量范圍為上下4?KB。將基址寄存器中的內容加上或減去地址偏移量,形成操作數的存儲器地址。

應用示例:

LDRR0,[R1,#0x0C] ;將R1+0x0C所指向的存儲器單元

內容加載到R0中

STRR0,[R1,#-4]! ;將R0中的值存儲到R1-4所指向的

存儲器單元中,然后R1=R1-4

(2)基址加索引尋址中,包含一個用作基址的寄存器和一個用作索引的寄存器。以索引寄存器中的值作為偏移量與基址寄存器中的值相加,其和作為操作數的存儲地址。

應用示例:

LDR

R0,[R1,R2] ;將R1+R2指向的存儲器單元內容

加載到R0中

STRR0,[R1,R2,LSL#1] ;將R0的值保存到1+R2×2

所指向的存儲器單元中

3.相對尋址

相對尋址是基址變址尋址的一種特例。其中基址寄存器是程序計數器PC,而不是通用的寄存器。該尋址方式中的偏移量實際上是操作數存儲器單元與當前PC值的相對位置,即指令執行時操作數存儲器單元的地址等于PC的值加上指令中提供的偏移量DL。如圖3-2所示,當執行LAB單元中的指令BLarithfunc時,當前PC值為LAB+8(因為三級流水線),相對尋址的偏移量則為DL=arithfunc-(LAB+8),即ARM處理器將跳轉到PC+DL處執行子程序arithfunc。圖3-2相對尋址方式應用示例:

Start

MOV R0,#0

MOV R1,#3

MOV R2,#2

BL arithfunc

... ;其他指令

arithfunc

CMP R0,#num

MOV HS PC,LR

4.多寄存器尋址(塊拷貝尋址)

多寄存器尋址就是在ARM處理器與存儲器間用一條指令完成多個寄存器值的傳送,即允許用一條指令實現傳送16個寄存器的任何子集。該方式也稱為塊拷貝尋址,應用于多寄存器加載指令(LDM)和多寄存器存儲指令(STM),可以實現將一片連續的存儲器區域中的數據依次加載到指定的寄存器組中,或反之將指定的寄存器組數據依次存儲到一片連續的存儲器區域中。應用示例:

LDMIA R1!,{R2-R7,R12}

;將R1所指向的存儲器區域中的內容依次加載到R2~R7、

R12中(每傳送一個寄存器值后,R1的值自動加4并保存)

STMIA R0!,{R2-R7,R12}

;將R2~R7、R12中的值依次保存到R0所指向的存儲器

區域中(每傳送一個寄存器值后,R0的值自動加4并保存)

使用多寄存器尋址指令時,寄存器子集的順序應按由小

到大的順序排列,連續的寄存器可用“-”連接,否則用“,”分隔書寫。

5.堆棧尋址

ARM使用多寄存器加載指令(LDM)和多寄存器存儲指令(STM)的“變種”完成堆棧操作。堆棧操作中的指針寄存器(即堆棧指針SP)固定為R13,SP初始化時指向堆棧區域的頂,隨著堆棧內容的增減,堆棧指針也做相應的移動。通過對LDM指令和STM指令附加后綴(FA、FD、EA、ED),ARM處理器支持滿遞增(FA)、滿遞減(FD)、空遞增(EA)和空遞減(ED)4種

堆棧。使用堆棧時,進/出堆棧指令后綴(FA、FD、EA、ED)要配對,即如果入棧操作用的是STMFD指令,則對應的出棧應選用LDMFD指令。

應用示例:

STMFD SP!,{R1-R7,LR};將R1~R7、LR入棧。滿遞

減堆棧

LDMFD SP!,{R1-R7,PC};數據出棧,放入R1~R7、

PC寄存器。滿遞減堆棧3.3ARM7TDMI指令的條件執行

大多數處理器的指令集支持條件轉移指令,當條件滿足時,發生轉移;條件不滿足時,則順序執行。但ARM將條件執行特性擴展到所有的指令,ARM指令集中每條指令都可以條件執行,這也是ARM指令系統的特點之一。所謂ARM指令條件執行,是指在指令碼中含有本條指令的執行條件,當CPSR中的條件碼標志滿足時,處理器執行本條指令,否則本條指令等價于空操作。使用指令條件碼可實現高效的邏輯操作,提高代碼執行效率。ARM處理器支持16種指令條件碼,如表3-1所示。

ARM處理器支持16種指令條件碼,分別對應了CPSR寄存器標志位(N、Z、C、V)的16個值組合狀態,處理器根據CPSR中標志位N、Z、C和V的值來確定指令是執行還是跳過。表3-1給出了這些條件碼助記符及其對應的狀態標志值。ARM指令使用條件碼助記符來指定本指令的執行條件。其中條件(AL)

是缺省條件,可以省略。如果指令不含有條件碼,就默認是該條件。下面是對條件碼助記符的詳細說明:

●?EQ:等于,如果比較之后相等,則該條件滿足。

●?NE:不等于,如果比較之后不等,則該條件滿足。

●?CS:無符號數比較,當第1操作數大于或等于第2操作數時,該條件滿足。

●?CC:無符號數比較,當第1操作數小于第2操作數時,該條件滿足。

●?MI:負號,如果算術操作之后結果為負,則該條件滿足。

●?PL:正號,如果算術操作之后結果為正,則該條件滿足。

●?VS:有符號數運算,如果有溢出,則該條件滿足。

●?VC:有符號數運算,如果無溢出,則該條件滿足。●?HI:無符號數比較,當第1操作數大于第2操作數時,該條件滿足。

●?LS:無符號數比較,當第1操作數小于或等于第2操作數時,該條件滿足。

●?GE:有符號數比較,當第1操作數大于或等于第2操作數時,該條件滿足。

●?LT:有符號數比較,當第1操作數小于第2操作數時,該條件滿足。

●?GT:有符號數比較,當第1操作數大于第2操作數時,該條件滿足。

●?LE:有符號數比較,當第1操作數小于或等于第2操作數時,該條件滿足。●?AL:無條件執行,缺省條件,不用顯示聲明。

●?NV:“never”條件是不能使用的。ARM公司已指出,將來可能將這部分指令空間另作他用。

ARM數據處理指令均可選擇本指令執行結果是否影響CPSR條件碼標志,如果希望運算結果影響條件碼標志,則在指令助記符后加后綴“S”;否則,指令的執行不影響CPSR原標志位狀態。應用舉例:

ADDR0,R1,R2;?R0=R1+R2,運算結果不影響CPSR

狀態值

ADDSR0,R1,R2;?R0=R1+R2,并且根據結果更新

CPSR中條件標志碼

ADDEQSR0,R1,R2 ;當CPSR中Z=1時,執行

R0=R1+R2,并且根據結果更新

?CPSR中條件標志碼;若Z=0,則

跳過本指令不執行細心的讀者將注意到,條件是成雙的,對于任一條件都有其反條件(除了“always”,因為“never”不能使用)。因此,只要能用條件指令來實現“if…then…”,就能用帶有相反條件的指令加入“…else…”。

對于Thumb指令集,只有B指令具有條件碼執行功能。此指令的條件碼同表3-1。如果為無條件執行,則條件碼助記符AL不用在指令中書寫。

使用條件執行語句編程,可以提高編程效率,還可以少用轉移指令,避免轉移指令引起的處理器流水線的清空與重建,提高ARM處理器的效率。應用示例:

①比較兩個值大小,并進行相應加1處理,C代碼為

if(a>b) a++;

else b++;

對應的ARM指令如下(其中R0為a,R1為b):

CMP R0,R1 ;R0與R1比較

ADDHI R0,R0,#1 ;選擇執行,若R0>R1,則

R0=R0+1

ADDLS R1,R1,#1 ;選擇執行,若R0≤1,則

R1=R1+1②若兩個條件均成立,則將這兩個數值相加,C代碼為

if((a!=10)&&(b!=20)) a=a+b;

對應的ARM指令如下(其中R0為a,R1為b):

CMPR0,#10 ;比較R0是否為10

CMPNE R1,#20

;選擇執行,若R0不為10,則比較R1

是否為20

ADDNE R0,R0,R1;選擇執行,若R0不為10且R1不為

20,則R0=R0+R13.4ARM?指令集

第2章中已經介紹過,ARM7TDMI(-S)處理器具有ARM和Thumb兩種工作狀態,因此其指令集也對應包括32位的ARM指令集和16位的Thumb指令集。ARM指令集共有6種類型的指令,分別為分支指令、數據處理指令、狀態寄存器指令、寄存器加載/存儲指令、協處理器指令和異常產生指令。本節首先介紹ARM指令的基本格式及靈活的操作數,然后重點介紹ARM指令集,而對Thumb指令集僅作簡要介紹。3.4.1ARM指令的基本格式

ARM指令的基本格式如下:

<opcode>{<cond>}{S}<Rd>,<Rn> {,<operand2>}

其中,<>號內的項是必需的,{}號內的項是可選的。如<opcode>是指令助記符,是必須含有的,而{<cond>}為指令執行條件,是依據實際需要的可選項,若不書寫,則使用默認條件AL(無條件執行)。

指令格式中各參數含義如下:

opcode:指令助記符,如LDR、STR等。用于指定指令的操作功能。

cond:執行條件,如EQ、NE等,參考表3-1。用于指定指令的執行條件。

S:用于指定指令的執行是否影響CPSR寄存器的值,書寫時會影響CPSR。

Rd:目標寄存器。用于存放運算的結果。

Rn:第1個操作數的寄存器。用于存放參與運算的操作

數1。

operand2:第2個操作數。用于指定參與運算的操作數2。

指令格式舉例:

LDR

R0,[R1] ;將R1指向的存儲器單元內容加載到R0,

執行條件AL

BEQDATAEVEN ;分支指令,執行條件EQ,即相等

時跳轉到DATAEVEN

ADDSR0,R1,#1 ;加法指令,R1+1=>R0,并且根

據結果影響CPSR寄存器

SUBNES R0,R1,#0x10 ;帶條件的減法指令,執行條件

NE,即不相等時,執行R1-

0x10=>R0,并且根據結果影響

CPSR寄存器在ARM指令中,靈活地使用第2個操作數能夠提高代碼效率。第2個操作數有如下幾種形式:

(1)?#immed_8r——立即數(也可以是常數表達式)。

該常數必須是8位位圖立即數。

常數表達式應用舉例:

MOV R0,#1 ;?R0=1

AND R0,R1,#0x0F ;?R1和0x0F進行“與”運算,結果

保存到R0中

LDR R0,[R1],#-4;將R1指向的存儲器單元內容加載

到R0中,并且R1=R1-4

(2)?Rm——寄存器方式。

在寄存器方式下,操作數即為寄存器中的數值。

寄存器方式應用舉例:

SUB R0,R1,R2 ;?R0=R1-R2

MOV PC,R0 ;?PC=R0,ARM處理器將跳轉到

R0指定地址處執行

LDR R0,[R1],-R2;將R1指向的存儲器單元內

容加載到R0,修改R1=R1-R2

(3)?Rm,shift——寄存器移位方式。

使用寄存器的移位結果作為操作數,但Rm值保持不變。指令中使用移位后綴指定移位方式。具體的移位方式有以下

5種:

●?LSL:邏輯左移(LogicalShiftLeft),將Rm寄存器中的內容邏輯左移,寄存器中字的低端空出的位補0。

●?LSR:邏輯右移(LogicalShiftRight),將Rm寄存器中的內容邏輯右移,寄存器中字的高端空出的位補0。●?ASR:算術右移(ArithmeticShiftRight),將Rm寄存器中的內容算術右移,移位過程中保持操作數的最高位不變。因此,當被移位的操作數為正數時,則寄存器中字的高端空出的位補0;當被移位的操作數為負數時,則寄存器中字的高端空出的位補1;保持移位后的數據正負屬性不變。

●?ROR:循環右移(ROtateRight),將Rm寄存器中的內容循環右移,從寄存器中字的最低端移出的位填入到寄存器中字的最高端空出的位。●?RRX:帶擴展的循環右移(RotateRighteXtendedby1place),將Rm寄存器中的內容進行帶C標志的循環右移,操作數右移一位,最高端空出的位用原C標志值填充,同時最低端移出的數據位移動到C中。

各種移位操作如圖3-3所示。圖3-3移位操作示意圖以上5種移位方式,移位計數均可由立即數或寄存器指定:

ASR#n 算術右移n位(1≤n≤32)。

LSL#n 邏輯左移n位(0≤n≤31)。

LSR#n 邏輯右移n位(1≤n≤32)。

ROR#n 循環右移n位(1≤n≤31)。

RRX 帶擴展的循環右移1位。

typeRs 其中,type為ASR、LSL、LSR和ROR中的一

種;Rs為偏移量寄存器,低8位有效。通常

使用通用寄存器作為Rs。寄存器偏移方式應用舉例:

ADDR0,R1,R1,LSL#3

;?R0=R1*9,即將R1的值擴

大9倍,且指令執行完R1的

值保持不變

SUB

R0,R1,R2,LSR#2;?R0=R1-R2/4,且R1、R2

的值保持不變

MOVR0,R1,RRX ;將R1帶擴展的循環右移1位,

存入R0中3.4.2ARM存儲器訪問指令

ARM是基于RISC架構的處理器。ARM處理器無法像CISC架構的處理器那樣,讓存儲器中的數據直接參與指令的運算,而只能對處理器內部的數據進行運算;在需要對存儲器中的數據進行處理時,要先使用加載指令將存儲器中的數據讀取到ARM的內部寄存器,再參與指令中指定的運算;運算結束后,使用存儲指令將ARM內部寄存器中的運算結果存儲到存儲器中。ARM處理器采用加載/存儲(load/store)體系結構來實現對存儲器的讀/寫訪問。

ARM存儲器訪問指令主要包括3種基本的加載/存儲指令:單寄存器加載/存儲指令、多寄存器加載/存儲指令和單寄存器交換指令SWP(SingleregistersWaP),可實現字、無符號半字/有符號半字、無符號字節/有符號字節等類型數據的加載/存儲操作。其中多寄存器加載/存儲指令可實現一條指令加載/存儲多個寄存器的內容,雖然該指令的靈活性比單寄存器方式指令差,但是可以對多個字數據更有效地傳送,提高了數據傳送效率,常用于保存和恢復工作寄存器以及拷貝存儲器中的一塊數據。

SWP指令是一個寄存器與存儲器的數據交換指令,常用于操作系統信號量的操作等,以保證存儲數據與進程數據的同時性。

ARM7處理器是馮·諾依曼存儲結構,程序存儲器空間、數據存儲器空間及I/O映射空間統一編址,對這些空間的訪問均使用加載/存儲指令進行。ARM存儲器訪問指令見表3-2。表3-2ARM存儲器訪問指令

1.LDR和STR——(單寄存器)加載存儲指令

LDR(LoaDRegisterfrommemory)指令從存儲器加載一個數據到寄存器中,STR(SToreRegistertomemory)指令則相反,把寄存器中的一個數據存儲到存儲器中。LDR和STR指令搭配不同后綴可以實現字節、半字或字數據的訪問。當加載字節或半字符號數時,依據數據符號位,寄存器高端補0(正數)或補1(負數)。

1)加載/存儲——字數據

指令格式:

LDR{cond}Rd,<地址>;加載指定地址單元的(字)數據

到Rd中

STR{cond}Rd,<地址>;存儲Rd中的(字)數據到指定地

址單元中<地址>=基址寄存器

(Rn)+偏移量

LDR/STR指令尋址非常靈活,尋址由兩部分組成:第一部分是一個基址寄存器,任一個通用寄存器都可以選用作基址寄存器;另一部分為一個地址偏移量。地址偏移量有以下3種格式:

(1)立即數。立即數可以是一個無符號的數值。這個數據可以加到基址寄存器,也可以從基址寄存器中減去這個數值。它的取值范圍為0~+4095的整數,它的書寫格式為:#常數或者#常數表達式。

應用示例:

LDRR0,[R1,#0x12] ;將R1+0x12指向的存儲器單元的

數據加載到R0中(指令執行完,

R1的值不變)

LDRR0,[R1,#-0x12] ;將R1-0x12指向的存儲器單元的

數據加載到R0中(指令執行完,

R1的值不變)

LDR

R0,[R1] ;將R1指向的存儲器單元的數據加

載到R0中(零偏移)

(2)寄存器。寄存器中的數值可以加到基址寄存器,也可以從基址寄存器中減去這個數值。

應用示例:

LDR

R0,[R1,R2]

;將R1+R2指向的存儲器單元的數

據加載到R0中(指令執行完,

R1、R2的值不變)

LDR

R0,[R1,-R2] ;將R1-R2指向的存儲器單元的數

據加載到R0中(指令執行完,R1、

R2的值不變)

(3)寄存器及移位常數。寄存器移位后的值可以加到基址寄存器,也可以從基址寄存器中減去這個數值。

應用示例:

LDR

R0,[R1,R2,LSL#2] ;將R1+R2*4指向的存儲器

單元的數據加載到R0中

(指令執行完,R1、R2的值不變)

LDR

R0,[R1,-R2,LSL#2] ;將R1-R2*4指向的存儲器

單元的數據加載到R0中

(指令執行完,R1、R2的值不變)

2)前索引偏移與后索引偏移

ARM指令系統支持前索引和后索引,還允許前索引指定是否修改寄存器指針。

(1)前索引偏移。在數據傳送之前,將先計算基地址與偏移量,其結果作為傳送數據的存儲地址。若使用后綴“!”,則結果寫回到Rn中,且Rn不允許為R15;否則,不修改基址寄

存器。

應用示例:

LDRRd,[Rn,#0x04]! ;將Rn+4指向的存儲器單元的數據

加載到Rd中(指令執行完,Rn的

值更新為Rn+4)

LDR

Rd,[Rn,#-0x04] ;將Rn-4指向的存儲器單元的數

據加載到Rd中(指令執行完,Rn

的值不變)

(2)后索引偏移。Rn的值用作傳送數據的存儲地址。在數據傳送后,將偏移量與Rn相加,結果寫回到Rn中,Rn不允許是R15。

應用示例:

LDR

Rd,[Rn],#0x04 ;將Rn指向的存儲器單元的數據加

載到Rd中(指令執行完,Rn的值

更新為Rn+4)

(3)程序相對偏移。程序相對偏移是前索引形式的另一個版本,基址寄存器默認為PC。不能使用后綴“!”。匯編程序中,通常直接使用語句標號指定訪問單元。

應用示例:

LDRRd,label ;將標號label的地址中存放的數據加

載到Rd中

說明:label為程序標號,label必須是在當前指令的±4KB范圍內。

注意:這類指令要求操作數字對齊存儲。

3)加載/存儲——無符號/有符號半字、無符號/有符號字節數據

指令格式:

LDR{cond}SH Rd,<地址>

;加載指定地址單元的數據(有符號半字)到Rd中,

;依據被加載數據的正/負,Rd的高16比特補全

;?0或補全1

LDR{cond}H Rd,<地址>

;加載指定地址單元的半字數據到Rd最低16位,

高16位清0

STR{cond}H

Rd,<地址> ;將Rd中的半字數據存儲到指定地址單元,要存儲的數據是Rd最低16位

LDR{cond}SBRd,<地址> ;加載指定地址單元的數據(有符號字節)到Rd中,依據被加載數據的正/負,Rd的高24比特補全0或補全1

LDR{cond}B Rd,<地址> ;加載指定地址單元的字節數據到Rd最低8位,高24位清0

STR{cond}B Rd,<地址> ;將Rd中的字節數據存儲到指定地址單元,要存儲的數據是Rd最低8位這類LDR/STR指令的偏移量格式、尋址方式與加載/存儲字指令相同,不再冗述。

有符號的半字/字節數據加載指令使用數據符號位加載擴展高位域到32位;無符號的半字/字節數據加載指令使用零擴展高位域到32位。而存儲指令則是使用寄存器有效位數據直接寫存儲器單元。

注意:此類指令要求操作數半字對齊存儲。

應用示例:

LDRSB R0,[R1,R2] ;將R1+R2指向的存儲單元中的字節數據加載到R0中,R0中高24位用符號位擴展

LDRSH R0,[R1] ;將R1指向的存儲單元中的半字數據加載到R0,R0中高16位用符號位擴展

LDRH R0,[R1],#2

;將R1指向的存儲單元中的半字數據加載到R0,R0中高16位用零擴展,并且R1=R1+2

STRH R0,[R1,#2]! ;將R0中的低16位保存到R1+2所指向的存儲單元中,并且R1=R1+2

LDR/STR指令用于對內存變量的訪問、內存緩沖區數據的訪問、查表、外圍部件的控制操作等。若使用LDR指令加載數據到PC寄存器,則實現程序跳轉功能。

2.LDM和STM——多寄存器加載/存儲指令

指令格式:

LDM{cond}<模式> Rn{!},reglist{^}

STM{cond}<模式> Rn{!},reglist{^}指令功能:多寄存器加載/存儲指令可以實現在一組寄存器與一塊連續的內存單元之間傳輸數據。LDM(LoaDMutipleregistersfrommemory)指令是把多個內存單元的內容加載到多個寄存器中;STM(SToreMutipleregisterstomemory)指令是把多個寄存器的內容存儲到多個內存單元中,這多個寄存器是R0~R15的任意組合(即R0~R15的任何子集)。

指令說明:LDM/STM的主要用途是現場保護、數據復制、參數傳送等。其指令格式說明如圖3-4所示。圖3-4LDM和STM指令格式說明指令格式中的<模式>項用于指定指針寄存器的使用方式,有如下8種,前面4種用于數據塊的傳輸,后面4種是堆棧操作。

(1)?IA:每傳送一個字數據后,指針寄存器加4(先傳數據,后遞增撥移指針)。

(2)?IB:每傳送一個字數據前,指針寄存器先行加4(先遞增撥移指針,再傳送數據)。

(3)?DA:每傳送一個字數據后,指針寄存器減4(先傳數據,后遞減撥移指針)。

(4)?DB:每傳送一個字數據前,指針寄存器先行減4(先遞減撥移指針,再傳送數據)

(5)?D:滿遞減堆棧。

(6)?ED:空遞減堆棧。

(7)?FA:滿遞增堆棧。

(8)?EA:空遞增堆棧。

注意事項:

①多寄存器加載/存儲指令只能訪問字數據。

②指令格式中的Rn寄存器為基址寄存器,它指向了所要訪問存儲塊的起始地址。Rn不允許為R15(PC)。③基址寄存器Rn在指令執行結束后有兩種選擇:一種是保持Rn的內容指令執行前后不變化,指令中的Rn無“!”后綴;另一種是讓Rn指向操作結束的地址,指令中的Rn加上“!”后綴,表示最后的地址寫回到Rn。

LDM指令執行前后寄存器的狀態如圖3-5所示。圖3-5LDM指令執行前后寄存器狀態應用示例:

LDMIA R0,{R1-R4} ;將R0指向的存儲塊的多字數據依次分別加載到R1~R4中,指令執行完后R0的值不變

LDMIA R0!,{R1-R4} ;將R0指向的存儲單元中的多字數據加載到R1~R4中,并且每加載一個字數據,R0的值加4④寄存器列表reglist可包含多于一個寄存器或包含寄存器范圍,使用“,”分開,如{R1,R2,R6-R9},寄存器由小到大排列。

⑤寄存器與內存單元的對應關系是,編號低的寄存器對應于存儲單元中低地址單元,編號高的寄存器對應于存儲單元中高地址單元。

⑥“^”后綴不允許在用戶模式或系統模式下使用,若在LDM指令寄存器列表中包含有PC,那么除了正常的多寄存器傳送外,還會把SPSR也拷貝到CPSR中,通常可用于異常處理返回。注意:此類指令要求操作數字對齊存儲。

在進行數據復制時,先設置好源數據指針和目的指針,然后使用多寄存器尋址/塊拷貝尋址指令LDMIA/STMIA、LDMIB/STMIB、LDMDA/STMDA、LDMDB/STMDB進行讀取/存儲;而進行堆棧操作時,則要先設置堆棧指針,一般使用SP,然后使用堆棧尋址指令STMFD/LDMFD、STMED/

LDMED、STMFA/LDMFA和STMEA/LDMEA實現堆棧操作。多寄存器存儲指令示意圖如圖3-6所示,其中R0為指令執行前的基址寄存器,指令執行前R0指向的存儲器單元地址為0x400C,R0'?是指令執行后指向的存儲器單元地址。圖3-6多寄存器傳送指令示意圖使用多寄存器傳送指令時,基址寄存器的地址是向上增長還是向下增長,地址是在加載/存儲數據之前還是之后增加/減少,其對應關系如表3-3所示。在設計程序使用加載/存儲指令時,要注意基址指針的變化方向和前后要匹配對應;對于堆棧指令,進出棧指令要配對使用,例如使用STMFA指令作進棧操作,則須用對應的LDMFA指令作出棧操作。如程序清單3-1所示,使用STMFD指令將寄存器R0~R7保存到堆棧之中,指令執行前后的寄存器和存儲器內容變化如圖3-7所示。

程序清單3-1滿遞減堆棧的壓棧操作

STMFD SP!,{R0-R7,LR} ;現場保存,將R0~R7和

LR的內容壓棧圖3-7使用STM壓棧指令的前后對比與壓棧操作相對應的出棧操作是通過LDM指令來實現的。需要特別注意,為了讓堆棧指針能正確移動,出棧和壓棧時的LDM指令后綴必須都是一致的。比如程序清單3-1中使用的是“FD”后綴,那么出棧時也同樣要使用“FD”后綴,如程序清單3-2和程序清單3-3所示。因為出棧操作常用于子程序返回,所以通常在出棧的同時,將之前入棧的LR寄存器內容恢復到PC寄存器中,實現程序的返回。后者的指令上多了一個“^”符號,其功能是,如果操作寄存器組中含有PC寄存器,那么在恢復寄存器的同時將當前模式下的SPSR寄存器內容恢復到CPSR寄存器中。它們的使用效果如圖3-8所示。圖3-8使用LDM指令出棧操作

3.SWP——(單一數據)寄存器和存儲器交換指令

指令格式:

SWP{cond}{B} Rd,Rm,[Rn]

其中:B為可選后綴,若有B,則交換字節,否則交換32位字;Rd為目的寄存器;Rm是源寄存器,若Rd與Rm相同,則為該寄存器與存儲器單元內容進行交換;Rn在此用作基址寄存器,指向進行數據交換的存儲器單元,Rn不能與Rd和Rm相同。指令功能:SWP(SWaPdatabetweenregistersandmemory)指令用于將寄存器Rn指向的存儲器單元的內容讀取到寄存器Rd中,同時將寄存器Rm的內容寫入到該存儲器單元中,Rd和Rm可以是同一個寄存器。使用SWP可實現信號量操作,實現寄存器與存儲器間的數據同步交換;可以避免在多條指令實現的數據交換過程中,可能的異常響應而造成的交換數據不同步。應用示例:

SWP R0,R0,[R1] ;將R0的值與R1指向的存儲單元中

的內容進行字交換

SWPB R0,R1,[R2] ;將R2指向的存儲單元中的一個字

節的數據加載到R0中(高24位清

0),并將R1[7:0]存儲到該存儲單

元中3.4.3ARM數據處理指令

數據處理指令大致可分為3類:數據傳送指令(如MOV、MVN)、算術邏輯運算指令(如ADD、SUB、AND)和比較指令(如CMP、TST),見圖3-4。數據處理指令只能對處理器內部的數據進行操作。所有ARM數據處理指令均可選擇使用S后綴,表示是否根據本指令的執行結果影響CPSR寄存器中的狀態標志位。比較指令CMP、CMN、TST和TEQ不需要后綴S,它們會直接影響狀態標志。

三地址格式的ARM數據處理指令中含有兩個源操作數和一個目的寄存器。第一源操作數總是寄存器,第二源操作數可以是寄存器、移位后的寄存器或立即數。第二操作數如果是移位后的寄存器,則移位可以是邏輯移位、算術移位或循環移位(參見圖3-2)。移位計數可以由立即數指定,也可以由第4寄存器指定。

1.數據傳送指令

數據傳送指令主要用于立即數到寄存器或寄存器之間的數據傳遞,也可用于移位運算等操作。

1)?MOV——數據傳送指令

指令格式:

MOV{cond}{S} Rd,operand2

指令功能:MOV(MOVe)指令用于將8位位圖立即數或寄存器數據傳送到目標寄存器(Rd),也可用于移位運算等操作。應用示例:

MOVPC,LR;?PC=LR,常用于子程序的返回

MOVSR1,R1,LSL#2 ;?R1=R1*4,并影響標志位

2)?MVN——數據非傳送指令

指令格式:

MVN{cond}{S}Rd,operand2

指令功能:MVN(MoVeNot)指令用于將8位位圖立即數或寄存器數據按位取“反”后傳送到目標寄存器(Rd)。

應用示例:

MVN R0,0xFF ;R0=0xFFFFFF00

2.算術邏輯運算指令

算術邏輯運算指令主要用于加/減等算術運算和與/或等邏輯運算,完成數據的運算處理。

1)?ADD——加法指令

指令格式:

ADD{cond}{S}Rd,Rn,operand2

指令功能:本指令將operand2的值與Rn的值相加,結果保存到目標寄存器(Rd)中。

應用示例:

ADD

R0,R1,R2;R0=R1+R2

ADDSR0,R1,R2LSL#2;R0=R1+R2*4,并影響標志位

2)?SUB——減法指令

指令格式:

SUB{cond}{S}Rd,Rn,operand2

指令功能:本指令用Rn中的值減去operand2,結果保存到目標寄存器(Rd)中。

應用示例:

SUB R0,R1,R2 ;R0=R1-R2

SUBS R0,R1,R2LSL#2

;R0=R1-R2*4,并影響標志位

3)?RSB——逆向減法指令

指令格式:

RSB{cond}{S}Rd,Rn,operand2

指令功能:RSB(ReverseSuBtract)指令用operand2減去Rn中的值,結果保存到目標寄存器(Rd)中。

應用示例:

RSBR0,R1,R1LSL#2 ;R0=R1*4-R1=R1*3

RSBSR0,R1,0xFF00 ;R0=0xFF00-R1,并影響

標志位

4)?ADC——帶進位加法指令

指令格式:

ADC{cond}{S}Rd,Rn,operand2

指令功能:ADC(ADdwithCarry)指令將Rn的值與operand2的值相加,再加上CPSR寄存器中C條件標志位,結果保存到目標寄存器(Rd)中。應用示例:ARM處理器字長32?bit,可以用如下指令組合來進行超32?bit的加法運算。如64?bit的加法,可用兩個寄存器為一組表示一個64?bit數據。第一個64?bit數的高32?bit在R1中,低32?bit在R0中;第二個64?bit數的高、低32?bit分別在R3、R2中,運算結果存放到(R1,R0)中,即(R1,R0)=(R1,R0)+(R3,R2),代碼如下:

ADDS R0,R0,R2 ;運算低32?bit,可能產生進位

ADC R1,R1,R3 ;帶進位計算高32?bit

5)?SBC——帶進位減法指令

指令格式:

SBC{cond}{S} Rd,Rn,operand2

指令功能:SBC(SuBtractwithCarry)指令將Rn的值減去operand2的值,再減去CPSR寄存器中C條件標志位的“非”(若C標志位清0,則結果減去1),結果保存到目標寄存器(Rd)中。應用示例:ARM處理器字長32?bit,可以用如下指令組合來進行超32?bit的減法運算。如64?bit的減法,可用兩個寄存器為一組表示一個64?bit數據。64?bit被減數的高32?bit在R1中,低32?bit在R0中;64?bit減數的高、低32?bit分別在R3、R2中,運算結果存放到(R1,R0)中,即(R1,R0)=(R1,R0)-(R3,R2),代碼如下:

SUBS R0,R0,R2 ;運算低32?bit,可能產生借位

SBCS R1,R1,R3 ;帶進(借)位計算高32?bit

6)?RSC——帶進位逆向減法指令

指令格式:

RSC{cond}{S}Rd,Rn,operand2

指令功能:RSC(ReverseSubtractwithCarry)指令將operand2的值減去Rn的值,再減去CPSR寄存器中C條件標志位,結果保存到目標寄存器(Rd)中。

應用示例:

RSBS R2,R0,#0

RSC R3,R1,#0;求某64位數據(R1,R0)的負數補碼

并存放到(R3,R2)中

7)?AND——邏輯“與”指令

指令格式:

AND{cond}{S}Rd,Rn,operand2

指令功能:本指令將Rn的值與operand2的值進行按位邏輯“與”操作,結果保存到目標寄存器(Rd)中。

應用示例:

AND R0,R0,#0xff;R0=R0&0xff,屏蔽R0的

高24?bit

AND R0,R1,R2 ;R0=R1&R2

8)?ORR——邏輯“或”指令

指令格式:

ORR{cond}{S}Rd,Rn,operand2

指令功能:本指令將Rn的值與operand2的值進行按位邏輯“或”操作,結果保存到目標寄存器(Rd)中。

應用示例:

ORR R0,R0,#0x0F;R0=R0∨0x0F,實現將R0的

低4位置1

ORR R0,R1,R2 ;R0=R1∨R2

9)?EOR——邏輯“異或”指令

指令格式:

EOR{cond}{S} Rd,Rn,operand2

指令功能:本指令將Rn的值和operand2的值進行按位邏輯“異或”操作,結果保存到目標寄存器(Rd)中。

應用示例:

EOR R0,R0,#0x0F;R0=R0⊕0x0F,實現將R0的

低4位按位取反

EOR R0,R1,R2 ;R0=R1⊕R2

10)?BIC——位清除指令

指令格式:

BIC{cond}{S} Rd,Rn,operand2

指令功能:BIC(BItClear)指令將Rn的值和operand2的值的反碼進行按位邏輯“與”操作,結果保存到目標寄存器(Rd)中。

應用示例:

BICR0,R0,#0x0F ;R0=R1&(~R2),實現將R0的

低4位清0

BICR0,R1,R2 ;R0=R1&(~R2)

3.比較指令

比較指令都只是“試”運算,僅將運算結果標志于CPSR的條件碼位,都不會影響原操作數據。該類指令主要用于程序中的數據測試判斷、分情況處理的場合。

1)?CMP——比較指令

指令格式:

CMP{cond}Rn,operand2

指令功能:CMP(CoMPare)指令把Rn寄存器的數據與數據operand2進行試減比較,比較后的結果影響CPSR寄存器中的相應條件標志位,不保存試減的結果。

CMP指令中不需要顯式地指定S后綴,該指令總是會更改狀態標志。

應用示例:

CMP

R0,#10 ;R0與立即數10比較,設置相關標志位

CMP

R0,R1 ;R0與R1比較,設置相關標志位

說明:CMP指令與SUBS指令的區別在于CMP指令不修改原始操作數據。該指令常應用于需要比較兩個數據的大小,分情況處理的場合。程序清單3-4為使用CMP指令實現對傳入參數的過濾處理,當R0<3時,依據具體的值分別轉移到Fun0、Fun1或Fun2,否則程序返回。

2)?CMN——負數比較指令

指令格式:

CMN{cond}Rn,operand2

指令功能:CMN(CoMpareNegative)指令將寄存器Rn的值加上operand2的值,根據運算的結果更新CPSR中的相應條件標志位。

應用示例:

CMN

R0,#1;R0+1,判斷R0是否為1的補碼。

若是,則Z置位

說明:CMN指令與ADDS指令的區別在于CMN指令不影響原操作數。CMN指令可用于負數比較,比如“CMNR0,#1”指令表示R0與-1比較,若R0為-1(即1的補碼),則Z置位;否則,Z復位。

3)?TST——位測試指令

指令格式:

TST{cond}Rn,operand2

指令功能:TST(TeST)指令將寄存器Rn的值與operand2進行按位邏輯“與”操作,根據運算的結果更新CPSR中的相應條件標志位。本指令不影響原操作數。

應用示例:

TST

R0,#0x01;測試R0最低位是否為0

TSTR0,#0x0F;測試R0低4位是否為0

說明:TST指令與ANDS指令的區別在于TST指令不保存運算結果。TST指令通常與EQ、NE條件碼匹配使用,當所有測試位均為0時,EQ有效;而只要有一個測試位不為0,則NE有效。

4)?TEQ——相等測試指令

指令格式:

TEQ{cond}Rn,operand2

指令功能:TEQ(TestEQuivalence)指令將寄存器Rn的值與operand2進行按位邏輯“異或”操作,根據運算的結果更新CPSR中的相應條件標志位。本指令不影響原操作數。

應用示例:

TEQR0,

R1;測試R0與R1是否相等(不影響V和C位)

說明:TEQ指令與EORS指令的區別在于TEQ指令不保存運算結果。使用TEQ進行相等測試時,常與EQ、NE條件碼配合使用。當兩個數據相等時,EQ有效;否則,NE有效。3.4.4ARM分支指令

在ARM中有兩種方式可以實現程序的跳轉,一種是使用分支指令直接跳轉,另一種則是直接向PC寄存器賦值實現跳轉。分支指令包含分支指令B、帶鏈接的分支指令BL和帶狀態切換的分支指令BX等3條指令,見表3-5。

1.B——分支指令

指令格式:

B{cond} label

指令功能:B(Branch)指令跳轉到標號指定的地址執行

程序。

應用示例:

B WAITA ;跳轉到WAITA標號處

說明:分支指令中目的地址實際上是相對于當前PC的一個偏移量,而不是一個絕對地址。分支指令B限制在當前指令的?±32?MB地址范圍內。

2.BL——帶連接的分支指令

指令格式:

BL{cond} label

指令功能:BL(BranchwithLink)指令先將下一條指令的地址拷貝到R14(即LR鏈接寄存器)中,然后跳轉到標號指定地址運行程序。

應用示例:

BL

DELAY ;跳轉到DELAY標號處說明:分支指令BL限制在當前指令的?±32?MB地址范

圍內。

若要從分支返回調用處,則可以通過重新把R14的內容裝載到R15中來實現,ARM處理器返回到這個分支指令之后的下一條指令處繼續執行。BL指令常用于子程序調用,也稱為子程序調用指令。

3.BX——帶狀態切換的分支指令

指令格式:

BX{cond} Rm

其中:Rm為目標地址寄存器。

指令功能:BX(BranchandoptionallyeXchange)指令跳轉到Rm指定的地址處執行程序,若Rm[0]為1,則跳轉時自動將CPSR中的標志T置位,即把目標地址的代碼解釋為Thumb代碼;若Rm[0]為0,則跳轉時自動將CPSR中的標志T清0,即

把目標地址的代碼解釋為ARM代碼。該指令用于處理器狀態切換。應用示例:

ADRLR0, ThumbFun+1

BX

R0 ;跳轉到R0指定的地址,并根據R0[0]

切換處理器狀態

… ;其他指令

CODE16

ThumbFun

… ;Thumb指令碼

ThumbFun是Thumb程序的語句標號,Thumb程序的指令一定是半字對齊存儲,語句標號ThumbFun的地址bit0一定為0,ThumbFun+1的值bit0為1。3.4.5ARM雜項指令

ARM雜項指令是兩條專用于程序狀態字寄存器(CPSR、SPSR)訪問的ARM指令,主要應用于處理器的中斷屏蔽控制和處理器模式轉換,見表3-6。

1.MRS——讀狀態寄存器指令

指令格式:

MRS{cond}Rd,psr

其中:Rd為目標寄存器,Rd不允許為R15;psr為源操作數寄存器,只能是CPSR或SPSR。

指令功能:MRS指令將CPSR或SPSR中的內容裝入到一個通用寄存器中。在ARM處理器中,只有MRS指令可以將狀態寄存器CPSR或SPSR讀出到通用寄存器中。

應用示例:

MRS

R0,CPSR;將CPSR狀態寄存器值讀取到R0中

MRSR2,SPSR;將SPSR狀態寄存器值讀取到R2中

2.MSR——寫狀態寄存器指令

指令格式:

MSR{cond} psr_fields, #immed_8r

MSR{cond} psr_fields, Rm

其中:immed_8r為要傳送到狀態寄存器指定域的8?bit立即數;Rm為要傳送到狀態寄存器指定域的源寄存器數;psr為CPSR或SPSR;fields為指定傳送的區域,分別對應psr的4個字節片段。fields可以是以下的一種或多種(字母必須為小寫):

c:控制域屏蔽字節(psr[7…0]);

x:擴展域屏蔽字節(psr[15…8]);

s:狀態域屏蔽字節(psr[23…16]);

f:標志域屏蔽字節(psr[31…24])。各個域在CPRS寄存器中的位置如圖3-9所示。圖3-9程序狀態寄存器的域位置指令功能:MSR指令將一個立即常數裝載到CPSR或SPSR指定的位域中,或者將一個通用寄存器中的內容裝載到CPSR或SPSR中。

在ARM處理器中,只有MSR指令可以直接設置狀態寄存器CPSR或SPSR。

應用示例:

MSR

CPSR_c,#0xD3

;?CPSR[7…0]=0xD3,

即切換到管理模式

MSR

CPSR_cxsf,R3 ;?CPSR=R3說明:MRS指令讀取CPSR,可用來判斷ALU的狀態標志,或IRQ、FIQ中斷是否允許等。在異常處理程序中,讀SPSR可知道進入異常前的處理器狀態等。MRS與MSR配合使用,實現CPSR或SPSR寄存器的“讀-修改-寫”操作,可用來進行處理器模式切換、允許/禁止IRQ/FIQ中斷等設置,如程序清單3-5、程序清單3-6所示。另外,進程切換或允許異常中斷嵌套時,也需要使用MRS指令讀取SPSR狀態值,并保存起來。只有在特權模式下才能修改狀態寄存器。

注意:由于ARM處理器三級流水線結構的特征,程序中不能通過MSR指令直接修改CPSR中的T控制位來實現ARM/Thumb狀態的切換,如需要切換處理器的狀態,必須使用BX指令完成處理器狀態的切換。使用MRS與MSR指令進行處理器模式切換、允許/禁止IRQ/FIQ中斷等設置時,應采用“讀-修改-寫”的操作步驟完成,保證僅修改相關的位,切勿影響其他位的值。程序清單3-7用于設置管理模式堆棧區和IRQ模式下的堆棧區。

CPSR寄存器位域說明如圖3-10所示。圖3-10CPSR位域說明3.4.6ARM軟中斷指令

指令格式:

SWI{cond} immed_24

其中:immed_24是24位立即數,為0~16?777?215的整數,可

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
  • 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論