嵌入式:ARM汇编语言程序设计基础教程

news2024/9/30 19:35:53

文章目录

    • 汇编语言程序设计的步骤
    • 顺序程序设计
    • 分支程序设计
    • 循环程序设计
    • 子程序设计
      • 寄存器传递参数方式
      • 存储区域传递参数方式
      • 堆栈传递参数方式

汇编语言程序设计的步骤

① 合理地分配存储器资源,将前述的目标系统‘数据结构模型’表示到各存储器单元。

② CPU寄存器数量有限,在程序中,大多数操作都要使用寄存器;并且有的操作使用特定的寄存器(如堆栈操作使用SP/R13等),程序中要合理分配各寄存器的用途。

用计算机语言,对数据结构模型和流程图表示的算法进行准确地描述。

① 语法调试:排除程序中的语法错误。

② 功能调试:保证程序的逻辑功能正确性。

用文档形式记录说明程序的功能、使用方法、程序结构、算法流程等每一个阶段的工作。 把解题的方法、步骤用框图形式表示。如果问题比较复杂,那么可以逐步细化,直到每一框图可以容易编程为止。流程图不仅便于程序的编制,且对程序逻辑正确性也比较容易查找和修改。

顺序程序设计

顺序程序是一种最简单的程序结构,也称为直线程序,它的执行自始自终按照语句的先后顺序进行。这种结构的流程图,除了有一个起始框,一个终止框外,就是若干执行框。

例:试编制一程序,完成10+3的操作。

在这里插入图片描述

AREA  ARMex, CODE, READONLY	; 代码段名ARMex
ENTRY					; 程序的入口
CODE 32

start
	MOV	R0,	#10		; 将立即数10存入寄存器R0
	MOV	R1,	#3		; 将立即数3存入寄存器R1
	ADD	R0,	R0,	R1	; R0 = R0 + R1
stop
	MOV	R0,	#0x18		; 这三条指令是ADS调试环境特约
	LDR	R1,	=0x20026	;程序运行结束返回编译器调试环境
	SWI		0x123456

END				; 结束 

分支程序设计

许多实际问题需要根据不同的情况作出不同的处理。在程序中,针对不同的情况把不同的处理方法编制成各自的处理程序段,运行时由机器根据当时的条件自动作出判断,选择执行相应的处理程序段。这样的程序结构中,计算机不再完全按指令存储的顺序执行,称之为分支。分支程序使用转移指令B、子程序调用指令BL或带状态转移指令BX来实现。

例:给定以下符号函数:

在这里插入图片描述

任意给定值,假定为-25,存放在x单元,函数值存放在y单元;要求根据x中的值来确定y的值。

 AREA symbol, CODE, READONLY ; 代码段的名字 symbol

 ENTRY           ; 程序的入口

 CODE32

start

 LDR   R0, =x ; 加载数据段中的变量x地址,存入R0

 LDR   R1, =y ; 加载数据段中的变量y地址,存入R1

 LDR R2, [R0] ; 加载变量x的值,存入R2

compare

 CMP R2, #0 ; 将R2的值与0作比较

 BEQ ZERO ; 如果R2等于0,那么转向标号ZERO处

 BGT PLUS ; 如果R2大于0,那么转向标号PLUS处

 MOV R3, #-1 ; 否则,R2小于0,将-1存入R3中

 B stop

ZERO

 MOV R3, #0 ; R2等于0,将0存入R3中

 B stop

PLUS

 MOV R3, #1 ; R2大于0,将1存入R3中

; 续上段代码

stop 

  STR R3,  [R1]

 MOV R0,  #0x18 

 LDR R1, =0x20026

 SWI 0x123456

      AREA Data, DATA, READWRITE

x DCD -25

y DCD 0

   END 

循环程序设计

顺序程序和分支程序中的指令每次运行最多只执行一次。在实际应用中重复地做某些事的情况很多,这也是计算机最擅长的工作方式。重复地执行某些指令,最好用循环程序来实现。
循环程序的结构—重复地执行同一种运算,直到某种条件满足。

建立循环初始值。如设置地址指针、计数器、其他循环参数的起始值等。循环程序的主体业务代码,可以是一个顺序程序、分支程序或另一个循环程序。 为执行下一个循环而修改某些参数,尤其循环控制变量的修改等。

条件控制循环:通过判断循环终止条件是否已成立,控制循环。判断循环结束条件是否成立,决定是否继续循环。

例如:计数控制循环;通过计数循环次数,判断是否已达到预定次数,控制循环。对循环结束进行适当处理;有的循环程序可以没有这部分。

