ARM體系結構


【1】ARM相關理論基礎介紹

1、ARM相關的概念

指令:就是一條匯編代碼,可以完成一個特定的功能
指令就是一堆CMOS組成的可以完成特定功能的電路圖
CMOS:柵極 源極 漏極 開關特性
NMOS:柵極為高電平,源極和漏極導通
	 柵極為低電平,源極和漏極截止
PMOS:柵極為低電平,源極和漏極導通
	 柵極為高電平,源極和漏極截止

image

內核(ARM內核) = 運算器 + 控制器 + 存儲器(寄存器)
運算器:匯編指令
控制器:控制程序運行
存儲器:數據

ARM公司將ARM內核授權給芯片廠家,使用ARM的內核生產對應的芯片
ARM指令集的架構(ARM-V1 到 ARM-V8)
1.此架構支持的是32位ARM指令集,還有64位的ARM指令集
	ARM-V1 ~ ARM-V7架構屬於32位ARM指令集
	ARM-V8機構屬於64位ARM指令集
2.架構的版本越高,支持的指令個數越多
	指令實現的功能越復雜
總結:指令集->架構->內核->SOC

2、ARM的發展史

1. 1978年,CPU公司 
	Cambridge processing Unit
	
2. 1979年    Acorn

3. 1985年, 32位,8MHz, 
    使用的精簡指令集RISC
    芯片的名字ARM 
4.1990年,轉折點
iphone 150萬英鎊 VLSI: 25萬英鎊
ARM公司12工程師+技術專利:150萬英鎊
ARM公司-》 Advanced RISC Machine

ARM公司不生產芯片,做技術的授權,
提供解決方案。芯片廠家拿到技術授權之后,
根據需求設計生產自己的SOC。
5. 2016年,日本軟銀收購

6. 2020年,英偉達(未收購成功)

ARM指令集 
RISC-V指令:完全開源

3、精簡指令集和復雜指令集的區別

精簡指令集(RISC)ARM架構
1.精簡指令集從復雜指令集中提取一些使用頻率較高,或者相對簡單的指令組合成精簡指令集
2.精簡指令集的指令周期和指令寬度都是固定的
3.指令的周期:執行一條指令所需要的時間
4.指令的寬度:一條指令編譯器成機器碼之后,占用內存空間的大小
復雜指令集(CISC)X86架構
1.復雜指令集更加注重指令的功能性和指令的運算能力
2.復雜指令集的指令寬度和指令的周期不固定

4、ARM產品的分布

cortex-A:高端處理器,可以運行linux系統(手機、平板)
cortex-R:主要針對的實時處理(汽車電子,攝像機,照相機)
cortex-M:低端電子產品,運行邏輯程序(物聯網設備開發)
		 stm32/stm8(意法半導體公司)
		 可以運行實時的操作系統
arm內核命令的規范:
早期:ARM7 ARM9 ARM10 ARM11
從ARM11之后ARM內核的命名調整為Cortex-A


5、ARM數據的約定

ARM-V7約定:
    char :8bits 
    half word:16bits 
    word:32bits 
    double word :64bits(cortex-a系列才支持)

ARM-V8約定:
    char :8bits 
    half word:16bits 
    word:32bits 
    double word :64bits(cortex-a系列才支持)
    quad word:128bits(ARM-V8架構才支持)

6、ARM處理器的工作模式

ARM處理器的工作模式就是不同的代碼執行在不同的工作模式下,完成特定的功能,ARM處理器的7種工作模式
1.ARM7 ARM9 ARM11有7種工作模式
2.Cortex-A系列有8種工作模式,多了monitor(安全監控模式)
用戶模式 user 應用層
系統模式 system user的特權模式
普通中斷模式 IRQ 外設中斷
快速中斷模式 FIQ 高速數據
未定義模式 Undef 指令未定義
中止模式 Abort 取指/取數據中止
管理模式 SVC 復位/軟中斷

7、ARM寄存器組織

8、特殊的寄存器

1.r13 -->別名sp:the stack pointer 棧指針寄存器
	主要存放的是棧頂的地址
