STM32F0Thumb汇编学习




 -  **一周掌握STM32汇编指令用法**

---;************************************************
;一周掌握STM32汇编指令用法
;Project:	Light Led (C)
;MCU:		STM32F030C8T6
;Date:		2022.03.24
;File:		start.s
;Function:	startup C program
;************************************************
	AREA	START,CODE,READONLY
	EXPORT	__Vectors
	EXPORT	Reset_Handler
	
	ENTRY		
;------------------------------------------------	
__Vectors	;这种标号比较特殊,不能自己定义 是规定的,必须这样写 ;标号的本质就是地址 代表的是一个地址,标号要顶格写,不可自定义
	DCD		0x20002000		
	DCD		Reset_Handler


;------------------------------------------------		
Reset_Handler	;这种标号比较特殊,不能自己定义 是规定的,必须这样写,;标号的本质就是地址 代表的是一个地址,标号要顶格写,不可自定义
	
	;MOVS	R0,#10 
	
;把立即数10 放到R0寄存器中
;在这个指令中MOVS就是一个操作码,R0是操作数1,#10是操作数2。
;指令周期:一个指令执行如果需要一个周期就可以完成,我们称这个指令为单周期指令	,如果需要多个周期,那就是多周期指令
;比如说8M主频单指令周期就是125ns
;48M主频,单指令周期就是20.833ns
;假如系统时钟为8Mhz,执行一条单周期需要125ns,如果一个指令的执行需要2个周期的话,那么就需要250ns
;这里的单个指令周期和系统时钟的周期是相等的,也就是时钟周期=机器周期
	

;Ram_Clear    ;STR指令的位置,想要跳到STR指令执行的时候;就直接使用标号就能跳过去了  使用BNE   Ram_Clear 跳转;标号的本质就是地址 代表的是一个地址,标号要顶格写,不可自定义
;------------------------------------------------------------------------------------------------------------------------------------------------------
;LR 保存的是返回地址, 返回地址是对应的是该函数的下一条指令对应的地址
;PC 程序计数器 存放当前欲执行指令的地址,决定了程序到哪里去执行指令
;--------------
;xPSR特殊功能寄存器: 组合状态寄存器
;31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
;N  Z  C  V    保留    T                 保留                               I S R 编 号
;--------------
						;表3.1Cortex-MO处理器的ALU标志
;标志																		描述
;N(第31位)
	;设置到执行指令结果的31位,为"1"时结果为负数(被解析为有符号整数时)设为“0”时,结果为整数或等0
;Z(第30位)
	;如果执行指令的结果为О置位,两个相同数值经比较后也会置“1”
;C(第29位)
	;结果的进位,对于无符号加法,如果产生了无符号溢出﹐该位置"1",对于无符号减法,该位为借位输出状态取反
;V(第28位)
	;结果溢出,对于有符号加法和减法,如果发生了有符号溢出,该位置“1”
;--------------
;APSR应用程序状态寄存器
;N负号标志,Z零标志,C进位或借位标志,V溢出标志位
;--------------
;EPSR执行程序状态寄存器
;T 是否处于THUMB指令状态 始终为1 否则触发硬件异常
;IPSR中断程序状态寄存器
;ISR编号   中断编号
;--------------
;PRIAMASK 特殊功能寄存器: 中断屏蔽寄存器 相当于总中断,即是所有的中断都不能执行了  ,但是不可屏蔽中断不能屏蔽的(特殊的中断)
;           31 ...1      0
;PRIAMASK    保留      PRIAMASK
;--------------
;CONTROL   特殊功能寄存器:控制寄存器
; 		         31......    1               0
;CONTROL		保留    SPSEL(栈定义)   nPRIV(非特权)保留

;------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------	



;------------------------------------------------1.MOVE传输指令------------------------------------------------	
;MOVE传输指令			共4条 (具体和配套课件结合看)
;--------------
;MOVS  Rd	#<imm8>  ; 1 Cycles(一个周期) 8 bit immediate Rd    
;MOVS  Rd	Rm		 ; 1 Cycles Rm ->Rd
;MOVS  Rd	Rm		 ; 1 Cycles Rm ->Rd
;MOVS  PC	Rm		 ; 1 Cycles Rm ->PC
;----------------------------


;第一个MOVS  Rd	#<imm8> 
;表示:			    将立即数移动到Rd(目的寄存器) Rd, Rn范围为低位寄存器R0-R7 ,  指令时间:为1个周期
;影响:				比MOV多个“s”后缀,影响内核寄存器xPSP寄存器标志位,会跟新xPSP(APSP)
;基于标准:			UAL统一汇编语言
;立即数需要注意的是:取值范围:#<imm8>"immediate"  == 0--((2^8)-1)以此类推

;第二个MOVS Rd,Rm ,  Rd Rm范围为低位寄存器RO-R7,指令执行时间1个指令周期。例:
;第三个MOV  Rd,Rm ,  Rd Rm范围为RO-R12,指令执行时间1个指令周期。
;第四个MOV  PC,Rm       Rm范围为低位寄存器RO-R7,指令执行时间3个指令周期。
;----------------------------	
;举例
	;MOVS	R0,#0
	;;-------------	
	;MOVS	R0,#255
	;;-------------	
	;MOVS	R0,R1
	;;-------------
	;MOV	    R12,R0
;	
;------------------------------------------------2.ADD加法指令------------------------------------------------	
;ADD加法指令   共8条
;--------------
;ADDS Rd,Rn,#<imm3> ;1 Cycles Rn + 3 bit immediate->Rd
;ADDS Rd,Rn,Rm		 ;1 Cycles Rn + Rm -> Rd	
;ADD  PC,PC, Rm		 ;3 Cycles PC + Rm -> PC	
;ADDS Rd,Rd, #<imm8> ;1 Cycles Rd + 8 bit immediate->Rd
;ADCS Rd,Rd, Rm      ;1 Cycles Rd + Rm + C-> Rd
;ADD  SP,SP, #<imm7> ;1 Cycles SP + 7 bit immediate->SP
;ADD  Rd,SP, #<imm8> ;1 Cycles SP + 8 bit immediate->Rd
;ADR  Rd,    <label> ;1 Cycles label Rd
;----------------------------
;第一个,ADDS Rd,Rn, #<imm3>,将Rn寄存器中的数据和3位立即数相加,并将结果保存到Rd寄存器中。
;        					 3位立即数范围为0-7 ,Rd Rn范围为低位寄存器 RO-R7,指令执行时间1个指令周期。
;第二个, ADDS Rd,Rn,Rm      ,将Rn寄存器中的数据和Rm寄存器中的数据相加,并将结果保存到Rd寄存器中,
;                             Rd Rn Rm范围为低位寄存器RO-R7 ,指令执行时间1个指令周期。
;第三个, ADD  PC,PC,Rm    ,将PC寄存器中的数据和Rm寄存器中的数据相加,并将结果保存到PC寄存器中。
;第四个,ADDS Rd,Rd, #<imm8>,将Rd寄存器中的数据和8位立即数相加,并将结果保存。到Rd寄存器中,8位立即数范围为0-255。Rd范围为低位寄存器RO-R7指令执行时间1个指令周期。
;                             立即数是8位的,但是前面的2个寄存器必须是一样的。
;第五个,ADCS Rd,Rd,Rm      , 将Rd寄存器中的数据、Rm寄存器中的数据、APSR 中的C标志位的值相加,并将结果保存到Rd寄存器中。Rd,Rm都是32位寄存器,Rd,Rm范围为低位寄存器RO-R7,
;                             指令执行时间1个指令周期。也就是Rd=Rd+Rm+C标志位的值,C这个标志位是状态寄存器(APSR)中的一个位,C要么是0,要么是1 。
;                             这些标志位一般在条件跳转的时候用。
;第六个,ADD SP,SP, #<imm7> ,将SP寄存器中的数据和7位立即数相加,并将结果保存到SP寄存器中,7位立即数:0-127。
;                             指令执行完成之后,堆栈指针将产生跳转,跳转到SP中数据所指向的地址。这里需要注意的是堆栈的地址是4字节对齐的,
;							  所以要保证#<imm7>要是4的倍数,指令执行时间1个指令周期,因为堆栈指针每次移动4个字节,所有这里要求要是4个倍数SP=SP+(0-127)*4。
;第七个,ADD Rd,SP;#<imm8> ,  将SP寄存器中的数据和8位立即数相加,并将结果保存到Rd寄存器中8位立即数:0-255,这里需要注意的是#<imm8>要是4的倍数,
;							  Rd范围为低位寄存器RO-R7,指令执行时间1个指令周期。SP=SP+(O-255)*4 。
;第八个,ADR Rd,<label>    ,  将label标号的代表的地址保存到Rd寄存器中Rd范围为低位寄存器RO-R7指令执行时间1个指令周期。
;							  这条指令会涉及到程序字节对齐的概念,会在后面为大家具体描述。如果遇到报错,可以先思考一下,暂时保留一下问题。
;----------------------------
;举例
	;ADDS	R0,R7,#7
	;;-------------
	;ADDS 	R0,R2,R1
	;;-------------
	;;ADD  	PC,PC,R12
	;;-------------
	;ADDS 	R0,R0,#255
	;;-------------
	;ADCS 	R0,R0,R1
	;;-------------
	;ADD  	SP,SP,#508   ;127*4
	;;-------------
	;ADD  	R0,SP,#1020  ;255*4
	;-------------
	;ADR	 	R1,loop
	;ADDS 	R0,R1,R3