用计数控制循环适用于已知循环次数的循环程序设计

例:从x单元开始的30个连续字单元中存放有30个无符号数,从中找出最大者送入y单元中。

在这里插入图片描述

分析:

根据题意,把第一个数先送入Rx寄存器,将Rx中的数与后面的29个数逐个进行比较,如果Rx中的数较小,则将该较大的数送入Rx ;继续与余下的数据逐个比较。在比较过程中, Rx中始终保持较大的数,共计比较29次,则最终Rx中保留了最大数,最后把Rx中的数(最大者)送入y单元。

	AREA  max, CODE, READONLY		; 代码段的名字 max
	ENTRY                   			; 程序的入口
	CODE32
num	EQU	29                   ; 比较的次数
start
	LDR	R0,  =x           ; R0指向源数据块x
	LDR	R1,  =y           ; R1指向单元y
	LDR	R2,  =num      ; R2作为计数器
	LDR	R3,  [R0]        ; 将源数据块x中第一个数加载到R3中
compare
	ADD	R0, R0,	#4       ; 每进行一次比较,将R0指针地址加4
	LDR	R4, [R0]          ; 依次将源数据块x中下一个数加载到R4中
	CMP	R3, R4             ; 比较R3和R4中数的大小 
	MOVCC  R3,  R4          ; 如果R3小于R4,则将较大的数送入R3中
	SUBS	R2,  R2,  #1       ; 计数器值减1
	BNE	compare           ; 如果不为0,那么继续跳到compare执行
	STREQ	R3,  [R1]          ; 如果为0,那么循环比较结束,R3是最大的数
			       ; 并且将R3中的数加载到R1指向的单元(即y)中 


stop
	MOV	r0, #0x18
	LDR	r1, =0x20026		
	SWI	0x123456        

	AREA  Data, DATA, READWRITE
x	DCD	73,59,61,34,81,107,225,231,54,43
	DCD	100,35,1,42,222,254,34,71,100,31
	DCD	33,119,13,44,18,147,55,244,97,3
y	DCD	0
	END

② 适用于已知循环条件的循环程序设计

适用于无法确定循环次数,但知道循环结束的条件

例:从自然数1开始累加,直到累加和大于1000为止,统计被累加的自然数的个数,并把统计的个数送入n单元,把累加和送入sum单元。

分析:

根据题意,被累加的自然数的个数事先未知,因此不能用计数方法控制循环。但题目中给定一个条件,即累加和大于1000则停止累加,因此,可以根据这一条件控制循环。我们用R3寄存器放累加和,用R4寄存器放每次取得的自然数,其中它的值也是统计自然数的个数。

在这里插入图片描述

     AREA  SUM, CODE, READONLY	; 代码段的名字 SUM
     ENTRY                   			; 程序的入口
     CODE32
start
     LDR   R0,   =n            ; 将数据段中自然数的个数n的地址加载到R0寄存器
     LDR   R1,   =sum       ; 将数据段中自然数的累加和sum的地址加载到R1寄存器
     LDR   R3,   =0            ; R3存放自然数的累加和
     LDR   R4,   =0            ; R4用于循环个数的统计/每次取得的自然数
     LDR   R5,   =1000      ; R5用于循环结束的界限值
continue
     ADD	R4,   R4,	    #1    ; 取下一个自然数
     ADD	R3,   R3,	   R4    ; 累加自然数
     CMP	R3,   R5             ; 比较累加和是否超过了1000
     BCC	continue            ; 如果小于1000,那么跳到compare执行
     STRCS   R3,  [R1]     ; 如果大于1000,那么将累加和存储到R1所指向的单元中
     STRCS   R4,   [R0]    ; 如果大于1000,那么将已累加的自然数个数值存储
		            ; 到R0所指向的单元中 


stop
        MOV    r0, #0x18
        LDR     r1, =0x20026			
        SWI     0x123456 
     		
        AREA  Data, DATA, READWRITE
n	DCD	0	    ; 定义累加的自然数的个数
sum	DCD	0 	   ; 定义自然数的累加和

        END

子程序设计

子程序概念

如果在一个程序中的多处用到同一段程序代码,那么可以把这段共同的程序代码抽取出来,写成一个相对独立的程序段,每当需要执行这段代码时,就调用这个程序段,执行完这个程序段后,再返回原来调用它的程序。这样编写程序时,就不必重复写这段代码了,而这样的程序段称为子程序或子过程。

子程序的调用与返回

主程序中使用BL指令实现子程序的调用

BL 子程序名

