闲谈ARM的汇编指令

发布者:Mingyue1314最新更新时间:2021-03-19 来源: eefocus关键字:ARM  汇编指令  初学者 手机看文章 扫描二维码
随时随地手机看文章

在51单片机为主流的时期,常常会有个问题困扰嵌入式应用的初学者,是先学习汇编语言,还是直接学习C语言。


在51时代,可以毫不犹豫的说,不懂汇编就不是个好的开发者。51指令系统开发与70年代末,因此,相关资料极为详细。而主流的51教科书都无一例外的会从汇编指令表展开教学。


在针对51开发的C语言普及之前,汇编几乎是51开发的唯一手段,加上51单片机资源有限,因此在C语言只能用在扩展了存储器的51单片机系统电路.中或者是增强型(在芯片上增加了存储器等)芯片上。对于资源很少的AT1051、AT2051芯片,除非功能特别简单,否则,用C语言进行开发是不可能的事情,因此,可以说不懂汇编,就不是一个好的开发者。


嵌入式开发进入到ARM芯片时代,先学汇编还是直接学习C语言已经不再是问题了。ARM芯片上的存储资源尤其是RAM比标准51的要大上10倍以上,为C语言开发奠定了基础。在弃繁就简习性的推动下,C语言成了为数不多甚至是唯一的选择。在今天,即使你想学习ARM的汇编也困难重重了。首先是ARM的汇编指令表,几乎没有书籍和资料做专门的介绍。其次,所有开发平台虽然都可以支持汇编(相对C语言,汇编编译器要简单很多,并且是高级语言编译的基础)但都没有做专门介绍,也不提供汇编的例程。因此现在学习汇编要比以前艰难许多。


和C语言比起来,汇编比较繁琐,但它确无法绕开的。许多初学者甚至许多业内“高手”认为C语言可以做到汇编语言能做到的一切。我以为这个不但目前做不到,在可以未来预见的未来也不可能做到,除非计算机在结构上发生重大进步。


现在所有所谓“高级”语言,对CPU来讲都不是“自然”语言,在这些源代码由编译器翻译成CPU可执行的机器语言之前是不可能被CPU执行的。因此,有一种指令系统就必须配备一款专门的编译器,就像微软的PC操作系统和Mac操作系统不同是一个道理。所以,编译器的完成者是必须懂得汇编语言。


ARM公司最成功的思想就是统一了CPU的汇编指令体系,它自己不生产芯片,但它使ARM体系的编译器发挥最大的作用。各个芯片生产公司都使用ARM体系内核,再加上各自擅长的外部设备集成芯片。这样就为各个公司的MCU推广提前铺平了道路,ARM公司也在这种开发系统应用最大化中获得了可观的利益。


即使有了最好的编译器。也并不能使高级语言解决一切问题。这个做PC软件的工程师应该最有体会,因为一旦涉及到底层设备的操作,就需要调用一个叫做“驱动库文件”的东西,而这个东西最核心的代码只能是用汇编程序做的。


在嵌入式开发进入到C语言时代后,芯片生产厂一般都会为芯片上比较复杂的设备如:USB、Ether等设备配上专门的驱动库以便芯片应用者使用。这虽然解决了复杂设备的一些应用问题,但不等于解决了所有问题。做过汇编程序的人都知道,对于一个计算功能的实现,不同的编程者所写的代码一般是不同的,虽然都能完成任务,但有些程序会更好一些。造成这种情况的原因是汇编指令中有很多功能相同但又有些许差别的指令,例如,51单片机的累加器加1这个功能,既可以用“ADD A,#1”来完成,也可以用“INC A”这条指令,就像每个人有自己的习惯用语一样,每个程序员都有自己使用指令的习惯。程序员不用清楚每条汇编指令的含义,照样可以编出很棒的程序,就像作家不用认识每个字照样写出好文章一样。


微处理器技术发展到现在,增加了许多原先没有的操作细节,如增加速度的流水线操作等,这些指令的使用有很高的的条件要求,高级语言编译器是无法将这些细节操作通过编译产生的,各种编译器其实也有自己的“习惯用语”,所以,也不可能用到所有的汇编指令。因此,当高级语言程序需要做复杂操作时,是必须调用“库”文件的。


