ARM体系结构学习总结

arm体系结构:研究核core,如何工作 内部原理以及工作工程

ARM核:CPU中最核心最重要的部分,ARM核由ALU,存储器,逻辑控制器,移位寄存器等组成

ARM指令:随着cpu的发展,指令也在发生变化

        指令:cpu执行的就是指令

        指令的生成: 与计算机语言的发展相反

           x.c ----> x.s ---> x.o

        C语言---->汇编(助记符)---->二进制指令

        每条汇编就对应一条二进制指令,二进制指令和汇编一一对应

指令执行过程:

        flash存放指令,控制器负责从flash中 取指 交给运算器执行,执行过程中,

有临时数据存放在寄存器中,一般建议,指令在执行之前拷贝到RAM(内存)中

Flash(Rom):读写速度慢,断电不丢失数据,永久存储

                        flash淘汰了Rom---固态硬盘/SD/存储内存--并行存储

ARM的工作模式:

        ARM和人也有相似的地方,人在生活中会有很多种模式,如睡觉、工作、学习、打游戏...

在不同模式下,所占有的资源和权限是不一样

        cpu:在不同模式下,功耗不同

模式切换:

        作用:方便获取该模式下的权限和资源

                 从一种模式切换到另一种模式,需要保存当前状态/位置,方便以后返回

   USR模式, 该模式权限最低, 大部分程序都要在该模式下执行   90%  ---安全
    SVC模式: super 管理员模式, 权限最高, 负责执行高优先级的程序  6%
    IRQ模式: 外部中断模式, 权限很高, 负责处理中断    3%
    *FIQ模式: fast IRQ模式, 权限比IRQ高, 处理高优先级中断,linux并没有该模式
    
    #### undefine 模式: 当cpu发现指令异常, 进入该模式处理
    #### abort模式: cpu发现内存违法,进入该模式
    #### system模式, 和usr一样

不同模式下, 权限和资源不一样 
    寄存器,用来存放临时数据的,
    寄存器 r0 ~ r7 只有一份, 各种模式都共享他们
    *r8 ~ r12  有两份 FIQ模式 自占一份
    r13 r14各个模式都有一份     r15(PC)一份
    CPSR只有一份, SPSR多份-
    总结:不管如何分配,每个模式都有r0-r15可以使用, 还有cpsr
    
    但是: 有几个特殊的寄存器, 他们有专门的用途
        r15:又称pc ,pragram counter--程序计数器
            pc记录了指令执行的位置: 
                控制器每次都会从pc 记录的位置取出一条指令,pc自动+4
                然后控制器循环取指....
            
            pc记录的是 程序指令地址不是指令本身, pc指向的指令是将要被执行的
        
        r14: 又称LR寄存器, linker register 
                pc 的备胎backup, 当程序跳转的时候,记录pc的位置 (LR =pc),
                那么程序返回的时候 pc = LR
                
        r13: 又称sp, stack point  栈指针
        
        CPSR: current  process state  register,当前处理器状态寄存器
            比如cpu的当前模式,其他东西
                [4:0] 记录当前模式, 读取获取当时的模式,写入改变模式
                [7]  读取获取当前IRQ 状态, 写入改变IRQ状态
                
        SPSR:save process state register ,保存处理器状态寄存器
            
            模式切换 ,会从模式A 切换到模式B, CPSR 会被改变
                那么当返回的时候,CPSR 要恢复到以前的状态

ARM指令集编码基本格式:
    条件码  指定码  目的寄存器  操作数1寄存器   操作数2
    31-28    27-20     19-16            15-13                12-0
    标志位 (EQ NE )
        <opcode>      <Rd>         <Rn>                 <operand2>
        操作码        目标寄存器     操作数1寄存器        第二个操作数
        
        add r1, r0,#3   @@ r1=r0+3
        
        add R3, R2, R1,LSR #2        #R3 = R2+R1 /4    @@r1逻辑右移两位+4

########    汇编指令  ####################