2.r14 -->別名lr:the linking register 鏈接寄存器
	主要用於保存函數返回地址的
3.r15 -->別名pc:the program counter 程序計數寄存器
	存儲的是當前取指指令的地址
	取完一條指令之后,PC中的值會自動加4指向下一條指令,繼續取指
4.cpsr -->current program status register
	當前程序狀態寄存器
	保存的是當前程序的運行狀態,如工作模式
5.spsr -->saved program status register
	保存程序狀態寄存器
	專門用於保存CPSR中的值到SPSR中  

9、三級流水線

1.取指器:根據PC寄存器中的地址,取對應的指令
2.譯碼器:翻譯指令的功能,交給對應的執行器執行
3.執行器:執行指令,並將指令的執行結果寫回到寄存器中
以上三個期間都是獨立的硬件,工作互不干擾
三個器件都屬於單周期的器件,及一個時鍾周期可以完成一件事

【2】ARM匯編指令集

1、匯編代碼(.s)中的主要符號

1.指令:編譯器將指令編譯生成32位機器碼,	   執行時可以完成特定的功能2.偽指令:偽指令本身不是指令,編譯器可以將偽指令編譯生成多條指令,共同完成一條偽指令的功能3.偽操作:偽操作不占用任何的代碼段的空間,指導編譯器對代碼如何進行編譯的(.text .global .end)以.開頭的都屬於偽操作4.注釋:單行注釋:@   多行注釋:/**/

2、map.lds鏈接腳本文件分析

//1.鏈接腳本文件:告訴編譯器如何對代碼進行編譯的//2.輸出可執行文件為:32位 elf文件 小端對齊OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")/*OUTPUT_FORMAT("elf32-arm", "elf32-arm", "elf32-arm")*///3.輸出文件的架構:arm架構的可執行程序OUTPUT_ARCH(arm)//4.程序的入口是:_startENTRY(_start)//5.可執行程序中各個段的排布方式SECTIONS{	. = 0x00000000;//程序的入口地址	. = ALIGN(4);//對齊2^4:占位	.text      ://代碼段	{	//代碼段開始的位置必須放start.o的代碼		./Objects/start.o(.text)	//其他的.o文件編譯器看着辦		*(.text)	}	. = ALIGN(4);    .rodata : //只讀數據段	{ *(.rodata) }    . = ALIGN(4);    .data : //全局數據段	{ *(.data) }    . = ALIGN(4);	__bss_start = .;     .bss ://未初始化的全局變量     { *(.bss) }	__bss_end__ = .;}

3、指令的基本語法格式

<opcode><cond>{S}  Rd, Rn, oprand2
<opcode>:指令的名字
<cond>:條件碼
{s}:狀態位,加S,指令的執行結構影響CPSR的NZCV位
Rd:目標寄存器
Rn:第一個操作寄存器
oprand2:第二個操作數
	1>可以是一個普通的寄存器
	2>可以是一個立即數
	3>可以是一個經過移位操作的寄存器
	
注意:
1><opcode><cond>{S} :連到一起寫
2>指令和目標寄存器之間使用空格隔開
3>寄存器之間使用“,”隔開
4>一條指令獨占一行
5>指令中不區分大小寫
	mov r0,#0xff
	mov R0,#0xFF

【3】數據操作指令(最簡單、最常用)

1、數據搬移指令mov / mvn

語法格式:opcode <cond> {s} Rd,oprand2
mov r0, #0x000000FF  @ r0 = 0xFF 
mov r1, r0     @ r1 = r0
mvn r2, #0x000000FF  @ r2 = ~0xFF

@ mov r0, #0xFFF   @ error  
@ mov r1, #0xFFFF  @ error
mov r2, #0xFF000000  @ 0xFF >> 8  ==> 4FF
@ mov r3, #0xFFFF0000  @error
mov r4, #0xFFFFFF00 @ mvn r4, #0xFF

@ 偽指令  ldr  
ldr r5, =0x12345678  @// r5 = 0x12345678

image

2、移位操作指令