当我们把这些任务交给“库”来完成后,我们就不能再有另外的选择,无论它是好一点或者差一点。


再者即使对于像GPIO这样简单的设备,在许多情况下我们也希望它们的操作判断越快越好,而能使这些口操作最快的手段,依然是汇编程序。


也许有些人要问了,C(包活其它高级)语言的程序不是经过编译器最后编译成了和汇编语言对应的机器语言吗,最后都是机器语言,怎么会说汇编编的程序快些而C语言的编译过的程序就慢些呢?


这里举一个简单的例子说明。作为项目的完成者,编写程序的人清楚的知道自己要完成的计算是什么规模的,比如要完成一个一百以内的数目运算使用一个字节就够了,因为一个字节里的最大数目是255;完成一万以内的数目运算只需要一个字就够(一个字里的最大数目是65535)。


如果是用汇编编程,程序员直接使用字节或字取数后,编写运算程序即可,不再占用运算需求以外的任何存储资源;但如果使用C语言,情况就不大一样,因为在C语言编程时你首先要确定数据类型,你需要用一个unsigned char a或者 unsigned int a来定义数据类型。如果你把这个C程序编译后所生成的汇编语言拿来看,你就会发现用汇编直接取数的一条指令,在C编译后的过程是先判断类型字节的数字是表示比特、字节、字还是长字,然后四中选一再进行相对应的取数操作。汇编编程直接的一条机器代码(与汇编是一一对应的)用C完成需要10条甚至20条以上的机器代码才能够完成。


所以,汇编程序编写的代码会比包括C语言在内的所有高级语言快得多,也是从硬件角度讲最便宜的选择。那为什么这种多快好省的开发方式会被边缘化呢?这是因为学习汇编需要相应的硬件基础,而且不容易被掌握。从这个角度讲,汇编才是真真的“高级”语言。


C语言的流行得益于芯片性价比的飞速提升,随着MCU的主频和资源的大幅提升,高级语言的硬件消耗越来越便宜,相反程序开发的劳务费用却在不断上升,因此,好懂易用的C语言在各种多用途多样化的产品中占了主导地位。尽管如此,各种高级语言并未能真正能摆脱汇编语言,前面提到的各种驱动“库”文件,就是在各种应用中不能缺少的。因为在真正需要高速操作的地方,是不能依靠高级语言自身去完成的。


所以,嵌入式的研发行业内仍然需要一定数量懂得汇编语言的人,尤其是在高要求又需要自主开发的地方,这也是本文作者写下该文的初衷。


闲话到此,下面就来谈谈ARM的汇编指令,由于ARM内核有多个,并且还在不断的变化,因此,本文只能以相对简单的Cotex M0指令系统作介绍,尽管如此,只要真弄清楚了这些指令的规范和结构,学习其它ARM指令会变得非常容易。熟悉51(或其它任何一种CPU、MCU)汇编指令系统的人,对本文理解会容易很多,对不懂汇编建议找一本有51指令系统介绍的书籍或先资料熟悉一下,然后再读本文。


本文的主要资料是来源于广州周立功单片机发展有限公司的公开资料《LPC1100系列微控制器用户手册(中文版)》的第二十二章“ARM Cortex-M0参考资料”,Cortex-M0 指令表中的指令代码,则是利用现有编译器,使用反汇编原理推导及验证的结果。由于可用的资料和作者能力的限制,文中难免有些存在少许误解和失误,在此先做个免责声明并敬请各位读者谅解。


先回顾一下51指令的数据格式,8051指令系统使用的是标准8位存储器,即每个地址单元有8个比特位。寻址空间则为16个比特位(共64K)。用二进制可以直观的表达为:

地址 对应地址存储数据

0000 0000 0000 0000 bbbb bbbb (注:b=0或者1)

0000 0000 0000 0001 bbbb bbbb

0000 0000 0000 0010 bbbb bbbb

…… …… ……

1111 1111 1111 1111 bbbb bbbb

地址表示使用具体数字是因为地址是常量,每个地址都是明确的,就像一个大旅馆面的房间编号,是固定不动的;数据使用b表示意味着数据是变量,就像旅馆房间一样,今天住这个人,明天住那个人。而编程者就是所有房间的安排者,确定每个地址应该存放什么样的数据。


对按照指令执行命令的CPU来讲,必须有个明确的执行起始点。而且这个起始点有对应的硬件操作端复位键,51是高电平复位,因此,给它的复位端一个高脉冲,它就会从0000 0000 0000 0000这个地址开始执行指令。51最大的地址是二进制1111 1111 1111 1111B,用十六进制表示为0FFFFH,也就是业内人常说的64K。


51是复杂指令集,因此,它的指令按所占地址分为单字节指令,双字节指令和单字节指令。也就是说,如果51的指令即可能只占一个地址,也可能会占两或3个地址,依照所使用的指令占用字节数的不同而不一样。


另外,为了使硬件效率最大化,51指令从00H-0FFH的所有256个数据都是指令。顺便提一下,0EA也是指令,虽然该指令在标准51中是双字节空指令,但这只不过是为了给今后的扩展预留,有些品牌的扩展51核用该指令扩展出4字节指令。


而ARM是使用的精简指令集,精简指令有2个特点,一是指令数目少,其指令数据位在理论上只占5个比特;二是它按每个的地址只占一条指令的规则安排存储器。下面以Cotex M0(一下简称为M0)指令系统为例,看看ARM指令的特点。


Cotex M0是16位指令系统,但由于它是32位的运算器,而且寻址空间也是32位,因此,把它说成是32位机也能说的过去。


依照前面的二进制表示法,M0的指令格式可表示为如下方式:

地址 对应地址存储数据

0000 0000 0000 0000 0000 0000 0000 0000 bbbb bbbb bbbb bbbb

0000 0000 0000 0000 0000 0000 0000 0001 bbbb bbbb bbbb bbbb

0000 0000 0000 0000 0000 0000 0000 0010 bbbb bbbb bbbb bbbb

…… …… ……

1111 1111 1111 1111 1111 1111 1111 1111 bbbb bbbb bbbb bbbb

和51的64K个地址相比,32位ARM的地址是51的64K倍数,就目前的嵌入式应用来讲,是不需要使用如此大的存储空间的。但就像大多数51芯片并不用满64K空间一样,大多数ARM芯片只用其空间的一小部分。


回到具体指令上看,M0是精简指令集,也就是说每条指令只能占一个地址,但每个地址有2个字节的容量(51每个地址只占一个地址容量)。


现在以51和M0指令为例,比较一下复杂指令集和精简指令集的数据格式。先看51指令的3中格式:

单字节指令:占一个地址,格式为“指令本身”。没有操作数,功能是寄存器之间的数据传递,寄存器左、右移动一位,加一等。例句:“MOV A,Rn”;

双字节指令:占2个地址,格式为“指令+八位操作数”。例句:“MOV A,#DATA”;

三字节指令:占3个地址,格式为“指令+8位操作数+8位操作数”或“指令+16位操作数”。例句:“MOV SBUF,B”、“MOV DPTR,#DATA(16位)”。


相比51的复杂指令集,M0的指令格式看起很简单,即:cccc cddd dddd dddd。其中c表示伪指令,d则为数据,前面5个比特位是精简指令集的标准指令位,共32条指令,而后面有数据位是11个,加在一起是16个比特位。精简指令集明确规定每个地址位置只放1条指令。


虽然精简指令集看起来好像很简单,其实真正了解的话并不比复杂指令集少多少而且不大容易理解,在存储器的使用上也不会更节约。2者性能其实差不太多,只是在产业联盟上存在竞争关系,有竞争对用户总是有利。


下面来看看为什么精简指令集的指令不少,从格式上看,精简指令集只有5个指令比特位,理论上只有32条指令。但由于它的每条指令必须占据一个地址位置,所以不能像复杂指令集中的单字节指令那样节约数据位(参见51的单指令)。比如M0中每个地址为占16个比特,如果是要实现一个空造作(NOP),51只需要8个比特位(一个字节)而M0则需要16个比特位,所以为避免浪费精简指令**尽可能的利用数据位的空余比特,形成许多子指令,即在不需使用数据位时会在32条指令的下面扩展出多条指令,最终的结果是精简指令集的指令数目远大于32条。


其次,因为软件应用已经习惯于以字节单位,所以顺应应用实际也必须规范数据格式。M0指令可以进行8位,16位和32位运算,而它的数据位是11位,只能满足8位取数。因此,要进行16位和32位的取数必须使指令超出一个地址位,事实上精简指令集也不是绝对的每条指令只占一个地址位置,它还是有多个一个以上地址位置指令存在的。


附件是Cortex-M0指令表,看过指令表后你就可以发现,M0的通用寄存器里面并没有包含R8至R12的高位寄存器,因为指令表中没有包含这几个寄存器如何寻址。类似的许多问题,都可以从指令表中找到。


关键字:ARM  汇编指令  初学者 引用地址:闲谈ARM的汇编指令

上一篇:基于GPS和CDMA的物流车辆监控终端的设计
下一篇:ARM技压群雄——发挥ARM Cortex-M3和M4微控制

推荐阅读最新更新时间:2024-11-10 12:10