在子程序结束处,使用如下指令返回到主程序中。

MOV PC, LR

主程序与子程序之间的参数传递

主程序调用子程序时,可以向子程序传递一些参数;同样,子程序运行后也可把一些结果参数传回给主程序。主程序与子程序之间的这种信息传递称为参数传递。

三种参数传递方式

  1. 寄存器传递参数方式
  2. 存储区域传递参数方式
  3. 堆栈传递参数方式

寄存器传递参数方式

例:用子程序实现内存区里的字符串拷贝功能,即将存储单元中源字符串对应拷贝到目的字符串中。

技术思想:主程序将待传递的数据直接写入约定的通用寄存器,在子程序中直接使用;或子程序返回后,主程序直接从约定的通用寄存器中获得子程序的结果数据。

应用特点:这种方式适合于传递较少参数的应用场合。

解题思路:

通过设定两个地址指针,分别指向存储区中的源字符串和目的字符串;然后通过加载和存储指令(LDR和STR)的寄存器间接寻址方式,依次从源字符串读取一个字符数据,写入到目的字符串的对应字符位置中,直到遇到源字符串的结束标志’\0’为止。

AREA    StrCopy, CODE, READONLY
        ENTRY
        CODE32
start
        LDR       R1,    =srcstr        ; R1指向数据区的源字符串
        LDR       R0,    =dststr        ; R0指向数据区的目的字符串
        BL          strcopy                 ; 调用子程序strcopy,完成字符串拷贝
stop
        MOV     R0,     #0x18	         ; 程序结束返回编译器调试环境
        LDR      R1,     =0x20026
        SWI        0x123456
strcopy 
        LDRB     R2,     [R1],    #1    ; 将R1指向的单元内容加载到R2中
        STRB      R2,     [R0],    #1    ; 将R2中的数存储到R0指向的单元中
        CMP       R2,    #0                 ; 检查R0的值是否等于0
        BNE        strcopy                  ; 如果不等于0,那么转到strcopy处执行 
        MOV       PC,    LR               ; 子程序返回 


        AREA    Strings, DATA, READWRITE
srcstr  DCB "First string - source",0		; 源字符串
dststr  DCB "Second string - destination",0	; 目的字符串
        END 

存储区域传递参数方式

例:通过设置的入口参数查找函数地址表,实现选择不同的函数功能。

说明:本题中通过事先将函数地址存放在存储单元中,通过查找地址表的方法,实现根据“选择项(choice)”进入不同的函数体功能。

技术思想:主程序和子程序约定了某一共享内存块用于参数传递,主程序在BL调用子程序前,先将要传递的参数写入到约定的存储单元,子程序可从约定的内存读取这些参数;子程序返回时,也可以使用该方式将数据传给主程序。

应用特点:这种方式可以传递大批量数据。

实现方法:当主程序与子程序有较多的数据需要传递时,可以通过共享内存区或传内存数据块地址方式来传递批量数据。

通过伪指令ADR直接装载近距离数据块地址;

通过伪指令ADRL直接装载中距离数据块地址;

通过语句LDR Rd, =Label转载远距离的数据块地址;

       AREA    Jump, CODE, READONLY
       num     EQU     4			; 函数地址表内容的个数
       ENTRY
       CODE32
start
     LDR   R0,   =choice		; R0指向存储区的choice单元
       LDR   R0,   [R0]		; 设置第一个参数:选择执行哪一个函数
       MOV  R1,   #16		; 设置第1个操作数
       MOV  R2,   #2		; 设置第2个操作数
       BL       arithfunc		; 调用子程序arithfunc
stop
       MOV   R0,   #0x18		; 程序结束返回编译器调试环境
       LDR    R1,   =0x20026
       SWI	     0x123456
arithfunc
       CMP   R0,    #num                     ; 比较R0的值是否超过函数地址表的个数
       MOVHS   PC, LR  		; 如果大于,那么就返回到标号stop处
       ADR   R3,    JumpTable	; 将函数地址表的地址作为基地址
       LDR    PC,   [R3, R0, LSL #2]	; 根据R0参数进入对应的子程序


JumpTable	; 函数地址表的入口基地址
        DCD     	DoAdd		; 加法子程序
        DCD	DoSub		; 减法子程序
        DCD	DoMul		; 乘法子程序
        DCD	DoDiv		; 除法子程序
DoAdd
        ADD   R0,   R1,    R2               ; R0 = R1 + R2
        MOV   PC,   LR		; 返回
DoSub
        SUB    R0,	R1,    R2      	; R0 = R1 - R2
        MOV   PC,	LR		; 返回
DoMul	
        MOV   R0,   R1,  LSL R2 	; R0 = R1 << R2
        MOV   PC,   LR 		; 返回
DoDiv	
        MOV   R0,   R1,  LSR R2      	; R0 = R1 >> R2
        MOV   PC,   LR	 	; 返回		
	  AREA  NUM, DATA, READWRITE
choice	DCD	3           ; 0:表示选择加法子程序   1:表示选择减法子程序
		             ; 2:表示选择乘法子程序   3:表示选择除法子程序
        END

堆栈传递参数方式

主程序和子程序使用同一个堆栈,主程序在BL调用子程序前,先将要传递的参数压入到堆栈中,子程序可从堆栈中读取传过来的数据;子程序返回需要向主程序传递参数时,也可使用此方法。

参考文献:

孟祥莲.嵌入式系统原理及应用教程(第2版)[M].北京:清华大学出版社,2017.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/128473.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

pytorch集锦(4)-ResNet图像分类

目录加载训练好的模型下载模型权重图像预处理打开要预测的图像传递图像运行模型下载数据打开imagenet_classes.txt预测结果前5个最可能分类加载训练好的模型 pip3 install pillow>>> from torchvision import models >>> dir(models) [AlexNet, DenseNet, I…

有哪些简单、免费、适合中小型企业的 CRM 软件?

有哪些简单、免费、适合中小型企业的 CRM 软件&#xff1f; 为了更好的管理客户&#xff0c;和客户建立持续的良好关系&#xff0c;很多企业开始采用CRM软件。 但是免费且好用的CRM软件并不多见&#xff0c;因此选择一款适合中小型企业的CRM软件需要注意以下方面。 1. 知己&…

微信小程序布局图片上面显示文字

实现的效果&#xff1a; xml布局文件&#xff1a; <view class"image-parent"> <image classimage modewidthFix src../../images/answer-ad.png></image> <view class"child">child</view> </view> css文件&a…

26-剑指 Offer 29. 顺时针打印矩阵

题目 输入一个矩阵&#xff0c;按照从外向里以顺时针的顺序依次打印出每一个数字。 示例 1&#xff1a; 输入&#xff1a;matrix [[1,2,3],[4,5,6],[7,8,9]] [[1,2,3], [4,5,6], [7,8,9]] 输出&#xff1a;[1,2,3,6,9,8,7,4,5] 示例 2&#xff1a; 输入&#xff1a;m…

年终摸鱼:用高效的技术对抗繁琐的运维日常

2022年的最后一周 免疫系统直接把我带入高端局 霍一下子烧到40&#xff0c; 差点起来写遗嘱 好在第二天就降到了38.5 现在除了有点咳嗽、头昏、无力。。。 也没啥大问题——到底是年轻。 谁能想到疫情蔓延三年&#xff0c; 所有人还要来一场集体“免疫”呢&#xff1f; …

太力科技冲刺上市:石正兵为实控人,股东刘健为失信被执行人

近日&#xff0c;广东太力科技集团股份有限公司&#xff08;下称“太力科技”&#xff09;在深圳证券交易所递交招股书&#xff0c;准备在创业板上市。 本次冲刺上市&#xff0c;太力科技计划募资5.42亿元&#xff0c;其中3.20亿元用于太力武汉生产及物流中心建设项目&#xf…

高频次收集个人信息情况分析

奇安信 2022年第二季度App收集个人信息检测报告 下载地址 2022年第二季度 APP收集个人信息 检测报告 奇安信 病毒响应中心 研究背景 随着互联网和移动设备的发展&#xff0c;手机已成为人人都拥有的设备&#xff0c;其中各式各样的APP更是丰富了人们的生活&#xff0c;从社交…

TCP/IP网络编程(11) 套接字和标准IO

标准IO函数的优点 标准IO函数具备两大优点&#xff1a; 标准IO函数具备良好的移植性标准IO函数可以利用缓冲提高性能 不仅是IO函数&#xff0c;所有的标准函数都具有很好的移植性&#xff0c;为了支持所有的操作系统和编译器&#xff0c;这些函数都是按照ANSI C标准定义的&am…

大数据和数据可视化为什么这么受欢迎?

“大数据”已经从一个概念性质的词语转变为了对经济社会各个领域都具有渗透影响的事物&#xff1b;并且随着互联网技术的持续发展&#xff0c;大数据所产生的影响呈现出了范围不断扩大&#xff0c;深度持续扩展的新特征。 大数据时代就是指人们的生产、生活和工作中出现更多的…

windows VS2015 Steup 打包发布软件并附带动态链接库dll

打包&#xff1a; 方法一&#xff1a;VS 2015 Steup 打包发布软件_柠檬野生菌的博客-CSDN博客_vs2015 exe发布 1、插件下载Microsoft Visual Studio 2015 Installer Projects 工具->扩展与更新->联机->搜索 Installer Projects 2、安装 关掉VS 双击下载好的 .exe …

ArcGIS基础实验操作100例--实验21按区域修改栅格值

本实验专栏来自于汤国安教授《地理信息系统基础实验操作100例》一书 实验平台&#xff1a;ArcGIS 10.6 实验数据&#xff1a;请访问实验1&#xff08;传送门&#xff09; 基础编辑篇--实验21 按区域修改栅格值 目录 一、实验背景 二、实验数据 三、实验步骤 &#xff08;1&…

8、多线程

文章目录8、多线程8.1 线程中的进程8.2 进程中的线程8.3 自己的第一个线程8.4 线程的生命周期8.5 线程执行方式&#xff08;串行和并发&#xff09;8.6 线程休眠8.7 工作8.8 线程池8.9 同步8.10 wait和sleep8.11 线程安全问题Java零基础极速入门-讲师&#xff1a;海波 失败&…

一文快速上手Swagger

目录 1.什么是Swagger&#xff1f; 2.Swagger的作用&#xff1f; 3.Swagger的使用方法 &#xff08;1&#xff09;一般是在Spring Boot项目中进行集成&#xff0c;只需在项目中引入springfox-swagger2和springfox-swagger-ui依赖即可 &#xff08;2&#xff09;配置Swaage…

[虚幻引擎][UE][UE5]在UE中画一个线框球,网格连接画球,高阶画球并操控

[虚幻引擎][UE][UE5]在UE中画一个线框球&#xff0c;网格连接画球&#xff0c;高阶画球并操控1.材质法2.绘制调试球体3.网格连接4.高阶画球并操控1.材质法 缺点&#xff1a;是实体的&#xff0c;只能欺骗视觉&#xff0c;实际还是一个实体体积球&#xff0c;往里放东西显示不出…

电磁兼容测试整改

1.1 什么时候需要电磁兼容整改及对策 在设计阶段就应考虑电磁兼容性&#xff0c;将产品生产阶段出现电磁兼容问题可能性减小。最终要通过电磁兼容测试检验其电磁兼容标准的符合性。 由于电磁兼容的复杂性&#xff0c;即使电磁兼容设计问题考虑比较周全&#xff0c;在设计制造…

SpringBoot+AOP+自定义注解,实现日志记录/权限验证

目录自定义注解简介AOP实现日志记录1.导入依赖2.创建自定义注解3.编写切面类4.编写测试接口5.测试AOP实现权限验证1.创建自定义注解2.编写切面类3.编写测试接口&#xff1a;4.测试自定义注解简介 为什么要通过AOP来实现日志记录 在业务处理中&#xff0c;我们经常需要将一些用…

基于springboot家政管理系统

大家好✌&#xff01;我是CZ淡陌。一名专注以理论为基础实战为主的技术博主&#xff0c;将再这里为大家分享优质的实战项目&#xff0c;本人在Java毕业设计领域有多年的经验&#xff0c;陆续会更新更多优质的Java实战项目&#xff0c;希望你能有所收获&#xff0c;少走一些弯路…

Python数据容器--字符串(str)

1、字符串的定义 字符串是字符的容器&#xff0c;一个字符串可以存放任意数量的字符。 如&#xff1a;字符串&#xff1a;“itheima”。 2、字符串的相关操作 2.1 字符串的下标索引取值 从前向后&#xff0c;下标从0开始。从后向前&#xff0c;下标从-1开始。 my_str &quo…

【LeetCode每日一题】——611.有效三角形的个数

文章目录一【题目类别】二【题目难度】三【题目编号】四【题目描述】五【题目示例】六【解题思路】七【题目提示】八【时间频度】九【代码实现】十【提交结果】一【题目类别】 二分查找 二【题目难度】 中等 三【题目编号】 611.有效三角形的个数 四【题目描述】 给定一…

数据库管理-第五十期 半百(20221230)

数据库管理 2022-12-30第五十期 半百1 半百2 展望3 计划总结第五十期 半百 1 半百 不知不觉&#xff0c;来到了第五十期&#xff0c;自从立了flag以后也几乎保持了一周一篇文章的频率&#xff0c;当然不得不承认&#xff0c;文章质量还是参差不齐的&#xff0c;有好几篇还是挺…