@@@@@@@@ 搬移指令 mov
		
		mov r0, #1  @@ r0 =1
		mov r1, r0  @@ r1=r0 
		mov r2, r1 
		
		@@@切换CPU模式--->usr模式
		@@@ mov cpsr ,#ox10    非法,因为 cpsr只有两条可以修改 msr mrs      
	
	@@@@@@@@  算数指令 ############
	add r1, r0,#3   @@ r1=r0+3
	add r2,r1,r0     @@ 用法 :add 目的寄存器  源寄存器  寄存器/数值

    sub r2, r1 ,#3   @@ r2=r1-3
	
	mul r2,r1,r2	@@ r2 = r1*r2  mul 目的寄存器,源1寄存器,源2寄存器 
	
	@@没有除法

		
	@@@@@@@@@ 逻辑运算 and--& orr-- |  bic--清零 bit clear

	与指令
	and Rd,Rn,operand
	and指令将Rn 的值与操作数operand2按位逻辑 与 ,结果存放到目的寄存器Rd 中。
	
	或指令
	orr Rd,Rn,operand
	orr指令将Rn 的值与操作数operand2按位逻辑 或 ,结果存放到目的寄存器Rd 中。
	
	异或指令
	eor Rd,Rn, operand
	eor 指令将Rn 的值与操作数operand2按位逻辑”异或”,相同为0,不同为1,
			结果存放到目的寄存器Rd 中。
	清除指令
	bic Rd,Rn,operand 
	bic指令将Rn 的值与操作数operand2 的反码按位逻辑”与”,结果存放到目的寄存器Rd 中
	bic R0,R0,#0x1F;      @@将R0最低5位清零,其余位不变
	
	@@@@@@@@@@@@@  比较指令 条件执行  #########
		mov r1,#5
		cmp r1,#8   	
			@@@ 内部原理: r1-8 得到一个结果: 负值 正值 0
			@@   结果放在 cpsr.N   cpsr.Z   cmp每次执行都会改变这些bit
			@@    cpsr.N  negative  负数   =1 表示有负数产生 =0表示没有负数产生
			@@@   cpsr.Z  zero    		   =1  b表示结果为零  =0 表示结果非零


	@@@@  条件执行   大于great  小于 -little  等于-equeue   不等于--not equeue
						
	    movgt r3,#9	@@ 大于执行 如果加上gt那么该指令会首先读取  cpsr.n/z,然后决定是否执行
		movlt r4,#8
		moveq r5,#5
		movne r6,#7

	
	cmp r2,r1
	
	@@@@@@@@@@ 跳转指令 #######
	修改PC值
	
mov r0,#1
mov r1,#2
mov r2,#3
mov r3,#4
b main			@@@强制修改PC =main所在的地址, pc=18

mov r4,#5
mov r5,#6

main:   	@@标号仅仅表示当前指令存在的地址,标号在编译之后不存在 不占用空间

mov r9,#9
mov r10,#10
	
@@@@@@@@@@@@@@@@@  b 基本操作 --break
	bl --- link register
		bl 首先把 当前指令的地址存放在 lr中,然后再跳转
	bl  main 
		
	mov pc,lr 
	
        

##### 深入指令 ###########
    指令,32bit 基本上和汇编一一对应
    指令生成: gcc x.c -o x.out
    如何从汇编翻译为机器码/指令:
    总结:每条指令都是独立的,不依赖于其他指令
    指令执行过程:
        最基本的三个过程: 取指 译码 (找到运算器 输入源 输出源)  执行 
    
    我们都是使用 指令流水 完成---流水线---一条指令一个周期
        51单片机: 三级流水
        STM32 :   五级流水
        x86 :       13级流水
    流水 :提高效率,不用等待, 每个模块只要关注一件事情

#######  立即数问题 ############
    放入指令中的常数
    指令有 12bit 用来存放数据   0xFFF  1111 1111 1111
        理论上 0-4095,但是这样就没有办法表示一个 很大很大的数
        实际上:
            12bit 分为 高8位 低四位
                高8bit用来存放一个 8bit数据, 0~255, 假设为 x
                低4bit表示 X 左移的位数*2 假设 低4bit值为 y
                那么最终结果是 :x<<(2*y)
            
    定义:立即数即一个bit常数循环左移偶数位得到的值
    
    判断一个数是不是立即数??
        如果它可以由一个 8bit常数 经过偶数位循环 左移得到
    0x01880  0001 1000 1000 0000  可以左移六位得到
    ox01F40  0001 1111 0100 0000  可以左移六位得到
    0x1234 不是

    问题:我们C语言 从没有考虑这个为问题 ,如何把0x12345678 放入r0呢?
    mov r0,0x12345678  不行 非法 
如何做:
    1.拆分大常数, 比如 0x1234 --> 0x1200 and 0x34,分别放入 r0,r1 ,然后orr r3,r0,r1
    *2.使用伪指令 : 假指令
        ldr r0, =0x12345678
            原理:编译器 遇到伪指令,会帮你替换为真实的指令,完成你要求的功能
#######  内存访问指令 ######
    寄存器的存储是有限的 r0-r15 
    ldr str 
        arm 规定,内存是不能直接拷贝的(从一片区域拷贝到另一片)
            ldr :load register,将数据 从此内存拷贝到  寄存器
            str :store register ,将寄存器值 存入内存中
            
    LDR用于将内存的内容加载到寄存器中,STR用于存储寄存器的内容到 存储器地址
 

@@@i++如何实现的??		
	
ldr r0,=val_i			@@将val_i的内存地址写入寄存器r0	
ldr r1,[r0]  @@ r1=*r0  @@取出值
add r1,r1,#1
str r1,[r0]        //将r1 中的值存储到r0中的内存地址中

		
mov r0,#buf     @@r0 = buf的地址

ldr r0,= buf
ldr r1= [r0]   @@ r1=*r0 r0存储了数据的地址, *r0 取出内容

ldr r0,=dbuf   
str r1,[r0]    @@ *r0 = r1   


.date   @@@ 表示后面是 数据段, 可以修改的

val_i:
	.byte 0x1,0x3,0x5,0x7

buf:  @@ char buf[] = {0x01,0x02,0x03,0x04}

	.byte 0x01,0x02,0x03,0x04  
	
	@@小端模式 :高字节放高位

dbuf:		@@ char *buf = malloc(8)
	.space 8

@@@@@@@@@@@  异常 #############@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
    正常--状态:学习 吃饭 睡觉  
    异常          :打断正常节奏的事件, 称之为异常
        
        CPU :在执行过程中,会遇到 中断 指令错误 内存错误...
        异常:需要处理,而且需要 及时处理
        |
        |
        |
        | 突然发生异常
        -----------> cpu立马放下手中的任务,转而去处理异常
    LR=pc,spsr=cpsr |
                    |    pc和 cpsr被改变
                    |
        ------------
        |    返回正常程序
        |    pc=LR,cpsr=spsr
        |
        
    中断,是异常的一种,异常包括很多种,中断异常 软中断异常
        中断是其中最重要的一种

    中断好处:提高系统的响应速度(鼠标跟踪)--实时性
    
    异常特点: 一般随机发生的,但是也可以主动让某个异常发生
        复位异常/RESET: 程序正在执行,突然系统复位..---优先级最高
        IRQ异常: 中断异常,当中断产生的时候
        @ FIQ异常: 快速中断发生
        swi软中断异常: 唯一一个 可以主动发生的异常
                                       只要执行一个指令,就可以产生异常 swi
        @未定义异常: 当程序发现 未定义指令的时候......
        @数据访问异常: 程序发现 内存非法(内存被释放)
            
        不同的异常, 处理的时候需要不同的资源和权限(模式)
        不同的异常发生, cpu会自动进入不同的模式,从而获得不同的权限和资源,执行不同的代码
        不同的异常--跳到异常向量表的0位置-->跳转指令,在跳转到代码执行区 
        
        SVC --supervisor
        RESET/SWI   ---SVC模式 
        IRQ               ---IRQ模式
        
        当发生不同异常,PC指针应该跳转到不同的位置,执行不同的代码段处理该异常
            那么问题:程序的位置是不同的
    
    异常向量表 vctor Table: 他存放在flash的0地址 0x00
            每4B为一个表项,  当cpu 发生不同异常的时候,pc指针跳转到对应的表项
            RESET          --->0x00 
            swi软中断异常--->0x08
            IRQ异常

@@跳转指令
	b reset

	reset:
	
	//初始化栈指针
	ldr sp, =end_stack  @@r13 一般写为sp ,我们一般使用减栈
	
	stmfd sp!,(r0-r12,lr)   @@将r0-r12,r14统统放入sp指向的栈中,!sp指针自动调整
	@@出栈
	ldmfd sp!,(r0-r12,pc)   @注: lr直接给了pc
	
	@@ mov pc,lr 
	
    .date 

    stack_base:
	.space 512
	
    end_stack:

@@@@ 伪指令
        假指令 ,真是不存在的指令, 作用是 告诉编译器 该如何去干活
        
        .text    告诉编译器,后面都是指令
        .end           , 结束了
        .byte    buf: .byte 0x1,0x2,0x3 ...告诉编译器,buf后面的空间 按照 字节为单位 进行访问,依次存入
        .word    buf: .word 0x12345678--一个字  0x23355589 ...
                        告诉编译器,buf后面的空间都按照 字为单位进行访问
                        int buf[] = {0x1234,0x2345678}
                        
        ldr      ldr r3,=0x1234666  告诉编译器,把这个数放入寄存器r3
        .global  标签   .global _start  声明 _start 为全局标签,即允许标签 被外部使用

        .equ   PI   3.1415926    @@@ #define PI  3.1415926

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值