ARM CEO:ARM被英伟达收购要好于独立上市
7月5日消息,据国外媒体报道,近日,芯片设计公司ARM首席执行官(CEO)西蒙•西格斯(Simon Segars)表示,该公司被英伟达收购要好于独立上市。    西格斯表示:“与英伟达合并将给我们带来所需的规模、资源和灵活性,从而使未来的机会最大化。”    2020年9月份,软银集团和英伟达宣布,双方已达成确定性协议。根据协议,软银将把ARM出售给英伟达,交易价值为400亿美元。    对于这笔交易,ARM联合创始人赫尔曼•豪瑟(Hermann Hauser)在去年9月中旬表示,这是一场灾难,将摧毁ARM的商业模式,应该予以阻止。    此外,这笔交易还遭到包括英特尔、高通等多家芯片供应商以及特斯拉在内的硅谷多家科技巨头的反对。
[半导体设计/制造]
Xilinx RFSoC凭借先进技术的最佳运用荣膺ARM TechCon创新奖
赛灵思公司(Xilinx, Inc.,(NASDAQ:XLNX))今天宣布,其Zynq® UltraScale+™ RFSoC产品线凭借对先进技术的最佳运用在2017年ARM TechCon大会上荣膺创新大奖。Zynq UltraScale+ RFSoC将直接RF数据转换器与FPGA逻辑和多核多处理ARM®子系统完美集成在一起,从而能为无线、有线电视网络接入、测试测量、雷达等高性能RF应用提供完整的RF信号链。基于分立式组件的传统实现方案需要在功能、成本、功耗之间进行取舍平衡,而Zynq UltraScale+ RFSoC则不受这种约束,因为该系列采用先进技术在同一颗芯片上完美集成了模拟和数字功能。单芯片上模拟和数字功能的集成,不
[半导体设计/制造]
Xilinx RFSoC凭借先进技术的最佳运用荣膺<font color='red'>ARM</font> TechCon创新奖
基于ARM9的LCD程序编写
人机交互是嵌入式系统必须具有的功能。比较简单的人机交互有按键、LED、蜂鸣器,稍微 复杂的有7 段数码管和点阵。但如今这些都不能满足人们的需求了,所以又出现了LCD 和 触摸屏技术。s3c2440 具有LCD 和触摸屏接口,可以很好的连接LCD 和触摸屏。这篇文章 主要介绍TFT 型LCD 的用法。 要想正确使用LCD,必须注意两点:1、时序;2、显示缓存区。 1、时序 LCD 一般需要三个时序信号:VSYNC、HSYNC 和VCLK。VSYNC 是垂直同步信号,在每 进行一个帧(即一个屏)的扫描之前,该信号就有效一次,由该信号可以确定LCD 的场频, 即每秒屏幕刷新的次数(单位Hz)。HSYNC 是水平同步信号,在每进行一行的扫描
[单片机]
ARM WIFI AP 模式 使用 iptables nat 转发 通过 LAN 网线上网
编译内核,支持 iptables 和 forward 和 nat。 编译内核,使用新内核启动arm 开发板。 编译内核支持 iptables - Networking support (NET ) - Networking options - Network packet filtering framework (Netfilter) (NETFILTER ) - IP: Netfilter Configuration 本开发板是通过 LAN 有线连接到 路由器上。路由器网段为 192.168.1.1 首先要配置 LAN 的网关,DNS 等 ,因为之前已经配置好 dhcp 如果你不是使用 NFS
[单片机]
<font color='red'>ARM</font> WIFI AP 模式 使用 iptables nat 转发 通过 LAN 网线上网
一文教你如何区别ARM Cortex系列处理器
众所周知,英国的ARM公司是嵌入式微处理器世界当中的佼佼者。ARM一直以来都是自己研发微处理器内核架构,然后将这些架构的知识产权授权给各个芯片厂商,精简的CPU架构,高效的处理能力以及成功的商业模式让ARM公司获得了巨大的成功,使它迅速占据了32位嵌入式微处理器的大部分市场份额。 目前,随着对嵌入式系统的要求越来越高,作为其核心的嵌入式微处理器的综合性能也受到日益严峻的考验,现在一个高端智能手机的处理能力几乎可以和几年前的笔记本电脑相当。为了迎合市场的需求,ARM公司也在加紧研发他们最新的 ARM架构,Cortex系列就是这样的产品。那么我们今天就不妨好好了解一下ARM Cortex系列处理器知识点汇总。 ARM Cort
[单片机]
一文教你如何区别<font color='red'>ARM</font> Cortex系列处理器
Arm 2022年的全面计算战略都带来了哪些创新?
2019 年,Arm推出了全面计算(Total Compute)战略,采用整体、以解决方案为中心的 SoC 设计方法。通过超越单个 IP 元素来设计和优化系统,以创建用例驱动的解决方案,为下一个十年不同行业的计算创新提供动力。 2021年,伴随着Armv9指令集的诞生,以及Cortex-X2/A710/A510等IP发布,标志着Arm首次进入了全面计算时代,并标志着64位计算时代的全面到来。 时隔一年,Arm在2022年继续更新了全面计算解决方案,并作出了多项重要创新。其中包括全新旗舰产品 Immortalis GPU,实现了基于硬件的光线追踪功能,为手游体验带来了显著增强。此外,旗舰型CPU Cortex-X3的性能也得
[半导体设计/制造]
基于Android的ARM汇编语言系列之六:NEON指令集与VFP指令集
章节列表 之一:ARM汇编语言开篇 之二:C/C++程序生成ARM汇编程序的过程分析 之三:ARM汇编语言程序结构 之四:ARM处理器的寻址方式 之五:ARM指令集与Thumb指令集 之六:NEON指令集与VFP指令集 NEON指令集与VFP指令集是ARM指令集的扩展,多用于多媒体编程和浮点运算。 一 Android平台使用NEON指令集与VFP指令集 Android NDK从r3版本开始也添加了对NEON指令集与VFP指令集的支持。使用方法如下所示: 1 运行时检测处理器是否支持NEON指令集与VFP指令集 Android NDK提供了一个cpufeatures的库来让开发者在运行时检测处理器是否支持NE
[单片机]
基于arm7的(lpc2388)flash的读写操作
开始工作不久就碰到一个flash读写的问题。是一块lpc2388的芯片(arm7), 开始总是抱着一arm11的flash读写的方式去看数据手册。看了好长时间都没有一个很好的解决方发。 后来我在keil的库文件中找到:flash的写入方式。如下://C:\Keil\ARM\Flash\LPC2888\FlashPrg.c /* * Program Page in Flash Memory * Parameter: adr: Page Start Address * sz: Page Size * buf: Page Data * Return Value: 0
[单片机]
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved