找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 2095|回复: 2
收起左侧

汇编之51单片机寻址原理详解(二)

[复制链接]
ID:266429 发表于 2019-3-12 09:17 | 显示全部楼层 |阅读模式
我想把第一个写汇编教材的人痛扁一顿先。
在汇编语言中,寻址方式是我们学习的重点之一,也是难点,让人很容易犯迷糊。个人觉得吧,这个犯迷糊的原因,不在于你,而在于,教材中有关寻址方式的一套说法,本身就很迷糊。下面,我们就寻址方式这一事,探究一下。
先说两点很基础的概念:一,“寻址”的方式本身就只有两大类:一是将一个具体的地址值给处理器,一个是在机器指令码中已经暗含了地址(寄存器);二,寻址,不应只如教材中所说的只针对源操作数(源数据),也应包括目的操作数(目的地)。教材中说的分类及解释,反正本人觉得很那个。
提示一下,上一个贴子,是以举例的形式,建立一些概念性的东西。
言归正传,下面我们展开了说:
一、“寻址”的内涵及应该做的前期工作
首先,我们弄清楚“寻址”这个概念的内涵,就是说要把一个源数据存放在存储器中的地址,告诉处理器,这个就是寻址。万变不离其宗,我们只要牢记,所谓“寻址”只是把地址告诉别人,至于将告诉别人地址的方式称乎成直接寻址、间接寻址、变址寻址之类的还是称乎成其它什么的,我们可以不管它。
我们再往前一步:要告诉别人这个地址,首先你要知道这个地址,也就是说,你要“获得”这个地址。
再往前推,我们要把这个数据(源数据)送出去,说明这个数据已经存在某个单元中了,那么,为了“获得”这个地址,我们就要弄明白,当初这个数据存进去的时候,它的地址是多少?是怎么确定的?
还有一点,教材中所谓的寻址的对象,指的是对源数据(源操作数)的地址的寻找,而不是目的操作数,目的操作数的地址,都是由程序员在该条程序中直接、精准地给出了的。
二、源数据存入时的地址选定方式
首先,所有源数据的存入,都是由程序员在程序中来规划的,但是,51机芯片本身在这方面有些原则和规定,所以,我们至少应从这两方面来了解说明。
另一方面,所有源数据存入时的地址,都是由程序员来选定的,但写入时间分为两种情况,一种是在程序运行前就已写入,这个情况指的是程序存储器中的数据;另一种情况是在程序运行中写入,这个指的是数据存储器中的数据,也就是中间数据和结果数据。
(一)程序存储器中的数据
51机程序存储器属两字节地址型,即每个单元的地址为16位二进制数。
1、紧跟在机器指令码后面的单元中
也即数据存在该机器指令码之后的一系列单元中,有多少字节数据就占用多少个单元。这里面又分为三种:一字节立即数据,如MOV Rn#data,二字节立即数据,一组数据的表数据。
属于相对地址,基地址为该条指令的机器指令码所在单元的地址。
2、另划存储区的表数据
这个就是在存储区,由程序员指定一个独立的绝对起始地址,把一组数据顺序写进去。我们常见的ORG伪指令,就是来指定绝对起始地址的。
这个属于绝对地址,程序员在ORG中给出了一个绝对地址数值。
(二)数据存储器中的数据
51机数据存储器(内部256B)属单字节地址型,即每个单元的地址为8位二进制数。
这个是在程序执行中才会发生数据的存入,其存储单元的地址,也是由程序员规划的,可以在源程序中直接指出,也可以在运行过程中通过计算得出。
源程序中直接指出地址的方式,也有几种,一种是将其地址值写在源程序中(烧写后存在程序存储器中);另一种,就是51机的指令规定了,它在机器指令码中直接指向了存储单元,即前面所说的机器指令码暗含地址,这个在51机的设计中,只针对部分寄存器,想了解哪些寄存器有这种设计,看机器指令对照表就是了。
三、如何获得源数据的地址
要想让处理器找到地址,程序员必须让处理先获得地址。其实,根据源数据存入时地址的选定方式,我们很容易想到如何获得其地址。
这个在后面结合起来讲。
四、地址值放在哪并如何告诉处理器
处理器根据地址值才能找到源数据,但是,这个地址值,得先放在一个地方,让处理器去取,所以,你得将地址值放在一个地方,并将这个地方告诉处理器。
(一)程序存储器中的源数据的地址值(十六位地址值)
1、跟在机器指令码后面的单个或两个数据
这个,机器指令码自己就知道地址,也就是说,其源数据单元地址指向已在机器指令码中明确,就不劳你另外费心了。这个属于立即寻址。
MOV A#data,这个是单个数据,该指令的机器指令码为74H,这个74H自己就知道要取的数据就在自己的屁股后面。
MOV DPTR#data16,这个是两个数据(两字节)。
2、跟在机器指令码后面的表数据
这个地址的获得,是以该机器指令码的PC值作为基地址值,A中的值作为要取的源数据的顺序值(偏离量),两者相加,即为绝对地址值。这个绝对地址值放在什么地方我不知道(按51机设计者的尿性,多半在A中),这个也不重要,因为处理器得到这个值后直接就去取数据了,不需要你再另加指令。
汇编指令:MOVC A@A+PC,查表指令之一
操作时,源数据的顺序值,必须先送入A中,这个,就得用到其它指令。下面第3条也是一样。
3、绝对地址表数据
这个地址的获得,是以DPTR(前面ORG中给出的起始绝对地址值)中的值为基地址值,以A中的值作为要取用的源数据的顺序值(偏移量),两者相加,即为绝对地址。其它情况同上。这个属于有的书上所说的变址寻址。
汇编指令:MOVC A@A+DPTR,查表指令之二。
PS1:说明一下,51机的机器代码指令集中,针对程序存储器只设计了这三种地址获得的方式,而且,对于程序存储器中的表数据,也是只设计了传给A,想传到其它地方?对不起,你只能先传给A后再说。为什么这样设计?一个是因为8位机最多只能有256条机器指令,不够用啊;二个是,你觉得这样设计合理么?(这部分涉及到51机数据传输的原理,在这里稍微提一下让人有个概念)
PS2:查表指令用起来真的很麻烦,可以考虑将小量的并常用的表数据,在程序开始时复制到数据存储器中,这样运行速度可能要快些。
(二)数据存储器中源数据的地址值(八位地址值)
程序存储器中的原数据,属于永久数据,其地址也是永久的,哪怕是程序重启后也不会改变。
但数据存储器中的源数据不是这样的,数据存储器的特点之一就是可以复用,程序员在编程时,对同一单元可以不断更改其用途,也可以在整个程序运行期内,指定部分单元存入固定用途(固定值)的数据。
所以,数据存储器中的源数据,其实都是程序运行过程中的中间数据或结果。其地址值,都是由程序员在编程时确定的,也是或者直接指定,或者通过计算得出。
数据存储器中的源数据的地址值,在传输开始前,放在以下几种位置:
1、程序存储器中
这个属于直接指定类,也就是程序员在源程序中直接给出源数据的单元地址(绝对地址),其地址值则放在机器指令码之后的一个程序存储器单元中,如MOV Adirect,机器代码为“E5 直接地址”,这个就是所谓的直接寻址,这种情况是目的地址已在机器指令码中指出,如果要分个类,可以称为寄存器对数据存储器的直接寻址。
还有一种,就是MOV direct,direct,这个也是直接寻址,三字节指令,源地址与目的地址都是直接给出地址值,其机器代码为“85 direct direct”,也可以说直接地址到直接地址类的直接寻址。
2、工作寄存器中
源数据的地址值存放在工作寄存器中,处理器将工作寄存器中的值当作源数据的地址值来取数据。如MOV A@Ri,这个就属于间接寻址,这个例子属于单字节指令,源地址和目的地址均在机器指令码中指出。需要说明一下的是,工作寄存器的地址值不需另外给出,它一定已经包括在机器指令码中了。
这种方式一般用于需用具体数值来表示源数据地址值、但是其地址值并未在程序存储器中给出的情况,对于计算出来的地址值,必须采用这种方式,这个跟程序存储器中的查表法有点不一样,计算得出的地址值一定要先放入寄存器中,而不是该指令在得出地址值后直接就去取数据了。
其实这种方式跟直接寻址差不多一回事,都是要有具体的地址值才能找到源数据,区别在于一个的地址值在程序存储器中,另一个在Ri中。
这里注意一点,这个地址值只能送入R0R1中,为什么不能送入其它R中?因为51机的设计者没有这样设计。为什么要这样设计?见前所述。
千万注意:对于具有256B(不计入SFR)容量的数据存储器的51机,128B值以上的地址如果采用直接寻址方式,则它会在SFR中找数据,如果采用间接寻址方式,则它会在用户数据区找数据。也就是说,对于SFR的地址值,只能在程序存储器中给出。
PS:个人觉得吧,SFR区也不是完全不能作为用户数据区,比如吧,对于电路上空置的端口,用了也不会有什么后果吧?要知道,它们也是可以位寻址的,更是可以直接寻址的。至于这样做有没有意义?这样说吧,至少思路有意义。
3、机器指令码直接指定
也就是说机器指令码它自己就知道源数据在哪,也就是书上所说的寄存器寻址,如MOV directA,这条语句具体应用时的机器代码是0F5H direct,两字节指令,这里面的0F5H是机器指令码,它已经明确了源数据在A中(这个是由51机的设计者设计成这样的)。
这种情况,只适用于部分寄存器,这部分包括ARnRiDPTR,还有半个PC,一个位寻址C,其它的寄存器没有设计这个功能(不会又问为什么没设计吧),包括把其当作源地址以及当作目的地址。你只要记住只有这几个有所谓的寄存器寻址功能,不管是把它们当全源地址还是目的地址,你就能很熟练地运用了。
PS1:如果数据传送的两头都是寄存器,51机设计者还给设计了一部分直通车,也就是在机器指令码中直接指明了两头是谁,也就是单字节指令,如MOV AR0,它直接一条机器指令码0E8,就把数据从R0传输到了A
PS2:从前面的说明可以看出,所谓“寄存器寻址”的说法,并不恰当,准确的说法,应该是“机器指令码定址寻址”,定址包括对源地址和目的地址(再重复一遍)。
五、说明
以上所说,均只针对片内的存储器。
每一条机器指令码,对应着一套实现该指令功能的硬件逻辑电路。
汇编语言并不能说难,至少,对于目前一些教材中所说的实例,编程起来不会比C复杂。
汇编程序员的大量且复杂的工作,应该是对存储器的规划。小程序还好说,大程序,真的是要好好规划,不然的话,要么存储器不够用,要么数据发生冲突而无法达到目的。
题外PS:写得蛮伤神,这些东西跟教材上的思路不一样,也不知说清楚没,更担心有什么说错了的害人,盼大虾指正。

评分

参与人数 1黑币 +100 收起 理由
admin + 100 共享资料的黑币奖励!

查看全部评分

回复

使用道具 举报

ID:266429 发表于 2019-3-18 08:23 | 显示全部楼层
    光看汇编,有时容易让人糊涂,想要了解清楚,得结合机器语言。
    “MOV 30,P0”与“MOV 30,A”,源数据寻址都是对寄存器寻址,很容易让人认为这两条都是寄存器寻址方式,实际不是,前一条是3字节指令,后一条是2字字指令,前一条翻译成机器代码,P0会译成P0的地址值80H,而后一条中的A则翻译到机器指令码中去了。
回复

使用道具 举报

ID:266429 发表于 2019-3-21 11:17 | 显示全部楼层
    有的人说P0之类的为什么写成P0,是英特尔公司规定的。这个说法是有问题的,它其实并不是芯片层面的,芯片只认识二进制数。它是软件层面的,是在编译工具中这样规定的,你可以在编译工具中改成你自己喜欢的称号。或者你很牛你喜欢手工编译,那你写成任意中文就一点问题都没有了。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表