;loop	
	;ADDS 	R0,R1,R3
	;-------------
;------------------------------------------------3.Subtract减法指令------------------------------------------------	
;Subtract减法指令	共6条
;--------------
;SUBS Rd,Rn,Rm      ;1 Cycles  Rn - Rm-> Rd
;SUBS Rd,Rn,#<imm3> ;1 Cycles  Rn- 3 bit immediate->  Rd 
;SUBS Rd,Rd,#<imm8>  ;1 Cycles  Rd - 8 bit immediate-> Rd
;SBCS Rd,Rd,Rm       ;1 Cycles  Rd - Rm- !C->Rd
;SUB  SP,SP,#<imm7>	 ;1 Cycles  SP - 7 bit immediate-> SP
;RSBS Rd,Rn,#O       ;1 Cycles  0 - Rn->Rd
;----------------------------
;第一个,SUBS Rd,Rn,Rm       ;将Rn寄存器中的数据减去Rm寄存器中的数据,并将结果保存到Rd寄存器中,Rd,Rn,Rm都是32位寄存器,Rd,Rn,Rm范围为低位寄存器,R0-R7指令执行时间1个指令周期。
;第二个,SUBS Rd,Rn,#<imm3>  ;将Rn寄存器中的数据减去3位立即数,并将结果保存到Rd寄存器中,3位立即数范围为0-7,Rd,Rn范围为低位寄存器R0-R7指令执行时间1个指令周期。
;第三个,SUBS Rd,Rd,#<imm8>  ;将Rd寄存器中的数据减去8位立即数,并将结果保存到Rd寄存器中,8位立即数范围为0-255,Rd范围为低位寄存器R0-R7指令执行时间1个指令周期
;第四个,SBCS Rd,Rd,Rm		 ;将Rd寄存器中的数据减去Rm寄存器中的数据减去APSR中的C标志位的取反值,并将结果保存到Rd寄存器中Rd Rm都是32位寄存器Rd Rm范围为低位寄存器R0-R7指令执行时间1个指令周期。
;第五个,SUB  SP,SP,#<imm7>  ;将SP寄存器中的数据减去7位立即数,并将结果保存到SP寄存器中,7位立即数:0-127指令执行完成之后,堆栈指针将产生跳转,跳转到SP中数据所指向的地址
;							   这里需要注意的是堆栈的地址是4位对齐的,所以要保证#<imm7>要是4的倍数,指令执行时间1个指令周期。这个跟上面的加法都是对应的。
;第六个,RSBS Rd,Rn,#0		 ;用0减去Rn寄存器中的数据,并将结果保存到Rd寄存器中Rd,Rn是32位寄存器范围为低位寄存器R0-R7,指令执行时间1个指令周期,
;							   最后一条指令举例:RSBS R2,R2,#0,R2=0-R2,相当于把一个数取反。
;----------------------------
;举例
   ;MOVS R0,#120
   ;MOVS	R1,#30
   ;SUBS	R2,R0,R1
   ;;-------------
   ;MOVS	R0,#120
   ;SUBS	R1,R0,#1
   ;;-------------
   ;MOVS	R0,#120
   ;SUBS	R0,R0,#100
   ;-------------
   ;MOVS R0,#120
   ;MOVS	R1,#130
   ;SBCS	R1,R1,R0
   ;;-------------
   ;SUB  	SP,SP,#4
   ;;-------------
   ;RSBS 	R0,R1,#0
   
;------------------------------------------------4.Multiply乘法指令------------------------------------------------	
;Multiply乘法指令	共1条
;--------------
;MULS Rd,Rm, Rd	   ;1 Cycles Rm x Rd Rd
;----------------------------
;第一个MULS Rd,Rm,Rd		;将Rm寄存器中的数据和Rd寄存器中的数据相乘,并将结果保存到Rd寄存器中(相乘结果只保留低32位数据)。Rd,Rm都是32位寄存器,Rd,Rm范围为低位寄存器R0-R7,指令执行时间1个指令周期。
;							这里需要注意2个32位数据相乘,乘完的结果可能大于32位数,寄存器保存不下,会只保留低32位,高于32位的就丢掉了,所以大家在计算乘法的时候需要注意。
;							我们这个单片机是没有除法指令的。使用除法的话,都是软件除法,不是硬件除法,软件除法是靠算法来运算的,那么硬件除法1个周期搞定的事情,软件除法可能要好多个周期,所以软件除法会慢,那么大家在写程序的时候需要注意。
;							除法可能占用的时间比较长,不过现在有些改良款的国产M0内核MCU支持硬件除法。
;----------------------------
;举例
	;MOVS	R0,#10
	;MOVS	R1,#10
	;MULS	R0,R1,R0

;------------------------------------------------5.Compare比较------------------------------------------------	
;Compare比较指令	共3条
;--------------
;CMP Rn, Rm 	;1 Cycles  比较Rn,Rm
;CMN Rn,Rm  	;1 Cycles  负数比较
;CMP Rn,#<imm8> ;1 Cycles  比较Rn, 8 bit immediate
;----------------------------
;第一个CMP Rn,Rm					;计算Rn寄存器中的数据减去,Rm寄存器中的数据,结果不保存,执行完之后会影响APSR中的标志位。Rn Rm都是32位寄存器,Rd Rm范围为位寄存器R0-R14指令执行时间1个指令周期。
;							  		  比较指令我们用的也非常多,比较两个数的大小经常用。比较指令会影响APSR标志位
;第二个CMN Rn,Rm					;计算Rn寄存器中的数据加上Rm寄存器中的数据,结果不保存,执行完之后会影响APSR中的标志位。Rn Rm都是32位寄存器,Rd Rm范围为低位寄存器R0-R7,可以用于负数的比较							
;第三个CMP Rn,#<imm8>				;比较Rn和8位立即数,结果不保存,执行完之后会影响APSR中的标志位。Rn范围为低位寄存器R0-R7。
;----------------------------
;举例
	;MOVS	R0,#20
	;MOVS	R1,#10
	;CMP		R0,R1
;    ;-------------
	;MOVS	R0,#20
	;RSBS	R0,R0,#0
	;MOVS	R1,#10
	;RSBS	R1,R1,#0
	;CMN		R0,R1
;	;-------------
	;CMP 	R0,#100