語法格式:opcode <cond> {s} Rd,Rn,oprand2lsl:邏輯左移(無符號數左移)高位移出,低位補0lsr:邏輯右移(無符號右移)低位移出,高位補0asr:算數右移(有符號數右移)低位移出,高位補符號位ror:循環右移  低位移出,補到高位mov r0,#0xFF00lsl r1,r0 #0x4 @ r1 = r0 << 4lsr r2,r0,#0x4 @ r2 = r0 >> 4asr r3,r0,#0x4 @ r3 = r0 >> 4

3、算數運算指令

語法格式:opcode <cond> {s} Rd,Rn,oprand2add:普通加法指令adc:帶進位的加法指令sub:普通的減法指令subc:帶借位的減法指令mul:乘法指令注:arm-v7架構之前都沒有除法指令    arm-v8架構才支持除法指令 div  
/*假設2個64位的數相加第一個64位的數R0存放低32位,R1存放高32位第二個64位數R2存放低32位,R3存放高32位結果R4存放低32位,R5存放高32位*/mov r0,#0xfffffffemov r1,#0x3mov r2,#0x4mov r3,#0x5adds r4,r0,r2adc r5,r1,r3   @ r5 = r1 + r3 + C
/*假設2個64位的數相減第一個64位的數R0存放低32位,R1存放高32位第二個64位數R2存放低32位,R3存放高32位結果R4存放低32位,R5存放高32位*/mov r0,#0x2mov r1,#0x9mov r2,#0x4mov r3,#0x5subs r4,r0,r2sbc r5,r1,r3  @ r5 = r1 -r3 -!c
mov r0,#3mov r1,#4mul r2,r0,r1

4、位運算指令

位運算指令:and orr eor bic << >> ~語法格式:<opcode><cond>{S}  Rd, Rn, oprand2         Rd  =  Rn # oprand2 ldr r0,=0x12345678@ 1> 將R0寄存器中的,第[3]位置1,保證其他位不變orr r0,r0,#(0x1 << 3)orr r0,r0.#0x8@ 2> 將R0寄存器中的,第[10]位清0,保證其他位不變and r0,r0,#(~(0x1 << 10))@ 3> 將R0寄存器中的,第[7:4]位置1,保證其他位不變orr r0,r0,#(0xf << 4)@ 4> 將R0寄存器中的,第[23:20]位清0,保證其他位不變and r0,r0,#(~(0xf << 20))@ 5> 將R0寄存器中的,第[15:10]位設置為0b101010,保證其他位不變①先清0and r0,r0,#(~(0x3f << 10))②在把相應的位置1orr r0,r0,#(0x2a << 10)@ 6> 將R0寄存器中的,第[31:28]位設置為0b1100,第[11:8]位設置為1011,保證其他位不變and r0,r0,#(~(0xf << 28))orr r0,r0,#(0xc << 28)and r0,r0,#(~(0xf << 8))orr r0,r0,#(0xb << 8)@ 7> bic  位清除指令 給對應的位寫1,就可以清0@ 將R0寄存器中的,第[23:20]位清0,保證其他位不變bic r0,r0,#(0xf << 20)        

5、比較指令

比較指令:cmp
用於比較兩個數的大小
格式:cmp Rn,oprand2
1.沒有目標寄存器
2.比較的結果影響的是CPSR的NZCV位
3.指令后邊不需要加S
4.本質:做減法運算
cmp指令常跟條件碼一起使用

image

mov r0,#8
mov r1,#15
cmp r0,r1
subhi r0,r0,r1
subcc r1,r1,r0

【4】跳轉指令

1、b跳轉指令

b:不帶保存返回地址的跳轉指令
格式:b <cond> Label
	跳轉到Label標簽下的第一條指令出執行
標簽:label
場合:有去無回

2、bl跳轉指令

bl:帶保存返回地址的跳轉指令格式:bl <cond> Label	跳轉到Label標簽下的第一條指令出執行	同時保存跳轉指令的下一條的地址到lr寄存器中標簽:label場合:有去有回總結:跳轉指令的本質就是修改PC中的值mov r0,#4	mov r1,#5	bl add_func	mov r2,#6	b stopadd_func:	add r0,r0,r1	mov pc,lr
/*實現1~100之間所有數相加之和*/for(i=1;i<=100;i++){	sum = sum + i;}sum = r0i = r1for(1;2;3){	4;}{1;2}{4;3;2}{4;3;2}{4;3;2}
/*求最大公約數*/		mov r0,#0x5	mov r1,#0x8	loop:	cmp r0,r1	beq stop 	subhi r0,r0,r1	subcc r1,r1,r0	b loop

【5】特殊功能寄存器操作指令

1、mrs和msr操作指令

msr cpsr,Rn   @cpsr = Rn  寫操作  實際操作是修改cpsr中的值
mrs Rn,cpsr   @Rn = cpsr  讀操作  實際操作是將cpsr中的值讀出來,不對cpsr中的值進行比較

2、從SVC模式切換到USER模式

 /*第一種方式*/
	msr cpsr,#0xD0
	
/*第二種方式*/
	mrs r0,cpsr @將CPSR中的值讀到普通寄存器中
	bic r0,r0,#0x1f @清除模式位
	orr r0,r0,#0x10 @修改模式位對應位為1
	msr cpsr,r0 @在寫到cpsr中

【6】load/store內存讀寫指令

1、單寄存器操作指令

單寄存器操作指令:ldr str
格式:ldr/str<cond> Rn,[Rm]
Rn:Rn中的數據看成一個普通的數據
Rm:Rm中的數據看成內存的地址

ldr:將Rm指向的內存地址中的內容,讀到Rn寄存器中
str:將Rn寄存器中的內容,寫到Rm指向的地址空間中

ldr r0,=0x40000800
ldr r1,=0x12345678
str r1,[r0]  將r1寄存器中的值,寫到r0指向的內存地址中的內容
ldr r2,[r0]  將r0指向的內存地址中的內容,讀到r2寄存器中
ldr r0,=0x40000800
ldr r1,=0x11111111
ldr r2,=0x22222222
ldr r3,=0x33333333
@將r1中的值存到r0+4指向的地址中,r0中的值不變
str r1,[r0,#4]
@將r2中的值存到r0指向的地址中,同時r0 = r0 + 4
str r2,[r0],#4
@將r3中的值存到r0+4指向的地址中,同時r0 = r0 + 4
@!:更新地址
str r3,[r0,#4]!

2、測試arm的大小端

問:首先要知道什么是大端存儲,什么是小端存儲?
答:小端存儲低地址中存放低字節內容,高地址存放高字節內容
    大端存儲高地址存放低字節內容,低地址存放高字節內容
思考:如何用匯編代碼,編寫測試大小端,使用字節進行讀取數據就可以了ldr r0,=0x40000800ldr r1,=0x12345678str r1,[r0]ldrb r2,[r0]ARM是小端存儲方式
@使用ldrh讀出地址中4字節的數據@並將讀到的數據合並的r9寄存器中ldrh r3,[r0]ldrh r4,[r0,#2]orr r9,r3,r4,lsl #16

3、多寄存器操作指令

多寄存器操作指令:ldm stmstm/ldm  Rm, {寄存器列表}stm:將寄存器列表中的所有寄存器中的內容,存到Rm指向的地址連續空間中ldm:將Rm指向的連續的內存空間中的內容,讀到寄存器列表中的所有寄存器中注意:1.如果寄存器列表中的寄存器連續,則使用“-”隔開,不連續使用“,”隔開2.寄存器列表中的寄存器編號順序,不管怎么寫,永遠都是地地址對應小編號的寄存器,高地址對應大編號的寄存器
ldr r0,=0x40000800ldr r1,=0x11111111ldr r2,=0x22222222ldr r3,=0x33333333ldr r4,=0x44444444ldr r5,=0x55555555stm r0,{r1-r4,r5}ldm r0,{r6-r10}或者如下寫法:stm r0, {r5,r4,r3,r2,r1}ldm r0, {r10,r9,r8,r7,r6}

【7】棧操作指令

1、棧的4種類型(sp棧指針)

滿棧:sp指向的棧空間有有效的數據,需先移動棧指針,在存儲數據空棧:sp指向的棧空間沒有有效的數據,先存儲數據,在將棧指針移動到一個空的空	間增棧:棧指針向高地址方向移動減棧:棧指針向低地址方向移動

2、棧的4種操作方式

滿增棧:stmfa/ldmfa   full ascending 滿減棧:stmfd/ldmfd   full descending 空增棧:stmea/ldmea   empty ascending空減棧:stmed/ldmed   empty descending

3、ARM處理器采用滿減棧

語法格式:
stmfd/ldmfd sp!, {寄存器列表}
!:更新棧指針的地址

ldr sp,=0x40000820
ldr r0,=0x11111111
ldr r1,=0x22222222
ldr r2,=0x33333333
ldr r3,=0x44444444
ldr r4,=0x55555555
stmfd sp!, {r0-r4}
ldmfd sp!, {r5-r9}
	ldr sp,=0x40000820	
	mov r0,#3
	mov r1,#4
	bl add_func
	add r2,r0,r1  @r2 = 0x7
	b stop

add_func:
	@保存現場
	stmfd sp!,{r0-r1,lr}
	mov r0,#5
	mov r1,#6
	bl sub_func
	add r3,r0,r1   @ r3 = 0xb
	@恢復現場
	ldmfd sp!,{r0-r1,pc}
	
sub_func:
	stmfd sp!,{r0-r1,lr}
	mov r0,#9
	mov r1,#7
	sub r4,r0,r1  @r4 = r0-r1 = 0x2
	ldmfd sp!,{r0-r1,pc}

【8】混合編程

ATPCS規范(ARM規定)1.參數的傳遞通過r0-r3傳遞2.返回值通過r0返回3.參數的個數如果超過4個通過壓棧的方法進行傳遞4.返回值大於4個字節通過r0,r1返回

1、匯編調用c代碼

.text   /* .text 代碼段 .data 數據段*/.global _start  /* 將_start聲明為全局的函數 */ 	_start: /* 標簽:理解成C語言的函數名 */	@ 匯編調用C 	@ C代碼必須有棧 	ldr sp, =0x40000820 @ 初始化棧		mov r0, #3  @ 指定實參值	mov r1, #4	bl addfunc  @ 調用C函數				@ 返回通過R0返回	stop: /* while(1) {} */		@ 匯編指令		b stop  /* 指令:跳轉指令 調用stop函數 */.end /* 結束 */
int addfunc(int a, int b){	return a + b;}

2、c調用匯編

.text   /* .text 代碼段 .data 數據段*/
.global _start  /* 將_start聲明為全局的函數 */
 	
_start: /* 標簽:理解成C語言的函數名 */
@ 啟動文件,在匯編的階段完成棧的初始化

	@ C代碼必須有棧 
	ldr sp, =0x40000820 @ 初始化棧
	
	b main

.end /* 結束 */
		
main.c文件
//1.需要使用extern將add_func函數進行聲明
extern int add_func(int a,int b,int c,int d);
int sum = 0;
int main()
{
	sum = add_func(1,2,3,4);
	return 0;
}
add_func.s文件
.text 

@ 2. 將匯編的函數聲明成一個全局的函數
.global add_func

add_func:
	add r0, r0, r1
	add r0, r0, r2
	add r0, r0, r3
	mov pc, lr
.end 

3、內聯匯編

格式:
asm volatile(
"匯編指令\n\t"
:輸出列表
:輸入列表
:破壞列表
);
//混合編程
int add_func2(int a,int b,int c,int d)
{
	int sum;
	asm volatile(
	"add r0,r0,r1\n\t" //指令列表
	"add r0,r0,r2\n\t"
	"add r0,r0,r3\n\t"
	:"=r"(sum) //輸出列表
	:"r"(a),"r"(b),"r"(c),"r"(d) //輸入列表
	:   //破壞列表
	);
	return sum;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM