TI教室 >
应用与设计 >
工业应用 >
工厂自动化与控制系统 >
Logistics Robots >
TI-RSLK 模块 3 - ARM Cortex M > TI-RSLK 模块 3 - ARM Cortex M 组件
- 本课程为精品课,您可以登录eeworld继续观看:
- TI-RSLK 模块 3 - ARM Cortex M 组件
- 登录
- 课程目录
- 相关资源
- 课程笔记
大家好,
我是 Jon Valvano,在本视频中,
我们将讨论汇编语言编程。
正如我上次说过的,您对 Cortex M 处理器
了解的越多,您就越了解
计算机实际上是如何执行
代码的,也就越有可能成为更加优秀的嵌入式
系统工程师。
因此,即使您使用C 编写您的所有程序,
我也认为您应该在机器级别
或汇编级别了解您的程序的实际
执行方式。
因此,我们要在这里讨论
Cortex M 上的几条指令,以便在您
调试 C 代码时,您可以了解它在做什么。
让我们开始吧。
让我们从逻辑运算开始。
正如您知道的,我们将使用“与”运算来执行掩码。
因此,如果我们以“1”结束,那么它将用于选择位。
如果我们以零结束,那么我们将清除位。
这里的或运算用于设置位。
因此,如果我们与一执行或运算,那么它将设置位,
如果我们与零执行或运算,则不会发生任何变化。
我们将使用或来设置位
或将两个不同数字的不同部分
合并到一个值中。
我要讨论的第三个逻辑
运算是异或。
因此,如果我与一执行异或运算,那么它将对该位取反。
换句话说,如果我进行切换,如果我与一执行
异或运算,它将从一变为零,或者从零变为一。
如果我与零执行异或预算,则不会发生变化。
那么,再说一次,我们也会在该课程使用异或。
这里是汇编语言指令。
这里是操作码。
这些是操作数。
这恰好是寄存器或立即寻址模式。
具体而言,在这里,Cortex M 上的大多数指令
都沿着这个方向执行。
换句话说,这里的指令获取 R2 中的值、
R1 中的值,然后一起对它们执行或运算,
并将结果放回到 R0 中。
您需要从这里面获取的 --
我们也会在C 中看到它 --
这称为按位逻辑运算。
那么,在本例中,我们要将 R1 的值
与 R2 的值执行或运算。
在这里,我有一些随机数,它们可能
已位于 R1 和R2 中,这样,您就
可以看到会发生什么情况。
它是按位发生的。
因此,如果您选择这里的一个位 --
让我们看看位八
我们会看到它将获取 R1 中位八的值
以及 R2 中位八的值,将它们在一起
对齐,然后将该值存储到 R0 的位八中。
它会对全部 32 个位执行该过程。
再说一次,逻辑运算用于设置和清除位。
移位运算本质上是除法或乘法运算。
换句话说,向右移位即除以二,
向左移位即乘以二。
但您需要了解的重要部分是这样
一个事实,即您需要知道您具有的是
无符号数还是有符号数,这一点
对您而言非常重要。
因为如果它是无符号数,那么
您需要进行逻辑移位,以便
零移位到这里,您实际上将这个数除以 2。
相反,如果它是算术移位,
那么您将在将其向右移位时保留
最高有效位。
因此,了解该运算的重点在于这样的事实,
即您看到您具有一个 32 位寄存器。
因此,我们将在对该32 位数字进行运算,
您应该知道您具有的数字是有符号数还是
无符号数,这一点很重要。
当您向左移位时,无论它是有符号数
还是无符号数都没有关系。
我们将放入一个零。
再说一次,运算沿着这个方向执行。
因此,它会获取RM 中的值,
将其右移多次,然后将结果存储到结果
寄存器中。
因此,我们将使用移位来移动位,或者
执行乘和除。
这里的重点是,它是 32 位运算,
您必须知道它是有符号数还是
无符号数。
算术运算 -- 它看起来很容易执行。
我将获取两个数字,然后我要
将它们相加。
P 等于 m 加 n。
但这里的问题是,它们是 32 位寄存器,
如果我获取该 32 位数字,然后将其与
另一个 32 位数字相加,我实际上将得到 33 位。
这就导致了一种可能,即我的结果
可能无法重新存储到我的 32 位
寄存器中,我可能会出错。
该错误称为溢出。
该情况会在加法和减法中发生。
它实际上在乘法中更糟糕。
如果我获取一个 32 位数字,然后将其与另一个 32 位
数字相乘,那么我实际上得到 -- 理论上而言
我得到 64 位。
那么,这是一条溢出路线。
那么,当您编写您的软件来防止或消除
对该溢出情况的担忧时,我们将要做两件事。
第一件事是,我们将通过某种方法在理论上
预测中间结果的最大值将是多少,
并确保该值不超过 32 位。
因此,这通常意味着我们知道该值、
我们的输入的范围,并且我们知道输入是受限的。
那么,例如,如果您知道我有一个 12 位的数字 --
换句话说,我知道我的数字介于 0 和 4,095 之间 --
我获取该数字,然后我将其乘以 1,000,
我知道它可能达到的最大值是 400 万。
这是它可能达到的最大值。
因此,理论上而言,这是一个 10 位的数字。
因此,我知道该数字可以存储在 22 个位中。
因此,如果我可以限制输入并且我
知道该限制是什么,那么我可以
在理论上证明,在整个计算中,
任何中间结果都不会超过 32 位限制。
我们将用于解决它的第二种方法是,
将其升级至更高的精度。
因此,我可能必须在64 位模式下执行运算,
或者我可能必须获取我的16 位运算并在 32 位
模式下执行它们。
因此,升级将使数字更大,
在该更高的精度下执行运算,
然后再将其降级回到原来的精度。
因此,您需要控制您的
数字的大小,这一点很重要,
因为我们在该处理器结构中具有该 32 位限制。
当我们执行除法时,很显然,我们不希望除以零,
另一个可能发生的问题是
称为掉出的问题,它会在除法上发生。
此外,它还会在向右移位上发生,正如我们先前看到的,
向右移位是除法。
基本而言,掉出即信息丢失。
正如您看到的,这相当容易。
如果我获取数字 n并将其除以 1,024,
这在本质上将丢弃 10 个位。
因此,我将丢失我的数字的最低 10 个位。
因此,再说一次,我要小心提防因为掉出
而导致灾难性的信息丢失 -- 因为溢出而导致
灾难性的信息丢失,以及因为
除法或向右移位而导致信息丢失。
就像移位、加法、减法以及乘法
和除法一样,您必须确保您知道
它是有符号数还是无符号数。
使用一个有符号数与一个无符号数
进行加、减、乘、除
是没有意义的。
因此,我们无法对两个类型不同的数字进行
算术运算。
这没有任何意义。
基本而言,我们必须将无符号数之一升级为
更大的有符号数,以便我们可以对它们
一起进行运算。
这是加法指令。
再说一次,它的工作方式是,
它获取第二个操作数,这可能是一个寄存器,
将其与中间操作数相加,然后这两个
操作数进入这里。
请注意,在汇编级别,它实际上会设置一些标志。
进位标志会在发生无符号溢出时设置,
溢出 V 位会在发生有符号溢出时设置。
不幸的是,C 中不提供这些位,
当我们执行加、减、乘和除运算时,
我们必须限制输入,
或者我们必须升级到更高的精度,
以防发生溢出。
当我们获取 F 时,我们将看到比较
指令。比较指令其实就是减法,
但它不在任何位置
存储结果,它用于 if/then 语句。
乘法和除法 --再说一次,我们
先前已提到,必须确保您
知道您的数字是有符号数还是无符号数。
实际上,我们有一条不同的
用于无符号数/除法与有符号数/除法的指令。
就像所有其他指令一样,
该运算沿着这个方向执行。
您可以看到它是寄存器寻址。
因此,它获取该数字,将其
乘以该数字,然后将结果存储在该位置,
存储在该寄存器中。
这是前一个讲座中介绍的有关我如何
访问变量的原理。
那么这位于 RAM 中。
那么我在这里有一个 RAM 变量。
我在那里有另一个 RAM 变量。
我们上次看到了访问 RAM 变量需要
执行两个步骤。
第一步是获取指针。
这是该指令。
这里是指针。
那么,这是指向该点的 32 位指针,
那么,这里的第一条指令将设置 R3,以指向
该 RAM 位置。
然后,我们可以使用第二条指令来访问它。
在本例中,我将读取该值。
现在,我们要乘以三
并除以五,再说一次,
这里是乘法指令。
它获取 R0,将其乘以 R1,
然后将结果存储回到 R1 中。
除法指令获取这里的 R1,将其
除以 R0,然后将结果存储回到该位置。
再说一次,我们看到用于访问变量的一、二步骤。
第一步是使一个寄存器指向该位置。
现在,该访问恰好是存储,
因此它要将结果存储回到原来的位置。
总之,需要考虑溢出。
总之,需要考虑它是有符号数还是无符号数。
堆栈非常重要。
我们将在整个课程中使用它。
我们可以将其用于临时存储,
比如我们有一些数据,
我们希望临时存储它,稍后再将其取回。
这是后进先出存储。
换句话说,我可以保存某些数据,然后再将其取回。
它还是编译器生成局部变量的
方法之一,当然,局部
变量也是另一种临时存储。
不过,让我们看看该入栈指令。
堆栈位于 RAM 中。
当我绘制一个堆栈图像时,
我要将零地址放在那里,
将 FFFFFFFC地址放在那里。
在这里的某个位置,我要为堆栈
分配一些空间。
现在,很显然,它必须位于 RAM 中,因为它可重复写入。
然后,我将设置我的堆栈指针,
以指向该位置。
我将定义堆栈指针,以指向
堆栈的顶部 --
我最近,上次入栈的数据。
因此,如果我查看这里的堆栈图像,
该堆栈指针将最初指向堆栈的顶部
元素。
我将在这里暂且假设 R0
最初等于 0,R1 最初等于 1,
R2 最初等于 2。
我将执行这六条指令。
那么,这是第一条指令,就在这里。
它的工作方式是,当我想入栈时,
它将递减四。
这是因为,您应该记得,内存本身
是 8 位可寻址的,但寄存器是 32 位
或四个字节。
因此,为了腾出空间,我必须减四,然后
我将在该位置进行存储。
因此,请记住,我说过 R0 是零,
我要将零存储在该位置。
然后,我执行第二条指令,
它存储一,递减堆栈指针,在该位置
进行存储。
第三条指令,使 R2 入栈。
然后在该位置使 R2 入栈。
因此,在任何给定的时间,堆栈指针
都会指向数据,并且它指向最新的数据,
最后入栈的数据。
因此,堆栈的顶部是最新的数据,最近
入栈的数据。
但是,出栈按照相反的方向发生,
这是出栈。
现在,我要弹出到 R3 中,
因此,这现在也将存储到 R3 中。
第五条指令,弹出 R4。
R4 将获得一,R5 将获得零。
堆栈现在与它的开始状态
实现了平衡。
那么,三个入栈,三个出栈,我在寄存器中
移动了一些数据。
再说一次,入栈指令将递减,然后存储,
而出栈会首先读取,然后递减四。
那么,再说一次,堆栈会非常有用,
当您在计算机上进行调试时,它是您可以
实际看到的东西。
因此,在整个课程中,我们
都将讨论抽象的概念,
它是一种用于处理复杂问题的方法。
那么,具体而言,我们将看到
如何定义和调用函数。
这是一个函数。
它是一种用于简化系统的方法。
因此,如果我有大量的代码,我可以将其置于多个级别中。
这是低级别的代码
而这是高级别代码。
那么,函数 --
这些点是伪操作,实际的指令是
这三个。
因此,当这执行时,我们将具有两个
函数调用。
因此,该函数的分支连接指令
是函数调用,我们可以
在这里看到 BXLR指令是子例程返回。
我们将看到这是怎么工作的。
让我们来执行它。
第一条指令将一放置到 R0 中。
那么,在我的寄存器中,在这里的某个位置,
R0 等于一。
第二条指令是分支连接构造,
分支连接上会发生两件事情。
然后,它要将连接寄存器 -- R14
设置为返回地址,它恰好位于此处。
返回地址是调用函数之后的指令。
那么,这里的指令是调用。
调用函数之后的指令是返回地址,
它插入到连接寄存器中。
然后,它将更改或设置程序计数器,
使其等于函数地址。
程序计数器在这里。
就是这样。
因此,要执行的下一条指令是
该指令,第三条指令。
我们以前看到过它。
它要将 M 的地址提取到 R1 中。
因此,R1 现在将指向此处,现在这是一个变量。
那么,第三条和第四条指令
要获取该存储到M 中的值。
因此,我初始化该全局变量。
但这里有趣的是指令五和分支连接
构造,以及一条非常简单的指令,
BXLR,它基本上会获取连接寄存器
并将其放置到程序计数器中。
但连接寄存器在这里,因此
这是程序计数器到达的位置。
因此,第六条指令将是这一条,它恰好是
另一个子例程调用。
那么,让我们来执行它。
现在连接寄存器已经更改为该指令,
程序计数器已更改为该指令。
然后它将执行该 -- 6、7、8、9、
10, 11, 12, 13, 14, 15.
现在,这恰好是随机数生成器。
这不是一个非常好的随机数生成器,
但是它会返回一个介于0 和 255 之间的数字。
请注意,它使用了R0 作为参数。
它在 R0 中作为输入参数进行传递。
然后,它还将使用R0 作为返回参数。
因此,R0 将包含该介于0 和 255 之间的数字。
但 BXLR 指令,我们在这里关注的指令,
实际上是子例程返回指令。
它获取连接寄存器并将其存储到程序
计数器中。
因此,现在程序计数器也将指向此处。
那么,第 16 条指令将位于此处,
它将存储值,将地址存储到
那一个中。
那么,现在我们使 R1 指向此处。
现在,在第 17 条指令中,第一个
随机数生成器,第一个随机数
将存储在这里。
现在,第 18 条指令是一个非条件分支,
因此,我们在 19 处结束,返回到这里。
那么,这里的重点是,我们将使用函数
来降低复杂性,以重用代码,
并且我们将使用 BL 指令
来调用函数。
我们将使用 BXLR从该子例程返回。
这是有关条件语句的简短介绍。
这里的重点是,需要知道它是无符号数
还是有符号数。
由于我们有一组不同的分支,因此,
基本而言,我们会将一个值存储到
一个寄存器中。
我们将使用比较指令,将其与第二个值
进行比较。
然后,我们将执行条件分支,
如果该条件为真,那么它将进行分支。
那么,这就是我们将实现 if/then 的方式。
再说一次,我们将看到将某个数据
存储到一个寄存器中,将某个数据存储到第二个寄存器中,
然后进行比较。
然后,我们可以比较这两个值。
只要两侧都是无符号数或者
两个值都是有符号数,一切就会正常运行。
我们使用循环来比较指令。
那么,在本例中,我们要“当 G2 大于
G1 时”进行循环,因此我将反复
不断地运行该指令。
有时,我们会将某个操作执行有限次数,
那么,我们可以通过 C 语言或者通过汇编语言来执行该操作。
在本例中,R4将是计数器,
我们将使 R4 递减,直到 R4 等于零。
然后,我们将退出。
这就是我们将执行循环的方式。
总之,我们在这里简要
概述了 Cortex M上的部分指令。
我建议您打开指令集手册,查看
您的 C 代码会生成什么,并看看您
是否还有什么不明白的地方。
在本次讲座中,您需要了解的
可以使您成为更优秀程序员的
重点是:需要考虑溢出,它意味着数字
太大而无法存储;需要考虑掉出,
这会在除法或向右移位上发生,它意味着信息丢失;
确保您了解您的数字是 8 位、16 位
还是 32 位,以及它们是有符号数还是无符号数。
随着我们继续学习,这会非常重要,
因为这些指令专门针对一种类型的
数字运行。
非常感谢,祝您本次实验愉快。
再说一次,在那里稍微深入研究一下,看看您是否不明白
该汇编语言的某些部分。
课程介绍
共计3课时,46分16秒
猜你喜欢
换一换
推荐帖子
- 利尔达MSP430离线烧写器修复一例
- 因为经常会用到利尔达的MSP430烧写器,最近有几个坏了,我研究了下,并已成功修复。分享经验给需要的人。故障现象是,可以装在成功下载文件,但是直接接到板子上不能下载成功。研究发现,接上下载器的主板供上电,就可以下载成功。故障确定在了下载器电源输出部分。拆开后,因为没有原理图,只能顺着线路去研究。发现TI的仿真器和下载器都有软件选择输出电压功能,硬件实现的方式是,通过一个可编程的可变电阻接到一个可调...
- 忘归尘 微控制器 MCU
- DSP+FPGA+ASIC的实时图像处理架构设计
- 随着红外焦平面阵列技术的快速发展,红外成像系统实现了高帧频、高分辨率、高可靠性及微型化,在目标跟踪、智能交通监控中得到了越来越多的应用,并向更加广泛的军事及民用领域扩展。实时红外图像处理系统一般会包括非均匀校正、图像增强、图像分割、区域特征提取、目标检测及跟踪等不同层次的实时图像处理算法,由于图像处理的数据量大,数据处理相关性高,因此实时红外图像处...
- Aguilera DSP 与 ARM 处理器
- 【活动讨论1】DIY低功耗东东
- ddllxxrr 提出利用MSP430的低功耗特性,DIY一个低功耗的小东西,大家有啥想DIY的东西吗?咱们跟帖讨论吧...
- wstt 微控制器 MCU
- ez430 rf2500
- 各位大神 开发ez430 rf2500只需要板子和ivr软件软件就可以了吗? 我下载的ivr几十兆大小 对吗? 请大神们抽空回复下,我完全没入门 呢,所以有这些弱智问题。 顿首。...
- aboutjust 微控制器 MCU