;-----------------------------------------------6.Logical逻辑运算指令------------------------------------------------	
;Logical逻辑运算指令 	共6条
;--------------
;ANDS Rd,Rd,Rm		;1 Cycles	Rd & Rm  -> Rd
;EORS Rd,Rd,Rm  	;1 Cycles 	Rd ^ Rm  -> Rd
;ORRS Rd,Rd,Rm 		;1 Cycles	Rd | Rm  -> Rd
;BICS Rd,Rd,Rm		;1 Cycles	Rd & !Rm -> Rd
;MVNS Rd,Rm 		;1 Cycles	!Rm 	 -> Rd
;TST  Rn,Rm 		;1 Cycles	Rn & Rm
;----------------------------
;第一个,ANDS Rd,Rd,Rm		;将Rd寄存器中的数据和Rm寄存器中的数据相与,结果保存到Rd中。Rd,Rm都是32位寄存器。Rd,Rm范围为低位寄存器R0-R7,指令执行时间1个指令周期。
;第二个,EORS Rd,Rd,Rm		;将Rd寄存器中的数据和Rm寄存器中的数据异或,结果保存到Rd中。Rd,Rm都是32位寄存器。Rd,Rm范围为低位寄存器R0-R7,指令执行时间1个指令周期
;							  异或只有两个数不相同的时候异或结果为1,两个数相同的时候异或结果为0,^这个是异或的符号,1^1=0,1^0=1,0^0=0,0^1=1;第三个,ORRS Rd,Rd,Rm     ;将Rd寄存器中的数据和Rm寄存器中的数据相或,结果保存到Rd中。Rd,Rm都是32位寄存器。Rd,Rm范围为低位寄存器R0-R7指令执行时间1个指令周期。
;第四个,BICS Rd,Rd,Rm		;将Rd寄存器中的数据与Rm寄存器中的数据的取反数相与,结果保存到Rd中。Rd,Rm都是32位寄存器。Rd,Rm范围为低位寄存器R0-R7指令执行时间1个指令周期。
;第五个,MVNS Rd,Rm			;将Rm寄存器中的数据的取反数保存到Rd中。Rd,Rm都是32位寄存器。Rd,Rm 范围为低位寄存器R0-R7,指令执行时间1个指令周期。
;第六个,TST  Rn,Rm			;将Rn寄存器中的数据和Rm寄存器中的数据相与,结果不保存,执行结果会影响APSR中的标志位。Rn,Rm都是32位寄存器。Rn,Rm范围为低位寄存器R0-R7指令执行时间1个指令周期。


;----------------------------
;举例
	;MOVS 	R0,#0x55  ; 01010101
	;MOVS 	R1,#0xAA  ; 10101010
	;ANDS 	R1,R1, R0
	;;-------------
	;MOVS 	R0,#0x55  ; 01010101
	;MOVS 	R1,#0xAA  ; 10101010
	;EORS 	R1,R1,R0
	;;-------------
	;MOVS 	R0,#0x55  ; 01010101
	;MOVS 	R1,#0xAA  ; 10101010
	;ORRS 	R1,R1,R0
	;;-------------
	;MOVS 	R0,#0x55  ; 01010101
	;MOVS 	R1,#0xAA  ; 10101010
	;BICS 	R1,R1,R0
	;;-------------
	;MOVS 	R0,#0x55  ; 01010101
	;MVNS 	R1,R0
;	;-------------	
;	;	.......

;------------------------------------------------7.Shift移位指令------------------------------------------------	
;Shift移位指令  共7条
;--------------
; __			 __
;|C| <-寄存器 <-|0| 	逻辑左移
; --			 --
;LSLS Rd,Rm,#<imm5>	; 1 Cycles		Rm << imm5->Rd
;LSLS Rd,Rd,Rm			; 1 Cycles		Rd << Rm  ->Rd
;__				__	
;|C| ->寄存器 ->|0| 	逻辑右移
; --			 --
;LSRS Rd,Rm,#<imm5>	; 1 Cycles		Rm >> imm5->Rd
;LSRS Rd,Rd,Rm			; 1 Cycles		Rd >> Rm  ->Rd
; _____
; |   |        __
; |-->寄存器 ->|C| 		算术右移移位时保留最高位
;			    --
;ASRS Rd,Rm,#<imm5>	; 1 Cycles		Rm >>imm5->Rd
;ASRS Rd,Rd,Rm			; 1 Cycles		Rd >>Rm  ->Rd
; ____________
; |          |  __
; |-->寄存器 ->|C| 		循环右移
;			    --
;RORS Rd,Rd,Rm			; 1 Cycles		Rd >>Rm  ->Rd
;----------------------------
;第一个, LSLS Rd,Rm,#<imm5>	;将Rm寄存器中的数据左移#<imm5>位,每次移位最高位保存在C标志位中,最低位补0,并将最终的结果保存在Rd寄存器中,#<imm5>范围为:0-31。
;								  Rd,Rm为低位寄存器R0-R7,执行该指令占用1个指令周期,注意这里的最高位指的是bit31位。
;第二个, LSLS Rd,Rd,Rm			;将Rd寄存器中的数据左移Rm位,每次移位最高位保存在C标志位中,最低位补0,并将最终的结果保存在Rd寄存器中,Rm,Rd是32位寄存器,
;								  Rd,Rm为低位寄存器R0-R7执行该指令占用1个指令周期,这个和上面的指令原理都是一样的,只不过把立即数变为了寄存器。
;第三个, LSRS Rd,Rm,#<imm5>	;将Rm寄存器中的数据右移#<imm5>位,每次移位最低位保存在C标志位中,最高位补0,并将最终的结果保存在Rd寄存器中,#<imm5>范围为:1-32。
;								  Rd,Rm为低位寄存器,R0-R7执行该指令占用1个指令周期。最低位也就是bit0位。
;第四个, LSRS Rd,Rd,Rm			;将Rd寄存器中的数据右移Rm位,每次移位最低位保存在C标志位中,高位补0,并将最终的结果保存在Rd寄存器中,
;								  Rm,Rd是32位寄存器,Rd,Rm为低位寄存器,R0-R7执行该指令占用1个指令周期,这个跟上面右移是一样的道理,只是把立即数换成了寄存器。
;第五个, ASRS Rd,Rm,#<imm5>	;将Rm寄存器中的数据右移#<imm5>位,每次移位最低位保存在C标志位中,最高位保持不变(即bit31位不变)(比如说0x80000001,进行算数右移1位后变为0xC0000000,C标志位为1)。
;							 	  并将最终的结果保存在Rd寄存器中,#<imm5>范围为:1-32。Rd,Rm为低位寄存器R0-R7,执行该指令占用1个指令周期。
;第六个, ASRS Rd,Rd,Rm			;将Rd寄存器中的数据右移Rm位,每次移位,最低位保存在C标志位中,最高位保持不变(即bit31位不变)(比如说0x80000000,进行算数右移1位后变为0xC0000000,C标志位为0),
;								  并将最终的结果保存在Rd寄存器中,Rm?Rd是32位寄存器,Rd Rm 为低位寄存器R0-R7,执行该指令占用1个指令周期,这个和上面的指令是一样的,只不过是把立即数改成了寄存器。
;第七个, RORS Rd,Rd,Rm			;将Rd寄存器中的数据右移Rm位,每次移位将最低位同时保存在C标志位和最高位(最高位即bit31位)中,并将最终的结果保存在Rd寄存器中,Rm Rd是32位寄存器。
;							      Rd,Rm为低位寄存器R0-R7,执行该指令占用1个指令周期。就是把最低位的数移位的时候放到最高位。
;----------------------------
;举例
	;MOVS R0,#0xAA 	; 10101010
	;LSLS R1,R0,#1
	;;-------------
	;MOVS R0,#0xAA   ; 10101010
	;MOVS R1,#1
	;LSLS R0, R0,R1
	;;-------------
	;MOVS R0,#0xAA 	; 10101010
	;LSRS R1,R0,#1
	;;-------------
	;MOVS R0,#0xAA	; 10101010
	;MOVS R1,#1 
	;LSRS R0, R0,R1
	;;-------------
    ;MOVS R0,#0xAA	; 10101010
	;ASRS R1,R0,#1
	;;-------------
	;MOVS R0,#0xAA 	; 10101010
	;MOVS R1,#1 
	;ASRS R0,R0,R1
	;;-------------
	;MOVS R0,#0xAA	; 10101010
	;MOVS R1,#1
	;RORS R0,R0, R1
 
 ;------------------------------------------------8.Load加载指令------------------------------------------------	
;Load加载指令	加伪指令    共13条
;含义:这个加载其实含义就是从内存中把数据取出来。比如在RAM的某个地址存着一个数据,我想要把这个数据读出来使用,那么可以用加载指令。
;--------------
;无符号加载
;LDRRd,   [Rn,#<imm5>] ;2 Cycles [Rn+imm5]-> Rd
;LDRH Rd, [Rn,#<imm5>] ;2 Cycles [Rn+imm5]-> Rd 16
;LDRB Rd,  [Rn,#<imm5>] ;2 Cycles [Rn+imm5]-> Rd 8
;LDRRd,   [Rn,Rm]      ;2 Cycles [Rn+Rm]  -> Rd
;LDRH Rd, [Rn,Rm]	    ;2 Cycles [Rn+Rm]  -> Rd 16
;LDRB Rd, [Rn,Rm]      ;2 Cycles [Rn+Rm]  -> Rd 8

;有符号加载 
;LDRSH Rd,[Rn,Rm]      ;2 Cycles [Rn+Rm]  -> Rd 16
;LDRSB Rd, [Rn,Rm]     ;2 Cycles [Rn+Rm]  -> Rd 8

;PC SP相关加载  
;LDR Rd,  [PC, # imm8] ;2 Cycles [PC+imm8]-> Rd
;LDRRd,   [SP,# imm8]  ;2 Cycles [SP+imm8]-> Rd

;多寄存器加载
;LDM Rn!{Ra,Rb,...} ;1+N Cycles[Rn]>Ra,[Rn+4]>Rb,...
;!表示最后的地址写回到Rn中;[Rn + N x 4]Rn
;N 表示加载寄存器个数

;伪指令加载
;含义:伪指令:指令集之外的指令,除了指令集中规定的指令,我们还可以使用一些伪指令。伪指令由汇编器工具(包含 在Keil中)提供,能被转换为一条或几条的实际指令(由Keil软件完成)
;LDR Rd,=immed32		;LDR Rd,[PC, # i mm8]
;LDR Rd,label			;LDR Rd,[PC, # i mm8]
;----------------------------
;第一个, 	LDR  Rd,[Rn,#<imm5>]	;将Rn寄存器中的数据和#<imm5>相加,将相加的结果作为地址,取这个地址里面的32位数据存放到Rd寄存器中。Rn,Rd是32位寄存器#<imm5>范围为:0-124,
;									  注意这里的Rn和立即数都必须是4的整数倍,Rn,Rd为低位寄存器R0-R7,执行该指令占用2个指令周期。
;第二个,	LDRH Rd,[Rn,#<imm5>]	;将Rn寄存器中的数据和#<imm5>相加,将相加的结果作为地址,取这个地址之后的16位数据存放到Rd寄存器的低16位中,高16位置0。Rn,Rd是32位寄存器,#<imm5>范围为:0-62。
;									  注意这里的Rn和5位立即数必须是2的整倍,Rn,Rd为低位寄存器R0-R7,执行该指令占用2个指令周期。
;第三个,	LDRB Rd,[Rn,#<imm5>]	;将Rn寄存器中的数据和#<imm5>相加,将相加的结果作为地址,取这个地址之后的8位数据存放到Rd寄存器的低8位中,高24位置0。
;									  Rn,Rd是32位寄存器 #<immX>范围为:0-31,Rn,Rd为低位寄存器R0-R7,执行该指令占用2个指令周期。
;第四个,	LDR  Rd,[Rn,Rm]			;将Rn寄存器中的数据和Rm寄存器中的数据相加,将相加的结果作为地址,取这个地址开始往后的32位数据存放到Rd寄存器中。
;									  Rn Rd Rm是32位寄存器注意这里的Rn,Rm中的数据之和必须是4的整数倍Rm,Rn,Rd为低位寄存器R0-R7,执行该指令占用2个指令周期。
;第五个,	LDRH Rd,[Rn,Rm]			;将Rn寄存器中的数据和Rm寄存器中的数据相加,将相加的结果作为地址,取这个地址开始往后的16位数据存放到Rd寄存器的低16位中,高16位置0。
;									  Rn,Rd,Rm是32位寄存器,注意这里的Rn,Rm中的数据之和必须是2的整数倍。Rm,Rn,Rd为低位寄存器R0-R7。执行该指令占用2个指令周期。
;第六个,	LDRB Rd,[Rn,Rm]			;将Rn寄存器中的数据和Rm寄存器中的数据相加,将相加的结果作为地址,取这个地址里面的数据存放到Rd寄存器的低8位中,高24位置0。
;									  Rn,Rd,Rm是32位寄存器。Rn,Rd,Rm为低位寄存器R0-R7,执行该指令占用2个指令周期。
;第七个,   LDRSH Rd,[Rn,Rm]		;将Rn寄存器中的数据和Rm寄存器中的数据相加,将相加的结果作为地址,取这个地址里面的16位数据存放到Rd寄存器的低16位中,对高16位进行有符号扩展(比如取出来的16位数据bit15位符号位为1,那么高16位全为1,相反全为0)。
;									  Rn,Rd,Rm是32位寄存器注意这里的Rn,Rm中的数据之和必须是2的整数倍,Rm,Rn,Rd为低位寄存器R0-R7,执行该指令占用2个指令周期。
;第八个,	LDRSB Rd,[Rn,Rm]		;将Rn寄存器中的数据和Rm寄存器中的数据相加,将相加的结果作为地址,取这个地址里面的8位数据存放到Rd寄存器的低8位中,对高24位进行有符号扩展(比如取出来的8位数据bit7位符号位为1,那么高24位全为1,相反全为0)。
;									  Rn,Rd,Rm是32位寄存器,Rn,Rd,Rm为低位寄存器R0-R7。执行该指令占用2个指令周期。
;									  比如内存某个位置存了一个有符号数据,你想把这个数据从内存中读出来,还要保持符号位不变那么就用这个(有符号加载)指令。因为CPU寄存器是32位的,如果你把一个有符号16位数据加载到这个32位寄存器中,那么32位最高位bit31位是0,所以一加载就变成了无符号数据了。
;第九个,   LDR Rd,[PC,#<imm8>]	  ;将PC寄存器中的数据和#<imm8>相加,将相加的结果作为地址,取这个地址里面的32位数据存放到Rd寄存器中。
;									  Rd是32位寄存器,注意这里的8位立即数必须是4的整数倍,Rd为低位寄存器R0-R7执行该指令占用2个指令周期。
;第十个,   LDR Rd,[SP,#<imm8>] 	 ;将SP寄存器中的数据和#<imm8>相加,将相加的结果作为地址,取这个地址里面的32位数据存放到Rd寄存器中。Rd是32位寄存器,#<imm8>范围为:0-1020,
;									  注意这里的立即数必须是4的整数倍Rd为低位寄存器R0-R7,执行该指令占用2个指令周期。
;第十一个, LDM Rn!,{Ra,Rb,…}		 ;Rn,Ra,Rb… 寄存器范围:低位寄存R0-R7
;									  Rn的数据必须是4的整数倍,这个指令占用的周期和大括号里面寄存器的数量有关,1+N这里的N指的就是大括号里面寄存器的数量。
;第十一个1,LDM R2!,{R1,R0}		 ;将R2寄存器中的数据作为地址,取从这个地址开始的连续4个地址单元里面的数据保存到R1里面;
;									  将R2寄存器中的数据加4作为地址,取从这个地址开始的连续4个地址单元里面的数据保存到R0里面,将最后的地址再加4保存到R2里面。
;第十二个, LDR Rd,=immed32		 ;将32位立即数传输到Rd寄存器中。Rd寄存器范围:低位寄存器R0-R7,指令执行占用2个指令周期。

;第十三个, LDR Rd,=label			; Rd寄存器范围:低位寄存器R0-R7,这条指令的用处是将label标号代表的地址传输到Rd寄存器中,指令执行占用2个指令周期。
;									   这里的label代表一个标号,前面我们讲过,标号就是地址。其实就是把标号所代表的的地址加载到寄存器中。这里的label只是一个示范,可以写成其他的名字。

;----------------------------
;举例
		;MOVS R1,#0x04
		;LDR R0,[R1,#4]
		;;-------------
		;MOVS R1,#0x02
		;LDRH R0,[R1,#2]
		;;-------------
		;MOVS R1,#0x01
		;LDRB R0,[R1,#1]
		;;-------------
		;MOVS R0,#0x02
		;MOVS R1,#0x02
		;LDR R2,[R0,R1]
		;;-------------
		;;........
		;;-------------
		;MOVS R0,#0x01
		;MOVS R1,#0x00
		;LDRB R2,[R0,R1]
		;;-------------
		;MOVS R0,#0x01
		;MOVS R1,#0x01
		;LDRSH R2,[R0,R1]
		;;-------------
		;MOVS R0,#0x01
		;MOVS R1,#0x00 
		;LDRSB R2,[R0, R1]
		;-------------
		;LDR R0,[PC,#4];?数据随机存放或者取出
		;;-------------
		;LDR R0,[SP,#4]
		;;-------------
		;MOVS R2,#4
		;LDM R2!,{R1,R0};?R2的值 为啥不是00000008 而是0000000C
		;;-------------
		;LDR R0,=4294967295
		;LDR R1,=0xFFFFFFFF
	    ;-------------
		;LDR R0,=4294967295
		;LDR	R2,=loop
;loop
		;LDR R1,=0xFFFFFFFF
;------------------------------------------------9.存储指令指令------------------------------------------------	
;存储指令   		共8条
;含义:
;--------------
;STR Rd,  [Rn,#<imm5>];2 Cycles Rd -> [Rn+imm5]
;STRH Rd, [Rn,#<imm5>];2 Cycles Rd -> [Rn+imm5] 16
;STRB Rd, [Rn,#<imm5>];2 Cycles Rd -> [Rn+imm5] 8
;STR Rd,  [Rn,Rm] 	  ;2 Cycles Rd -> [Rn+Rm] 
;STRH Rd, [Rn,Rm] 	  ;2 Cycles Rd -> [Rn+Rm]   16
;STRB Rd, [Rn,Rm] 	  ;2 Cycles Rd -> [Rn+Rm]   8
;STR Rd,  [SP,#imm8]  ;2 Cycles Rd -> [SP+imm8]
;STM Rn!, {Ra,Rb,…}  ;1+N Cycles Ra ->[Rn], Rb ->[Rn+4],
;----------------------------
;第一个,STR Rd,[Rn,#<imm5>]   ;  将Rn寄存器中的数据和#<imm5>相加,相加的结果作为地址,并将Rd寄存器中的32位数据存放到这个地址里面。注意#<imm5>范围:0-124,
;								   且Rn,立即数必须是4的整数倍Rn Rd寄存器范围:低位寄存器R0-R7,指令执行占用2个指令周期。
;第二个,STRH Rd,[Rn,#<imm5>]  ;  将Rn寄存器中的数据和#<imm5>相加,相加的结果作为地址,并将Rd寄存器中的低16位数据存放到这个地址里面,
;								   注意#<imm5>范围:0-62,且Rn立即数必须是2的整数倍,Rn Rd 寄存器范围:低位寄存器R0-R7,指令执行占用2个指令周期
;第三个,STRB Rd,[Rn,#<imm5>]  ;  将Rn寄存器中的数据和#<imm5>相加,相加的结果作为地址,并将Rd寄存器中的低8位数据存放到这个地址里面,注意#<imm5>范围:0-31,Rn,Rd,寄存器范围:低位寄存器R0-R7。
;第四个,STR  Rd,[Rn,Rm] 	    ;  将Rn寄存器中的数据和Rm寄存器中的数据相加,相加的结果作为地址,并将 Rd 寄存器中的32 位数据存放到这个地址里面,Rd Rn Rm 都是32位寄存器,
;								   且Rn 和 Rm 的和必须是4的整数倍RnRdRm寄存器范围:低位寄存器 R0-R7 指令执行占用 2 个指令周期。
;第五个,STRH Rd,[Rn,Rm]	    ;  将Rn寄存器中的数据和Rm寄存器中的数据相加,相加的结果作为地址,并将 Rd 寄存器中的低 16 位数据存放到这个地址里面,
;								   Rd Rn Rm 都是32 位寄存器,且Rn和Rm的和必须是2的整数倍Rn Rd Rm 寄存器范围:低位寄存器R0-R7,执行也是2个周期。
;第六个,STRB Rd,[Rn,Rm]      ;   将Rn寄存器中的数据和Rm寄存器中的数据相加,相加的结果作为地址,并将Rd寄存器中的低8位数据存放到这个地址里面,这里说明一下,  
;								   Rd Rn Rm都是32位寄存器,Rn Rd Rm寄存器范围:低位寄存器R0-R7指令执行占用2个指令周期。(上面说的存储到这个地址:其实表达的是存储在从这个地址开始的连续X(1(Byte),2(Halfword),4(word))个地址单元中。)
;第七个,STR  Rd,[SP,#<imm8>] ;   将SP寄存器中的数据和#<imm8>相加,相加的结果作为地址,并将Rd寄存器中的32位数据存放到这个地址里面,
;									注意#<imm8>范围:0-1020, 且#<imm8>必须是4的整数倍 Rd 寄存器范围:低位寄存器R0-R7 ,指令执行占用2个指令周期。
;第八个,STM Rn!,[Ra,Rb,…] Rn,Ra,Rb…;寄存器范围:低位寄存器 R0-R7 Rn 必须是 4 的整数倍。     ;  
;----------------------------
;举例
	;LDR R0,=0x12345678
	;LDR R1,=0x20000000
	;STR R0,[R1,#4]
	;;-------------
	;LDR R0,=0x1234
	;LDR R1,=0x20000000
	;STRH R0,[R1,#2]	
	;;-------------
	;LDR R0,=0x12
	;LDR R1,=0x20000000
	;STRB R0,[R1,#1]	
	;;-------------
	;LDR R1,=0x10000001
	;LDR R2,=0x40000001
	;LDR R0,=0x1234 
	;STRH R0,[R1,R2]
	;;;-------------	
	;LDR R1,=0x10000000
	;LDR R2,=0x10000001
	;LDR R0,=0x12 
	;STRB R0,[R1, R2]
	;;-------------	
    ;STR R0, [SP, #4] 
	;;;-------------	
    ;LDR R0, =0x12
    ;LDR R1,=0x34 
    ;LDR R2,=0x20001000
    ;STM R2!,{R0, R1}
	

;------------------------------------------------10.Push压栈和Pop出栈指令------------------------------------------------	
; Push压栈和Pop出栈指令 	共4条
;含义:
;--------------
;PUSH {reglist} 	; 1+N Cycles 
;PUSH {reglist,LR}  ; 1+N Cycles 
;POP  {reglist} 	; 1+N Cycles 
;POP  {reglist,PC}  ; 1+N Cycles
;----------------------------
;第一个,PUSH {reglist}		;将reglist寄存器中的数据按先后顺序压栈(每个数据压栈后堆栈指针递减4)reglist寄存器的数量可以是多位,
;								 范围:R0-R7。指令执行周期也是和大括号中的寄存器数量有关系1+N。
;第二个,PUSH {reglist,LR}	   ;将reglist寄存器中的数据和LR寄存器中的数据按先后顺序压栈(每个数据压栈后堆栈指针递减4),reglist寄存器的数量可以是多位,范围:R0-R7,执行周期也是1+N。
;								压栈的顺序,多个寄存器压栈的顺序是从右往左依次压栈的。例:PUSH {R0,R1,R2,LR}。比如说这个例子就是先压LR R2 R1 R0。
;第三个,POP{reglist}		  ;将堆栈区域中的数据按先后顺序出栈(先进后出原则),并保存到 reglist?寄存器中(每个数据出栈后堆栈指针递增4)。reglist寄存器的数量可以是多位,范围:R0-R7。
;第四个,POP{reglist,PC}      ;将堆栈区域中的数据和 PC 寄存器中的数据按先后顺序出栈(先进后出原则),并保存到reglist寄存器中(每个数据出栈后堆栈指针递增 4),reglist寄存器的数量可以是多位,
;								范围:R0-R7。指令执行周期取决于大括号中寄存器的数量N,总的执行指令周期为1+N个指令周期。
;								出栈顺序:先出栈的是括号中最左边的寄存器,然后开始依次往右,POP {R0,R1,R2,PC},就是先出栈到R0里面,接着是R1,R2,最后一个PC。
;								出栈的时候数据可以随便出栈到你指定的寄存器中。只要知道数据放在哪个寄存器里面就行了,但是一定要记住,一个压栈,对应一个出栈,
;								不要只压栈压了好几个之后,想取出第一个压栈的数据,
;								得把后面压的几个数据都先取出来,才能取到第一个数据,因为第一个数据是最先压进去的。
;----------------------------
;举例
	;PUSH {R0,R1}
 ;;-------------	
    ;PUSH {R0,LR}
 ;;-------------	
	;POP  {R0,R1}
;;-------------	
    ;POP  {R0,PC}
;;-------------		
	;PUSH {R0,LR}
	;POP	 {R0,PC}
	;;-------------	
	;PUSH {R0,R1}
	;POP  {R0,R1}

;------------------------------------------------11.跳转指令------------------------------------------------	
;跳转指令 					共5条

;含义:跳转指令分为两大类:一类是无条件跳转,一类是条件跳转。
;--------------
;B   label 	 	;3 Cycles 
;BL  label   	;4 Cycles 
;BX  Rm      	;3 Cycles 
;BLX Rm      	;3 Cycles
;B{cond} label  ;1or3 Cycles
;----------
;————————————————————————————————————————————————————————————————————
;icond}Suffix		|	lested Status Flags		    |	Description  |
;————————————————————————————————————————————————————————————————————
;EQ					|	z set						|	equal
;NE					|	z clear						|	not equal
;cs/Hs				|	c set						|	unsigned higher or same
;cc/Lo				|	c clear						|	unsigned lower
;MI					|	N set						|	negative
;PL					|	N clear						|	positive or zero
;vs					|	v set						|	overflow
;vc					|	v clear						|	no overflow
;HI					|	c set and z clear			|	unsigned higher
;Ls	 				|	clear or z set				|	unsigned lower or same
;GE					|	N equals v					|	signed greater or equal
;LT					|	N not equal to v			|	signed less than
;GT					|	z clear AND (N equals v)	|	signed greater than
;LE					|	z set OR (N not equal to v)	|	signed less than or equal
;AL					|	(ignored)					|	always (usually omitted)
;—————————————————————————————————————————————————————————————————————
;符号				|	条件						|	关系到的标志位
;————————————————————————————————————————————————————————————————————
;Eo					|	相等(EQual)					|	Z==1
;NE					|	不等《NotEqual)				|	Z==0
;cS/Hs				|	进位(Carryset)				|	C==1
;					|	无符号数高于或相同			|
;cc/Lo				|	未进位(carryclear)			|	C==0
;					|	无符号数低于					|		
;MI					|	负数(MInus)					|	N==1
;PL					|	非负数						|	N==0
;vs					|	溢出						|	V==1
;vc					|	未溢出						|	V==0
;Hr					|	无符号数大于				    |	C==1 && Z==0
;Ls					|	无符号数小于等于			    |	C==0 && Z==1
;GE					|	带符号数大于等于			    |	N==v
;LT					|	带符号数小于					|	N!=V
;Gr					|	带符号数大于					|	2==0 &&N=V
;LE					|	带符号数小于等于				|	Z==1||N!=V
;AL					|	总是						|	-
;—————————————————————————————————————————————————————————————————————


;第一个,B   label		;无条件跳转指令,执行指令后程序会无条件跳转到 label 标号的地址处开始执行程序,跳转范围:当前地址的前后 2KB 范围内。指令执行时间 3 个指令周期。
;第二个,BL  label		;无条件长跳转指令,执行指令后,先将下一条指令的地址备份到R14(LR)中,然后程序无条件跳转到label标号的地址处开始执行程序,跳转范围:当前地址的前后16MB范围内。
;						指令执行时间4个指令周期,常用于对程序,子程序的调用。
;第三个,BX  Rm		;执行指令后,程序跳转到Rm寄存器中的数据所指向的地址处开始执行,
;						Rm寄存器范围:任何寄存器指令执行时间3个指令周期。
;第四个,BLX Rm		执行指令后,先将下一条指令的地址备份到R14中,程序跳转到Rm寄存器中的数据所指向的地址处开始执行。
;						Rm寄存器范围:R0-R12,指令执行时间3个指令周期。(这个指令不常用)
;第五个,B{cond} cond  ;可以是EQ NE.....,例如我们可以这样写BNE BEQ BMI BPL等等,那么不同的指令用于不同的场合,对应不同条件的跳转。
;						前面我们学习过标志位,知道指令的执行结果影响标志位NZCV四个标志,那么条件跳转是根据什么跳转的呢,是以什么位条件的呢?
;						就是根据的这4个标志位的值来进行跳转的。 例如我们看 BEQ   

;							EQ						zset						equal
;						描述:equal就是相等的时候     Z set,即:Z置位   也就是Z=1;
;						那么这里列举了NZCV四个标志位的置位清零条件,那么我们可以根据这些不同的条件,
;						进行不同判断的时候,使用不同的指令来进行跳转。
;						指令完整的写法是B{cond} label
;						label是个标号也可以说是跳转到标号地址处开始执行,当然这个标号的也是由一个地址范围的,
;						不是说想跳多远就跳多远,
;						这个具体的跳转范围是在当前程序计数器(PC)+/-254个字节。条件跳转指令如果发生跳转,
;						指令执行需要3个指令周期,如果不发生跳转,指令执行需要1个指令周期。

;第1个BEQ				那接下来我们先看第一个BEQ指令,
;						BEQ指令是Z为1的时候跳转,
;						Z标志位:运行完结果如果是0 该位置1,如果不是0,该位置0。 
;						上述代码运行后,会执行MOVS R1,#0,跳过MOVS R2 ,#0; BEQ这条指令是Z=1跳转
;                       
;						那么执行完MOVS R0,R0,执行结果是0,因为R0里面是0,因为执行完结果是0,所以Z置1。
;                       那么BEQ是Z=1的时候跳转,所以执行到BEQ loop的时候就会发生跳转。跳转到loop这个标号处执行代码MOVS R1,#0

;第2个BNE				BNE是Z为0的时候跳转,Z标志位:执行结果为0,或者两个数比较相等的时候会置位。
;						那么换句话说就是,执行结果不为0。比较的时候两个数不相等的时候,就不置位,Z为0

;						因为MOVS R0,R0执行完结果为0,Z置1了,BNE是Z为0的时候才跳转,所以这里BNE的时候就不跳转继续向下MOVS R1,#1  
;						CMP比较,两个数不相等,Z=0发生跳转。

;第3个cs/Hs			BCS也可以写作BHS,都是一样的,这个是C=1的时候跳转,比较时大于和等于跳转。无符号加法溢出,无符号减法无借位  C=1 比较时大于和等于跳转,进位就是寄存器溢出

;第4个cc/Lo			BCC,或者BLO都是一个意思,可以写成BCC,可以写成BLO都可以,这条指令是C=0跳转,这条指令是没有进位(无符号加法),存在借位(无符号减法)或者比较小于的时候跳转 
;----------------------------
;举例
;MainLoop
	;BL	LedDisplay
	;BL	Co1orModule
	
	;B   MainLoop
	;-------------
	;BX,LR
    ;-------------
	;MOVS R0,#0
	;MOVS R0,R0
	;BEQ  loop
	;MOVS R2,#0
;loop 
	;MOVS R1,#0
    ;-------------
	;MOVS R0,#0
	;MOVS R0,R0
	;BNE  loop
	;MOVS R1,#1
;loop
	;MOVS R2,#1
	;-------------
	;MOVS R0,#0
	;MOVS R1,#1
	;CMP  R0,R1
	;BNE  loop
	;MOVS R1,#1
;loop
	;MOVS R2,#1
	
	;;-------------
	;LDR  R0,=0xFFFFFFFF
	;ADDS R0,#1
	;BCS  loop
	;MOVS R1,#1
;loop
	;MOVS R2,#1
	;;-------------
	;LDR  R0,=0xFFFFFFFE
	;MOVS R1,#1
	;SUBS R0, R1
	;BCS loop
	;MOVS R1,#1
;loop
	;MOVS R2,#1
	;;-------------
;Reset_Handler
	;MOVS R0,#5
	;MOVS R1,#6
	;CMP R1,R0 ;6>5
	;BCS loop
	;MOVS R1,#1
;loop
	;MOVS R2,#1
	;;-------------
	;CMP R0,R0;RO=RO
	;BCS loop
	;MOVS R1,#1
;loop 
	;MOVS R2,#1
	;;-------------
	;LDR R0,=0xFFFFFFFE
	;MOVS R1,#1
	;ADDS R1, R1,R0
	;CMP R0, R1
	;BCC loop
	;MOVS R1,#1
;loop
	;MOVS R2,#1
	;;-------------
	;LDR R0,=0xFFFFFFFE
	;MOVS R1,#1
	;ADDS R1,R1, R0
	;CMP R1, R0	; 1<OxFFFFFFFE
	;BCC loop
	;MOVS R1,#1
;loop
	;MOVS R2,#1
	;;-------------
	;MOVS R0,#0
	;MOVS R1,#1
	;SUBS R0,R0,R1;减法借位
	;BCC  loop
	;MOVS R1,#1
;loop
	;MOVS R2,#1
	;-------------

;------------------------------------------------12.序转指令------------------------------------------------	
;序转指令 	共3条
;含义:
;--------------
;REV Rd,Rm 		;1 Cycles 
;[31:24] <-->[7:0]
;[23:16] <-->[15:8] 
;REV16 Rd,Rm 	;1 Cycles 
;[31:24] <-->[23:16]
;[15:8]  <-->[7:0] 
;REVSH Rd,Rm 	;1 Cycles 
;[15:8]  <-->[7:0] 
;[31:16] 有符号扩展
;----------------------------
;第一个,REV Rd,Rm 	将Rm寄存器中数据的对应的位互换置。([31:24]<->[7:0]  [23:16]<->[15:8] ),然后存到 Rd 寄存器中.[31:24][7:0]互换位置 [23:16][15:8]互换位置。
;								
;第二个,REV16 Rd,Rm	将Rm寄存器中数据的对应的位互换位([31:24]<->[23:16]  [15:8]<->[7:0] ),然后存到 Rd 寄存器中。
;第三个,REVSH Rd,Rm	将Rm寄存器中的低16位数据对应的位互换位置([15:8]<->[7:0]),高16 位进行符号位扩展(互换过后如果bit15 位为 1,则高 16 位全为 1,如果互换过后 bit15 位为 0;						则高 16 位全为 0),然后存到 Rd 寄存器中。
;第四个,
;第五个,
;第六个,
;----------------------------
;举例
	;LDR R0,=0x0080;0000 0000 1000 0000
	;REVSH R1,R0
	;-------------
 
;------------------------------------------------13.SVC异常中断申请指令------------------------------------------------	
;SVC异常中断申请指令 共1条
;含义:
;--------------
;SVC #<imm8> ;SVC异常中断申请
;----------------------------
;第一个,SVC #<imm8> 	用户可以申请 SVC 异常中断,8 位立即数在申请时可以作为 SVC 函数的参数,作为系统所需要的异常服务号。一般用于有操作系统软件的程序中。
;第二个,
;第三个,
;第四个,
;第五个,
;第六个,
;----------------------------
;举例
 ;-------------

;------------------------------------------------14.中断指令------------------------------------------------	
;中断指令 	共2条
;含义:
;--------------
;CPSIE I ;1 Cycles 使能总中断
;CPSID I ;1 Cycles 禁止总中断
;----------------------------
;第一个,CPSIE I 	使能总中断 ;将 PRIMASK 的 BIT0 位清 0 打开除不可屏蔽中断之外的所有中断 指令执行周期 1 个指令周期。
;第二个,CPSID I 	禁止总中断 ;将 PRIMASK 的 BIT0 位置 1 禁止除不可屏蔽中断之外的所有中断?指令执行周期 1 个指令周期
;					CPSIE CPSID这两条指令,操作的就是特殊寄存器里面的这个位。
;第三个,
;第四个,
;第五个,
;第六个,
;----------------------------
;举例
 ;-------------
 
 ;------------------------------------------------15.特殊寄存器操作指令------------------------------------------------	
;特殊寄存器操作指令 共2条
;含义:
;--------------
;MRS Rd,specreg ;4 Cycles 	将特殊寄存器内容传输至Rd
;MSR specreg,Rd ;4 Cycles 	将Rd内容传输至特殊寄存器
;----------------------------
;第一个,MRS Rd,spec_reg 	将特殊寄存器中的内容传送到Rd,特殊寄存器指 xPSR PRIMASK CONTROL。
;第二个,MSR spec_reg,Rd   将Rd中的数据传送到特殊寄存器,这个就相当于是改写特殊寄存器中的内容。
;第三个,
;第四个,
;第五个,
;第六个,
;----------------------------
;举例
;MRS RO , xPSR
;MRS RO ,PRIMASK
;MRS RO , CONTROL
 ;-------------
 
 ;------------------------------------------------16.断点指令------------------------------------------------	
;断点指令 共1条
;含义:
;--------------
;BKPT #imm8 ;设置调试断点
;----------------------------
;第一个,BKPT  #<imm8> 设置调试断点,8位立即数表示调试断点的顺序号,这个是用软件的方法设置断点,实现的目的都是一样的。
;						例如这个红点,就是一个断点,这个是我们仿真的时候人工手动打的断点,鼠标左击每行代码左边灰色的地方,出现一个红点就表示断点,当仿真的时候?程序运行到这里就会停止。
;						比如说MRS前面放了一条指令,那么当仿真调试界面直接F5运行的时候,程序自动到箭头这里就停下来了,剩下的正常操作就行了,该单步执行单步执行,
;						如果想再次运行直接点运行就可以了,等于是暂停,要继续运行,点运行,开始执行剩下的程序。
;第二个,
;第三个,
;第四个,
;第五个,
;第六个,
;----------------------------
;举例
 ;-------------
 
 ;------------------------------------------------17.发送事件指令------------------------------------------------	
;发送事件指令 共1条
;含义:
;--------------
;SEV ;与WFE指令相关
;----------------------------
;第一个,
;第二个,
;第三个,
;第四个,
;第五个,
;第六个,
;----------------------------
;举例
 ;-------------
 
 ;------------------------------------------------18.休眠指令------------------------------------------------	
;休眠指令 共2条
;含义:
;--------------
;WFE ;休眠等待事件
;WFI ;休眠等待中断
;----------------------------
;第一个,SEV与WFE		指令相关用于产生事件,如果在执行WFE之前已经执行过SEV指令,那么在执行WFE的时候不会进入休眠状态。
;						如果在执行WFE之前没有执行过SEV指令,那么在执行WFE的时候会进入休眠状态
;						通过执行WFI/WFE 指令,可以请求系统进入睡眠模式,只不过执行这两个指令,从睡眠中唤醒的方式不一样
;第二个,
;第三个,
;第四个,
;第五个,
;第六个,
;----------------------------
;举例
 ;-------------
 
 ;------------------------------------------------19.空操作指令------------------------------------------------	
;空操作指令 共1条
;含义:
;--------------
;NOP ;1 Cycles 
;YIELD ;1 Cycles 在Cortex M0上同NOP指令
;----------------------------
;第一个,NOP          NOP空指令占用1个指令周期,这个指令我们会经常使用,这个NOP可以直译理解为,光吃饭不干活,占位的,
;					  我们可以用这个NOP 进行延时等,比如说一个NOP 是1个指令周期125ns,
;					  我写上10个NOP就是1250ns,那么这样就可以实现一个延时,而且时间是非常精准的。
;第二个,
;第三个,
;第四个,
;第五个,
;第六个,
;----------------------------
;举例
 ;-------------
 
 ;------------------------------------------------20.存储器屏蔽指令------------------------------------------------	
;存储器屏蔽指令 共3条 用于复杂的存储器系统
;含义:
;--------------
;ISB ;指令同步屏蔽
;DMB ;数据存储器屏蔽
;DSB ;数据同步屏蔽
;----------------------------
;第一个,
;第二个,
;第三个,
;第四个,
;第五个,
;第六个,
;----------------------------
;举例
 ;-------------
 
;------------------------------------------------21.常用伪指令------------------------------------------------	
;常用伪指令
;含义:
;--------------
;第一个,  定义程序段 AREA SectionName, CODE, READONLY    SectionName:表示段名  CODE: 表示代码部分 READONLY: 表示只读  
;			代码(CODE)节,通常只是只读(READONLY)节。
;			数据(DATE)节,通常是读写(READWRITE)节。
;			可能要写很多文件,每个文件里面有不同的函数用于实现不同的功能,然后不同的函数之间相互调用,来形成一个完整的工程。
;			每个文件的开头部分都需要AREA来给这个文件起个名字,那么这个SectionName就相当于是这个文件中代码区域的名字。后面的CODE和REDONLY是一个属性,表示这个代码段只读,
;			但是大家要记清楚,这个是在汇编文件中才写的,C语言文件中不需要写
 ;-------------
;第二个,	定义程序入口和结束 ENTRY END
;			我们刚才说了一个工程有好多个文件,那每一个文件有一个名字,按照这样的思想,每个文件也要有一个入口,ENTRY定义程序入口(可以省略),
;			END定义程序结束,ENTRY就表示这个文件的入口,那么在文件的结尾写上END,就表示这个文件结束了。
 ;-------------

;第三个,	定义常量 Name EQU expr
;			下面我们看一下EQU,C语言里面有#define 宏定义,例如#define X 10 ,这条代码的意思就是用X来替换10,
;			代码中看到了X都会被替换成10,这个EQU就和#define是类似的,EQU定义常量。
;			比如 COUNT EQU 4,那么在程序中看到COUNT就知道它是代表4。
 ;-------------
;第四个,	声明标号
 ;-------------
;			EXPORT Label
;			IMPORT Label
;			假如有AB两个文件,A文件中写了FUN1 FUN2函数 B文件中写了FUN3,FUN4函数,那么B文件想要调用A文件中的FUN1,那么FUN1必须在A文件中进行EXPORT声明
;			B文件想要调用A文件中的FUN1,仅仅是在A中进行EXPORT声明就可以了,当然不是。第二步就是还需要在B文件中做引用。
;			IMPORT LABEL表示要引用一个外部文件的标号。
;			引用之后外部文件的这个标号可以在当前这个文件中使用,也就是说不仅仅要在A文件中进行EXPORT FUN1 还要在B文件中 进行IMPORT FUN1 ,这样B才能顺利使用这个FUN1。
 ;-------------
;第五个,  定义数据
 ;-------------
;			DCB 分配连续的字节存储单元【1Byte】
;			DCW 分配连续的半字存储单元【2Bytes】
;			DCD 分配连续的字存储单元【4Bytes】
;			比如说  DCB  20,就是分配一个存储单元,这个存储单元里面存放20
;			换句话说就是从内存中申请一个存储单元,这个存储单元里面20
;			DCD 0x12345678申请连续4个字节存储单元,里面存放数据0x12345678。
;			当然也可以写成DCB 12,12,12 这样是表示连续申请3个字节的空间,每个存储单元分别存储的都是数据12
 ;-------------
;			SPACE FILL 填充0或数据
;			SPACE,SPACE申请一片内存空间,比如说NAME SPACE 20 ,我们申请了一片空间,这片空间的名字就叫NAME,这片空间20个字节,我们结合结构体来讲一下这段内容。
;			typedef struct
;			{
;			unsigned int Ticklma;
;			unsigned int Tickls;
;			unsigned int Ledcount;
;			}SysClock TypeDer:		
;			大家看这个是C语言中,我们构造的一个结构体数据类型,我们会用这个数据类型去定义结构体变量,那么我们用这个数据类型去定义结构体变量的时候,系统根据数据类型的大小给开辟了一片空间。
;			那么这片空间的大小跟什么有关系,跟结构体成员有关系,那么如上图这个结构体成员,都是unsigned int 类型, 每个成员都是32位的,占四个字节,那么这段空间总共是12个字节。
;			那我们访问结构体成员,如何访问,我们前面说过基地址+偏移量,基地址就是我们申请变量的是得到的地址。偏移量是什么,就是结构体成员,在我们看来这个结构体成员就是一个符号,这个符号代表了成员在这片空间本身在结构体内部的偏移量。那么就是基地址+偏移量就是我们可以操作的结构体成员
;			基地址+偏移量得到的还是一个地址,那么最终我们还是通过地址来操控结构体成员的,或者再直白一点说,就是操控申请变量的时候开辟的这片空间。
;			在C语言中,我们可以这样去定义结构体类型,定义一些我们想要的变量,那么在汇编中我们怎么操作呢,我们说了一切的思想都是地址,不管是C语言还是汇编,那么最最核心的还是操控地址来解决问题。
			 ;---------------------------------------
					   ;AREA	LedData,DATA,READWRITE
			;tLed	    SPACE	16     ; define l6 bytes
			;count	    EQu	    0	   ;offset
			;Value	    EoU	    4	   ;D7-Do
			;Mode	    EOU	    8	   ;
			;NoteValue	EoU	    12	   ;
			 ;---------------------------------------
;			大家看tLED SPACE 16,这里我们是不是申请了一片空间,这片空间名字叫tLED,大小为16 个字节,那么这个空间的名字也代表了这片空间的基地址,那么访问这片空间里面不同的地址怎么访问,是不是还缺少一个偏移量?
;			大家看下面的Count EQU 4,大家看看这个是不是相当于定义一个常量,相当于说Count就代表了4,Value就是代表了4,tLED+Count    tLED+Value。那么大家现在在看这个,是不是相当于就是基地址+偏移量的概念。
;			从另一种角度上讲,我们是不是也可以把这个tLED+Count当成一个变量(类比C语言),可以通过这个地址操控从这个地址开始的空间,那么操控多少个字节。我们看这里每个常量是间隔4,那么从当前偏移量到下一个偏移量之间是有4个字节的空间是可以操作的,我们就可以认为当前的变量是4个字节(32位)变量。
;			那么我们要访问地址是不是通过LDR,STR这样的加载或者存储指令从内存中加载或者写数据,LDR?R0,=tLed+Count
;			把这个地址加载到寄存器R0中
;			LDR R1,[R0]   对应的把地址里面的数据加载到R1中
;			LDR R0,=tLED+Count,大家看tLed?这是这片空间的名字,也代表了这片空间的地址,那么这片空间的基地址假如是0x2000?0000
;			大家看加载到R0里面是什么数据是0x2000 0000因为Count是0
;			LDR R0,=tLED+Count,那么R0里面就是0x2000 0000这是地址,那么我要从这个地址里面加载4个字节的数据LDR?R1,[R0];			LDR R0,=tLED+Count
;			STR R1,[R0] 
;			那么这个对应的就是把R1中的数据写到R0这个地址里面。
;			注意:我们要看不同的偏移来使用LDR,LDRH,LDRB或者STR,STRH,STRB 。
;-------------
;第六个,条件编译
;IF ELSE ENDIF
;----------------------------
;举例
;---------------If else 分支-------------------------
;If else 分支
;	if (i < 100)
;			i ++;
;	else
;			i = 0;
;---------------
;	cmp R0,#100
;	bcs _R0_clear ;大于等于跳转 C=1
;	adds R0,R0,#1 
;	b _R0_done
;_R0_clear
;	movs R0,#0
;_R0_done

;绿线上面是C语言的if else判断,下面是用汇编写的一样的功能判断
;C标志位是什么时候发生变化?
;前面说C标志位主要是用在无符号的情况下,加操作有进位或者减操作没有借位C置1,加操作没有进位或者减操作发生借位该位置0。
;BCS也可以写作BHS,都是一样的,这个是C=1的时候跳转。
;CMP R0,#100 假如R0的值小于100执行完C=0
;CMP R0,#100 假如R0的值大于100执行完C=1。
;假如R0小于100 那么执行完C=0 ,那么执行BCS的时候是不跳转到clear,继续往下执行add指令
;那么执行完ADD之后 就接下来执行 B强制跳转,跳转到done
;就相当于C语言里面的:
;if(i<100) i++ if就是判断意思,就是假如i<100 那么执行i++。
;那么假如R0,大于100 那么执行完CMP指令?C就为1,那么就跳转到了clear执行,就执行movs r0,#0。	
;---------------Loop 循环----------------------------
 ;Loop 循环
;	i = 0;
;	do
;	{
;		i ++;
;	}while(i<10);

;-----------
;	movs R0,#0
;_R0_loop 
;	adds R0,R0,#1 
;	cmp R0,#10
;	bcc _R0_loop ;小于跳转 C=0

;这里我们先看汇编,第一步movs r0,#0,设置r0为0。
;下面就是开始R0的值加1,也就是add指令。
;接下来就是比较r0和10的关系,假如r0小于10执行完C=0
;那么BCC是 C=0的时候跳转,跳转到标号_r0_loop处
;那么就重新开始执行,重新开始执行r0加1
;然后再重新判断
;一直到R0加到10的时候C=1了,这个时候就不跳转了,就继续往下执行省略号后面的内容了。
;--------------Table 查表-----------------------------
 
;Table 查表
;unsigned short int Table[5] = {0x0000,0x1111,0x2222,0x3333,0x4444};
;unsigned short int a;
;unsigned char i;
;i = 3;
;a = Table[i];
;-------------------
;	movs R0,#3
;	ldr R1,=TableAddress
;	lsls R0,R0,#1
;	ldrh R2,[R1,R0]
;...
;TableAddress
;	dcw 0x0000
;	dcw 0x1111
;	dcw 0x2222
;	dcw 0x3333
;	dcw 0x4444
;------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------		

	NOP
	END
















;------------------------------------------------指令------------------------------------------------	

;含义:
;--------------

;----------------------------
;第一个,
;第二个,
;第三个,
;第四个,
;第五个,
;第六个,
;----------------------------
;举例
 ;-------------
		




---
  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值