一起学汇编

[复制链接]

4

主题

93

帖子

3205

积分

超级月卡

Rank: 7Rank: 7Rank: 7

积分
3205
发表于 2020-5-15 21:53:30 | 显示全部楼层 |阅读模式
本帖最后由 why 于 2020-8-16 21:00 编辑

小白自学,做个笔记吧。太难了,都是些小白问题也不好意思去问大神们,只能自己折腾。怕又坚持不住做个笔记约束一下自己,嗯!其实以前看了几页,从开始到放弃都云里雾里得!
3个月左右整本书看完,当然什么都感觉没学会。越往后越无法理解,再加上8086cpu实在太老,实验环境都无法搭建成功,后边书上的案例都无法编译出书本上将的结果。最后一个课程设计我们先留着等学完c语言再回头来学一遍汇编解决没有解决的问题。
汇编主要在于寻址,这是我个人理解的。等我们学完c回来重新整理一遍汇编!

看得书是清华大学出版社王爽编著得汇编语言(第3版)
只想说一句太难了!


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x

回复

使用道具 举报

4

主题

93

帖子

3205

积分

超级月卡

Rank: 7Rank: 7Rank: 7

积分
3205
 楼主| 发表于 2020-5-15 22:47:06 | 显示全部楼层
本帖最后由 why 于 2020-6-9 18:15 编辑

我又看了几章了,好多问题还是搞不懂,我将把每章发现得问题和理解得问题都写下来,这东西真是太难了,这不是毅力得问题!
汇编是直接在硬件之上得工作语言,编程课程得研究重点是如何利用硬件系统得编程结构和指令集有效灵活地控制系统进行工作。(解释:计算机主要由硬件和软件组成,硬件作为软件得载体,软件作为控制硬件完成任务,我们人类和计算机交流就必须要会计算机语言。好比美国人是计算机,我们想要跟他们交流那就要会英语才能进行沟通,机器语言就相当于跟美国人交流说得英语一样。由于计算机得硬件只能识别0和1,对于复杂得工程人类再跟计算机交流难度非常大,所以为了方便人类更好得理解机器语言各种编程语言诞生,汇编语言又是最早期最接近机器语言得存在。编程语言就相当于一个中间介质般得存在,比如跟美国人交流咱不会英语难度相当大,现在得情况是我们可以用翻译器直接把想说的话先翻译了给他看,这样他就能理解我们想干嘛了,在编程语言和机器语言中间也同样有个翻译器,我们管它叫编辑器!)
储存器:cpu是计算机的核心部件,它控制整个计算机的运行并进行计算。要想让一个cpu工作,就必须向它提供指令和数据,指令和数据在存储器中存放,也就是平时说的内存!
指令和数据是应用上的概念,在内存和磁盘上,指令和数据是没有任何区别的,都是二进制形式存信息。cpu在工作的时候把有的信息看做数据有的看作指令,为同样的信息赋予了不同的意义。就像围棋的棋子,不在棋盘上的时候都一样没有差别,在棋盘中对弈的时候就有了不同意义!
二进制:机器只能判断高低电平,所以只能出现两种情况0和1,和我们日常使用的10进制没有差距的,只是二进制我们不常用。
储存单元:内存被划分成若干个储存单元,比如一个小区是内存的话,那么它里边就有很多个单元。每个单元从0开始,你们小区有128个单元的话,那么就相当于这个内存是从0-127个储存单元。
那么一个储存单元能储存多少信息呢?我们知道电子计算机的最小储存单位是bit(比特),也就是一个二进制位。8个bit组成一个Byte,也就是一个字节。微型机存储器的储存单元可以存储一个Byte,即8个二进制位,一个储存器有128个单元,它就可以存储128个Byte。这个概念比较难理解,我们这样来理解一下:你们小区有128个单元,最小的单位肯定是一套房,然后几套房组成一个楼层,几个楼层组成一个单元。假设你们小区128个单元,每个单元都只有1层,每层8户。那么你家的房子就相当于一个二进制位bit(比特),你们同楼层8户组成了一个楼层相当于一个字节,正好你们小区就是128个单元128字节!这个概念非常复杂,但必须要理解了,要不然后边就两眼一抹黑了。
明天该1.7节,我头大了不行了不行了
回复

使用道具 举报

4

主题

93

帖子

3205

积分

超级月卡

Rank: 7Rank: 7Rank: 7

积分
3205
 楼主| 发表于 2020-5-16 22:37:36 | 显示全部楼层
本帖最后由 why 于 2020-6-9 18:29 编辑

昨天说了位.字节的关系,这个逻辑比较抽象,不好理解只能自己慢慢多理解透彻,要不然后边就给自己绕进去了,今天接着1.7做记录吧。
cpu要从内存中读取数据,首先要制定储存单元的地址,也就是说要先确定它要读取那一个储存单元中的数据,就像我要去你家首先要确定一条路到你家,你家的位置就是储存单元地址,这条路就是后边要说的总线。
另外在一台微机中不只有储存器这一种器件,就像你们小区128个单元,肯定不至你们一家一样。cpu要读写数据时还要指明要向那一个器件进行操作,进行那种操作,是从中读取数据还是向里边写入数据。
cpu要想进行数据读写必须要和其他硬件进行以下3类信息交换,也就是信息传递:首先明确储存单元的地址,其次硬件的选取并确定是读取还是写入数据的命令,再次才是读取或者写入数据的操作。
你对象要去你家,那么首先要明确知道你家的具体位置,这就是明确储存单元地址;要去你家说明已经选取了一个“去”的目的,他不是要离开你家,这就是类似于发出读取写入的命令,由于cpu有明确的指令集每个总线区间对应一个储存单元地址,所以有别于人类先明确目的再寻找解决方法;最后就是执行去你家这个命令,当然这个命令是你对象大脑给他传达的。那么去你家总要选一条路吧,这条路就是总线。在计算机中专门有链接cpu和其他芯片的导线,统称位总线。总线从物理上来讲,就是一根一根导线的合集,根据传送信息的不同,总线从逻辑上分为3类,地址总线.控制总线和数据总线。你家门前有很多条路,很多条路构成一个庞大的公路网,就相当于地址总线一样,每条路都可以去一个对应的地点,比如去超市的路和去图书馆的路他是相反方向并且无法顺路的,这就出现了每条路对应的地址不一样功能用途不一样,当然现实中大部分就算绕路也能到达目的地,电脑没人脑这么智能,三类总线分工合作各司其事互不相干。

我们来看看cpu是怎么实现数据读取的
1.cpu先通过地址总线将地址信息3发出(注意看图,内存中的每个地址空间永远按顺序排列并且对应地址总线)这里找到储存单元地址对应的3为08
2.cpu确定读取还是写入,通过控制总线发出内存读取命令
3.现在就可以将储存单元地址3中对应的数据08送入cpu了
一个完整的交换遵循这3类交换,3条总线都有参与工作,同理向3号单元写入数据也是一样的操作步骤。
我们发现这一整个交换好像控制总线这一步缺点什么,控制总线怎么发出这个读写的命令?
要让一个计算机处理工作,我们应该向他输入一个能驱动他工作的指令,这条指令还得让机器能认识,机器只能识别二进制数据所以在上面例子读取3号单元的数据我们这样写机器就能工作了:
机器码(机器能识别的语言)1010 001 0000 0001 1000 0000(含义:从3号单元读取数据送入寄存器ax)
cpu看到这一连串的0和1它就可以完成上诉的读写工作了,可问题是机器认识了我们不认识呀,反正单个0和1我都认识,这么一组合还真就有难度了,天知道这代表的啥。这时候汇编的价值就提现出来了,我们用汇编指令来翻译以下这一串0和1
机    器      码:1010 001 0000 0001 1000 0000
对应汇编指令:mov ax,[3]
含             义:传送3号单元的内容入ax
简单了很多也更容易我们读写记忆了,这就是汇编!
明天再学三类总线吧。头大的厉害

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

4

主题

93

帖子

3205

积分

超级月卡

Rank: 7Rank: 7Rank: 7

积分
3205
 楼主| 发表于 2020-5-18 21:41:43 | 显示全部楼层
本帖最后由 why 于 2020-6-9 18:25 编辑

昨天有点事,今天接着总线学习了。
现在我们知道,cpu是通过地址总线来指定储存单元的。可见地址总线上能传送多少个不同的信息,cpu就可以对多少个储存单元进行寻址。
一个10根地址总线的cpu,那么它的寻址能力应该是2的10次方,下图我们看到1跟总线只能传送一个数字(实际是二进制数字,0和1代表的是两种状态,二进制逢2进1位。我们这样来理解一下,十进制中一个10位数的最小数0最大数是10个9,用到二进制中来最小数也是0,最大数是10个1,二进制的10个1换算成十进制是1023,总共是2的10次方1024个数字。如果是12根地址总线那么就是12个1,换算成二进制就是4095,共2的12次方4096个数字。计算机只能识别二进制,换算成十进制是方便我们记忆书写。)

一个cpu有N根地址总线,我们就可以说这个cpu的地址总线宽度为N,这样我们就能算出来一台计算机有N根地址线那么寻址能力就是2的N次方,地址总线宽度越大寻址能力越大寻址范围越大,地址总线决定了cpu的寻址能力。


cpu与内存或其他硬件之间的数据传送通过数据总线来进行的,数据总线的宽度决定了cpu和硬件间的数据传送速度,8根数据总线一次可以传送8个二进制数据(前边说了8个二进制为一个字节,也就是8根数据总线一次可以传送一个字节。)
8088cpu的数据总线宽度为8,8086cpu的数据总线宽度为16,(地址总线寻址是2的n次方,数据总线是有多少根线传送多少数据,这两个不能混淆)下面两个图分别介绍8088和8086cpu写入同一个数据的情况

8086有16根数据线,一次可以传送16位数据,16位数据正好是4个字符,所以可以一次传送完89D8,而8088只有8根数据总线,要分两次才能传送完

cpu对外部硬件的控制是通过控制总线来进行的,在这里控制总线是个总称,控制总线是一些不同的控制线的集合,有多少根控制总线就意味着cpu提供了对外部硬件有多少种控制,所以控制总线的宽度决定了cpu对外部硬件的控制能力,前面所讲的内存读写命令是由几根控制线综合发出,其中有一根为“读信号输出”的控制线负责由cpu向外传送读信号,cpu向该控制线上输出低电平表示要读取数据,由一根为“写信号输出”的控制线则负责传送写信号。
一般学汇编要求至少熟悉一门高级语言,由于我不懂任何高级语言,所以很多概念只能自己理解。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

4

主题

93

帖子

3205

积分

超级月卡

Rank: 7Rank: 7Rank: 7

积分
3205
 楼主| 发表于 2020-5-18 22:33:16 | 显示全部楼层
本帖最后由 why 于 2020-6-9 18:29 编辑

小结
1,汇编指令是机器指令的助记符,同机器指令一一对应,(这里应该是指同一架构吧)
2,每一种cpu都有自己的汇编指令集
3,cpu可以直接使用的信息在存储器中存放
4,在存储器中指令和数据是没有区别的,都是二进制信息
5,存储单元从0开始编号
6,一个存储单元可以存储8个bit,即8为二进制数
7,1Byte=8bit  1KB=1024B  1MB=1024KB 1GB=1024MB
8,每一个cpu芯片都有许多管脚,这些管脚和总线相连。也可以说这些管脚引出总线,一个cpu可以引出3种总线的宽度标志这个cpu的不同方面的性能:
     地址总线的宽度决定了cpu的寻址能力
     数据总线的宽度决定了cpu与其他硬件进行数据传送时的一次数据传送量
     控制总线的宽度决定了cpu对系统中其他硬件的控制能力


检测点
1,1个cpu的寻址能力为8KB,那么它的地址总线的宽度为_____。
     解答:先把KB换算成字节,8KB*1024=8192B。N根地址总线的寻址能力为8192B,开方得出13
2,1KB的存储器有_____个存储单元,存储单元的编号从_____到____
     解答:KB换算成字节,1KB*1024=1024个存储单元,存储器编号从0到1023
3,1KB的存储器可以存储____个bit,____个Byte
     解答:根据上一题知道,1KB的存储器有1024个储存单元,一个存储单元就是一字节,故1KB的存储器可以存储1024*8个bit,1024个Byte
4,1GB.1MB.1KB分别是______Byte
   解答:1GB=1MB*1024=1024KB*1024=1024B*1024*1024=1073741824Byte
            1MB=1KB*1024=1024B*1024=1048576Byte
            1KB=1Byte*1024=1024Byte
5,8080.8088.80286.80386的地址总线的宽度分别是16根,20根,24根,32根。则它们的寻址能力分别是__KB,___MB,___MB,__GB
   解答:寻址能力=2的N次方
            8080寻址能力=2的16次方=65536Byte=64KB
            8088寻址能力=2的20次方=1048576Byte=1024KB=1M
            80286寻址能力=2的24次方=16777216Byte=16386KB=16M
            80386寻址能力=2的32次方=4294967296Byte=4194304KB=4096M=4GB
6,8080.8088.8086.80286.80386的数据总线的宽度分别是8根,8根,16根,16根,32根。则它们一次可以传送的数据为__B,___B,___B,__B,__B
   解答:每8根数据总线可以传送一个8位二进制数据,8位二进制数据是一个字节(8bit=1Byte)故分别为1B,1B,2B,2B,4B
7,从内存中读取1024字节数据,8086至少要读___次,80386至少要读__次
   解答:8086有16根数据总线,每次可以传送2个字节,1024/2=512次
             80386有32根数据总线,每次可以传送4个字节,1024/4=256次
8,在存储器中数据和程序是以___形式存在
   解答:计算机只能识别0和1,故在存储器中数据和程序都是以二进制形式存在
脑袋大的不行了,明天继续吧
回复

使用道具 举报

4

主题

93

帖子

3205

积分

超级月卡

Rank: 7Rank: 7Rank: 7

积分
3205
 楼主| 发表于 2020-5-19 23:56:29 | 显示全部楼层
本帖最后由 why 于 2020-6-9 18:40 编辑

什么是内存地址空间呢?前边实际上说过了,一个cpu的地址总线宽度为10,那么可以寻址1024个内存单元,这1024个可寻到的内存单元就构成这个cpu的内存地址空间。相当于现实中你在一个小区能实际看到1024套房,那么这些房就是内存空间,这个和昨天的检测点1里边提到的寻址能力我感觉是是不同说法表示同一件事,如果不对以后我们再纠正。
在每一台计算机中都有一个主板,主板上有核心器件和一些主要硬件,这些硬件通过总线(地址总线,数据总线,控制总线)相连,硬件包括cpu,存储器,外围芯片组,扩展插槽等,扩展插槽上一般插有RAM内存条和各种接口卡。
计算机系统中所有可用程序控制其工作的设备,必须接受cpu的控制。但cpu不能对外部设备直接控制,例如显示器,音箱,打印机等。直接控制这些设备工作的是在扩展插槽上的接口卡,这些扩展插槽通过总线和cpu相连,所以接口卡也通过总线同cpu相连,cpu可以直接控制接口卡,从而实现间接控制这些外部设备。简单讲就是cpu通过总线发送命令控制接口卡,接口卡根据cpu的命令控制外部设备。
一台pc机中,装有多种存储芯片,这些存储芯片从物理上来看都是相互独立的不同硬件(比如内存和硬盘),从读写属性上来看可分为两类:随机存储器(RAM)和只读存储器(ROM),随机存储器可读可写,但必须带电存储,一旦关机或者突然断电存储的内容将丢失;只读存储器只能读取不能写入,内容不会因为关机和断电丢失。这些存储器从功能和连接上又可分为以下几类:
  *随机存储器
    用于存放供cpu使用的绝大部分程序和数据,主随机存储器一般由两个位置上的RAM组成,装在主板上RAM和扩展插槽上的RAM。
  *装有BIOS(基本输入/输出系统)的ROM
    BIOS是由主板和各类接口卡(如显卡,网卡等)厂商提供的软件系统,可以通过BIOS利用该硬件设备进行最基本的输入输出。在主板和某些接口卡上插有存储相应BIOS的ROM,例如
    主板上的ROM中存储着主板BIOS(通常为系统BIOS),显卡上的ROM存储着显卡的BIOS,如果网卡上装有ROM,那其中就可以存储网卡的ROM。
  *接口上的RAM
    某些接口卡需要对大批量的输入,输出数据进行暂时存储,在其上装有RAM。最典型的是显卡上的RAM,一般称为显存。显卡随时将显存中的数据向显示器上输出。换句话说我们将需要显示出来的内容写入显存,显示器就会显示出来供我们查看。



上述的存储器在物理上都是独立硬件,具有以下相同点
  *都和cpu的总线相连
  *cpu对他们进行读或写的时候通过控制总线发出内存读写命令
也就是说cpu在操作他们的时候,把他们都当作内存来对待,一个由若干存储单元组成的逻辑存储器,这个逻辑存储器就是我们所说的内存地址空间。在汇编这门课中,我们所面对的是内存地址空间。


上图我们可以看到所有的硬件都被cpu看做一整个存储器来操作,每个硬件在这个存储器中占有一个地址段(寻址就是寻找的各个硬件对应的地址段),即一段地址空间。cpu在这段地址空间中读写数据,实际上就是在相对应的硬件上读写数据。
内存地址空间的大小受cpu地址总线宽度的限制,8086cpu的地址总线宽度为20,可以传送2的20次方个不同的地址信息(大小从0到2的20次方减1,),即可以定位2的20次方个内存单元,寻找能力和内存单元是相互匹配的,不可能一个多一个少。则8086pc的内存地址空间大小为1MB。说白了就是有20根地址总线就有一个由1组成的20位数(二进制中1最大,然后这20个1组成的数换算成十进制来方便我们书写就是1MB),这个你怎么叫都行,什么寻址能力,内存单元,地址空间大小,其实都是在说这个由20个1组成的数字。同理80386cpu的地址总线宽度为32,那么寻址能力为4GB,内存单元为4294967296个(这里注意内存单元单位是个,把4GB换算到最小单位B就是这个数字,正好也就是2的32次方。前边说过了一个存储单元正好一个字节。其他两个是空间概念,类似于100套房和100平房子的概念,后者是空间概念。),空间地址最大也是4GB。
我们再给予一个计算机硬件系统编程的时候,必须知道这个系统中内存地址空间的分配情况。因为当我们想在某类存储器中读写数据的时候,必须要知道它从哪个内存单元起始并从那个内存单元结束,才能保证读写操作对应到相应的存储器中进行。比如我们希望向显示器输入一段信息,那么必须将这段信息写到显存中,显卡才能将他输出到显示器上,要向显存写入数据,必须要知道显存在内存地址空间(这里指逻辑内存,是我们人为假设出来的,就是上图中那个假想出来的逻辑存储器。并不是我们现实常说的我手机内存512GB!)中的地址。不同的计算机系统的内存地址分配情况是不同的,下图是8086pc机内存地址空间分配的基本情况

上图我们可以看出,内存单元起始为A0000,内存单元结束为BFFFF的这段内存单元就是显存的内存地址空间,向这段内存单元写入数据就是在向显存中写入数据,这些数据会被显卡输出到显示器来供我们查看,如果写到C0000-FFFFF这个内存单元的话那么数据是无效的。
这一章的结尾特别提到了内存地址空间:
   最终运行程序的是cpu,我们用汇编语言编程的时候,必须要从cpu的角度考虑问题。对cpu来讲,系统中的所有存储器中的存储单元都处于一个统一的逻辑存储器中,它的容量受cpu寻址能力的限制。这个逻辑存储器就是我们所说的内存地址空间。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

4

主题

93

帖子

3205

积分

超级月卡

Rank: 7Rank: 7Rank: 7

积分
3205
 楼主| 发表于 2020-5-20 21:51:52 | 显示全部楼层
本帖最后由 why 于 2020-6-9 18:49 编辑

第2章 寄存器
一个典型的cpu(此处讨论的不是某一具体的cpu)由运算器、控制器、寄存器、(cpu工作原理)等器件构成,这些器件(也可以说硬件好理解一点)靠内部总线相连。前一章所说的总线,相对于cpu内部来说是外部总线(这句话的意思是这样,单独cpu这个硬件里边有3类总线,前一章说的是内部总线。这里说的外部总线是cpu和其他外设硬件间的连线)。内部总线实现cpu内部各器件之间的联系,外部总线实现cpu和主板上其他器件的联系。简单的说:
  运算器进行信息处理
  寄存器进行信息存储
  控制器控制各种器件进行工作
  内部总线连接各种器件,在他们之间进行数据的传送

对一个汇编程序员来说,cpu中的主要部件是寄存器。寄存器是cpu中程序员可以用指令读写的部件。程序员通过改变各种寄存器中的内容来实现对cpu的控制。
不同的cpu寄存器的个数、结构是不相同的。8086cpu有14个寄存器,每个寄存器有一个名称。这些寄存器是:AX、BX、CX、DX、SI、DI、SP、BP、IP、CS、SS、ES、PSW。我们不对这些寄存器进行一次性介绍,在课程进行中,需要用到哪些寄存器再介绍哪些寄存器。


通用寄存器
8086cpu中所有寄存器都是16位的,可以存放两个字节,AX、BX、CX、DX这4个寄存器通常用来存放一般性数据,被称为通用寄存器
  AX累加寄存器
  BX基址寄存器
  CX计数寄存器
  DX数据寄存器
以AX为例寄存器的数据逻辑结构如图

一个16位的寄存器可以存储一个16位的数据(16位就是16bit,1个字节是8bit,所以一个16位寄存器能存储的数据是2字节),数据在寄存器的存放情况如下图所示

8086cpu的上一代cpu中的寄存器都是8位的,为了保证兼容使原来的基于上代的cpu编写的程序稍加修改就可以运行在8086cpu上,8086cpu的AX、BX、CX、DX这4个寄存器都可以分为两个可以独立使用的8位寄存器
AX可分为AH和AL(AL是AX的high位,AL是AX的low位。不会英语感觉是这样解释的 )
BX可分为BH和BL
CX可分为CH和CL
DX可分为DH和DL
以AX为例,8086cpu的16位数据储存在两个8位寄存器的情况如下图所示

上图可以看出来AX的低8位(0-7位)构成了AL寄存器,高8位(8-15位)构成了高8位AH寄存器,我们再来看看16位数据分成两个8位数据是怎么存储的

这里注意我画圈的地方,寄存器中的数据都是二进制数据(因为计算机只认识二进制数据),所表示的数这里注意括号里边的数据结尾都带了个"H",为了区分10进制和16进制课本中所有数据结尾带"H"的都表示16进制,二进制在本课本中都会在数据结尾加“B”。十进制的数据是我们现实中习惯使用的,为了让我们从十进制的习惯过渡到二进制来,才出现了这么些进制的互换,始终记得计算机只认识二进制,为什么不直接用二进制转换到十进制省略掉十六进制呢?十六进制的一位正好相当于二进制的4位,如果用十进制的话,十进制的一位相当于二进制的2.5位,明显这个2.5位没法表示呀!所有我们看到0100 1110 0010 0000(上图里边的20000二进制就这么长一串)16进制表示正好是4(0100)、E(1110)、2(0010)、0(0000),我们也知道了一个内存单元可以存放8位数据,cpu中的寄存器又可以存放n个8位,也就是说计算机中的数据大多是由1---N个8位数据构成的,很多时候需要直观的看出组成数据的各个字节数据的值,用十六进制一眼就能看出来这个数据是由那8位构成的,比如20000写成4E20H就可以直观的看出,这个数据是由4E和20两个8位数据构成的如果AX中存放4E20,则AH里是4E,AL里是20,所以16进制能更好的阅读,便于许多问题的直观分析。
字在寄存器中的存储
出于对兼容性的考虑,8086cpu可以一次性处理以下两种尺寸的数据。
字节:记为byte,一个字节由8个bit组成,可以存放在8位寄存器中
字:记为Word,一个字由两个字节组成,这两个字节分别称为这个字的高位字节和低位字节(我们使用的汉字一个就是占两个字节),如下图所示


我把数值问题放到通用寄存器哪里顺便理解了一下,这里也就不按照课本来说了

回复

使用道具 举报

4

主题

93

帖子

3205

积分

超级月卡

Rank: 7Rank: 7Rank: 7

积分
3205
 楼主| 发表于 2020-5-21 22:30:45 | 显示全部楼层
本帖最后由 why 于 2020-6-11 13:32 编辑

几条汇编指令
通过汇编指令控制cpu进行工作,我们来看一下下表的几条指令
汇编指令 控制cpu完成操作 用高级语言的语法描述
mov ax,18 将18送入寄存器ax ax=18
mov ah,78 将78送入寄存器ah ah=78
add ax,8 将寄存器ax中的数值加上8 ax=ax+8
mov ax,bx 将寄存器bx中的数据送入寄存器ax ax=bx
add ax,bx 将ax和bx中的数值相加,结果存在ax中 ax=ax+bx

注意,为了使具有高级语言基础的读者更好地理解指令的含义,有时会用文字描述和高级语言描述这两种方式来描述一条汇编指令的含义。在写一条汇编指令或一个寄存器的名称时不区分大小写。如mov ax,18和MOV AX,18的含义时相同的(为了打字方便我以后都选用小写输入);bx和BX的含义相同。
接下来看一下cpu执行下表中所列的程序段中的每条指令后,对寄存器中的数据进行的改变。

程序段中指令的执行情况之一(原ax中的值:0000H,原bx中的值:0000H)
程序段中的指令 指令执行后ax中的数据 指令执行后bx中的数据
mov ax,4e20H4e20H 0000H
add ax,1406H6226H 0000H
mov bx,2000H6226H 2000H
add ax,bx8226H 2000H
mov bx,ax8226H 8226H
add ax,bx ?(参见问题2.1) 8226H



问题2.1
指令执行后ax中的数据为多少?我们来看看分析。
  分析:
        程序段中的最后一条指令add ax,bx,在执行前ax和bx中的数据为8226H,相加后所得的值为:1044CH,但是ax为16为寄存器,只能存放4位16进制的数据,所以最高位的1不能在ax中保存,ax中的数据为:04CH。
我们再来看看下表中的程序执行情况


程序段中指令的执行情况之二
程序段中的指令 指令执行后ax中的数据 指令执行后bx中的数据
mov ax,001aH 001aH 0000H
mov bx,0026H 001aH 0026H
add al,bl 0040H 0026H
add ah,bl 2640H 0026H
add bh,al 2640H 4026H
mov ah,0 0040H4026H
add al,85H 00c5H4026H
add al,93H ?(参见问题2.2)4026H
问题2.2
指令执行后ax中的数据为多少?我们来看看分析。
   分析:
          程序段中的最后一条指令add al,93H,在执行前,al中的数据为C5H,相加后所得的值为158H,但是al是8位寄存器,只能存放两位16进制的数据,所以最高位的1丢失,ax中的数据是0058H(这里的丢失指的是进位值不能在8位寄存器中保存,但是cpu并不真正的丢弃这个进位值,关于这个问题我们在以后的课程中讨论。)。
注意,此时al是作为一个独立的8位存储器来使用的,和ah没有关系,cpu在执行这条指令时认为ah和al是两个不相关的寄存器。不要错误地认为,诸如add al,93H的指令产生的进位会储存在ah中,add al,93H进行的是8位运算。
如果执行add ax,93H,低8位的进位会存储在ah中,cpu在执行这条指令时认为只有一个16位寄存器ax,进行的是16位运算。指令add ax,93H执行后,ax中的值为0158H。此时,使用的寄存器是16位寄存器ax,add ax,93H相当于将ax中的16位数据00c5H和另一个16位数据0093H相加,结果是16位的0158H。
在进行数据传送或运算时,要注意指令的两个操作对象的位数应当是一致的,例如
  mov ax,bx(将寄存器bx中的值送入寄存器ax,覆盖掉ax中原有数据)
  mov bx,cx(将寄存器cx中的值送入寄存器bx,覆盖掉bx中原有数据)
  mov ax,18H(将数据18H送入寄存器ax,,覆盖掉ax中原有数据)
  mov al,18H(将数据18H送入寄存器ax的低8位,,覆盖掉ax低8位中原有数据)
  add ax,bx(将寄存器ax中的值加上寄存器bx中的值得结果存放在寄存器ax中)
  add ax,20000(将寄存器ax中的值和20000相加的结果存放在ax中,这里的20000需要转换成16进制是4E20H,是一个16位的数据,前边的ax也是16位寄存器)
以上都是争取的指令,而:
  mov ax,bl  (在8位寄存器和16位寄存器之间传送数据)
  mov bh,ax (在16位寄存器和8位寄存器之间传送数据)
  mov al,20000(20000转换成16进制是4E20,明显16位数据无法存放到8位寄存器中)
  add al,100H(100H是一个12位数据,12位数据和8位数据无法相加)
等都是错误指令,错误的原因都是指令的两个操作对象的位数不一样。
这里有一个比较严重的问题,所有图片里边对mov的解释都是:将一个数据送入寄存器。那么上边的两个例子我们发现mov的正确解释应该是:将一个数据送入寄存器,并覆盖掉这个寄存器中原有的数据。我当时就纳闷直接送进去后原来寄存器中的数据怎么办,查询后确定是要直接覆盖掉的。
检测点2.1
1.写出每条汇编指令执行后相关寄存器的值
mov ax,62627      AX=f4a3H
mov ah,31H         AX=31a3H
mov al,23H          AX=3123H
add ax,ax            AX=6246H
mov bx,826CH     BX=826cH
mov cx,ax           CX=6246H
mov ax,bx           AX=826cH
add ax,bx           AX=04d8H
mov al,bh           AX=0482H
mov ah,bl           AX=6c82H
add ah,ah          AX=d882H
add al,6             AX=d888H
add al,al            AX=d810H
mov ax,cx         AX=6246H
做了一遍也详细的说了一下每一步有哪些坑

2.只能使用目前学过的汇编指令,做多用4条指令编程计算2的4次方。
  解答:2的4次方是16
            add ax,ax是累加,ax加ax存入ax中,正好累加3次2就是2的4次方,ax=2+2=4,ax=4+4=8,ax=8+8=16,
            3条指令就搞定了!别忘了我们要先传送一个数据进去,要不然计算机是不会工作的,故
            mov ax,2(这里是个10进制的2,但是十进制的2和十六进制的2又是一样的,所以也注意一下这个小问题)
            add,ax,ax(将寄存器ax中的值加上寄存器ax中的值得结果存放在寄存器ax中,执行后ax=2+2=4)
            add,ax,ax(将寄存器ax中的值加上寄存器ax中的值得结果存放在寄存器ax中,执行后ax=4+4=8)
            add,ax,ax(将寄存器ax中的值加上寄存器ax中的值得结果存放在寄存器ax中,执行后ax=8+8=16)


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

4

主题

93

帖子

3205

积分

超级月卡

Rank: 7Rank: 7Rank: 7

积分
3205
 楼主| 发表于 2020-5-23 00:07:17 | 显示全部楼层
本帖最后由 why 于 2020-6-9 19:14 编辑

物理地址
我们知道cpu访问内存单元时,要给出内存单元的地址。所有的内存单元构成的存储空间是一个一维的线性空间,每一个内存单元在这个空间中都有唯一的地址,我们将这个唯一的地址称为物理地址。cpu通过地址总线送入寄存器的,必须是一个内存单元的物理地址。在cpu向地址总线上发出物理地址之前,必须要在内部先形成这个物理地址。不同的cpu可以有不同的形成物理地址的方式,我们现在讨论8086cpu是如何在内部形成内存单元的物理地址的。


16位结构的cpu
我们说8086cpu的上一代(8080、8085)等是8位机,而8086是16位机,也可以说8086是16位结构的cpu。那么什么是16位结构的cpu呢?
概况地讲,16位结构(16位机,字长为16位等常见说法,与16位结构的含义相同)描述了一个cpu具有下面几方面的结构特性。
  运算器一次最多可以处理16位数据
  寄存器的最大宽度位16
  寄存器和运算器之间的通路位16位

8086是16位结构的cpu,这也就是说,在8086内部,能够一次性处理、传输、暂时存放的信息最大长度是16位的。内存单元地址送上地址总线前,必须在cpu中处理、传输、暂时存放,对于16位cpu,能一次性处理、传输、暂时存储16位的地址。


8086cpu给出物理地址的方法
8086cpu有20位地址总线,可以传输20位地址,达到1M的寻址能力。8086cpu又是16位结构,在内部一次性处理、传输、暂时存放的地址位16位。从8086cpu的内部结构来看,如果将地址从内部简单发出,那么它只能送出16位的地址,表现出的寻址能力只有64KB.
8086cpu采用一种在内部用两个16位地址合成的方法来形容一个20位的物理地址。
8086cpu相关部件得逻辑结构如图所示:

如图所示,当8086cpu要读写内存时:
(1)cpu中的相关不见提供两个16位的地址,一个称为段地址,另一个称为偏移地址;
(2)段地址和偏移地址通过内部总线合成为一个20位的物理地址;
(3)地址加法器将两个16位地址合成为一个20位的物理地址;
(4)地址加法器通过内部总线将20位的物理地址送入输入输出控制电路;
(5)输入输出控制电路将20位物理地址送上地址总线;
(6)20位物理地址被地址总线传送到寄存器;
地址加法器采用“物理地址=段地址*10H(16)+偏移地址(这里把公式中间的16换成10H来理解,要不然作为新人在下阶段按照课本讲的乘16带进去计算就要出错)的方法用段地址和偏移地址合成物理地址。例如8086cpu要访问地址为123c8H的内存单元。此时,地址加法器如下图所示(图中数据皆为16进制)




由段地址*10H(16)引发的讨论

"段地址*10H(16)"有一个更为常用的说法是左移4位。计算机中的所有信息都是以二进制的形式存储的,段地址当然也不例外。机器只能处理二进制信息,"左移4位"中的位,指的是二进制位。

我们看一个例子,一个数据为2H,二进制形式为10B,对其进行左移运算:

左移位数       二进制      十六进制         十进制

0                  10B          2H                  2

1                 100B         4H                  4

2                1000B        8H                  8

3               10000B      10H                16

4              100000B     20H                32


观察上面移位次数和各种形式数据的关系,我们可以发现:

(1) 一个数据的二进制(这里看成十进制会更直观好理解些,毕竟我们长期习惯更容易理解十进制)形式左移1位,相当于该数据乘以2;

(2) 一个数据的二进制(这里也看成十进制来理解)形式左移N位,相当于该数据乘以2的N次方;

(3) 地址加法器如何完成段地址*10H(16)的运算?就是将以二进制形式存放的段地址左移4位。

进一步思考,我们可看出:一个数据的十六进制形式左移1位,相当于乘以10H(16);一个数据的十进制形式左移1位,相当于乘以10;一个X进制的数据左移1位,相当于乘以X。
这个段地址*10H(16)说一下,在计算机中计算机只能识别二进制,为什么不能是二进制偏移4位呢?其实二进制偏移4位也是成立的,只是有一点我们必须清楚,那就是我们用十六进制来理解计算机是为了方便我们更好的识别并且计算,汇编会比较接近机器硬件的语言,但也是介于人类语言习惯和机器语言的介质,方便我们也要计算机能识别,这是最基本的,汇编就是用更偏向于我们人类的语言来解释机器语言,所以这里用段地址偏移*16是为了方便我们理解。那么问题又来了,既然最后要计算机识别为什么不可以是段地址偏移1位呢?这样按理来说不应该计算机更容易识别和操作吗?我们需要知道的一件事就是汇编的主要目的就是为了用十六进制来描述二进制,这个知道了就不会产生为什么不是二进制偏移1位来解释段地址偏移这个问题了。


段地址*10H(16)+偏移地址=物理地址的本质含义:注意这个公式里段地址和偏移地址都是十六进制形式的这个数据16却是十进制形式的,在后边的计算中我用                                                                        公式计算的时候一直出错,这里一定要理解成10H,方便下一阶段计算不出错
注意,这里讨论的是8086cpu段地址和便宜地址的本质含义,而不是为了解决具体的问题而在本质含义引申出来的更高级的逻辑意义。不管以多少中不同的逻辑意义去看待“段地址*10H(16)+偏移地址=物理地址”的寻址模式,一定要清楚的知道它的本质含义,这样才能更灵活的利用它来分析、解决问题。如果只拘泥于某一种引申出来的逻辑含义,而模糊本质含义的话,将从意识上限制对这种寻址功能的灵活应用。
“段地址*10H(16)+偏移地址=物理地址”的本质含义是:cpu在访问内存时,用一个基础地址(段地址*10H(16))和一个相对于基础地址偏移的地址相加,给出内存单元的物理地址。
更一般的说,8086cpu这种寻址功能是”基础地址+偏移地址=物理地址“寻址模式的一种具体实现方案。8086cpu中,段地址*16可看做是基础地址。
我们可以这样来理解,比如,你现在在单位,回家要走250000米,然后从家里走8000米去图书馆看书,问你今天走了多少米?
刚开始从单位走了250000米回家,又走了8000米去图书馆看书,一共是258000米。这个表示”基础地址(从单位到家里250000米)+偏移地址(从家里到图书馆)=物理地址“显得我们更好理解一些了吧,这样就构成了一个完整的起点到终点的距离出来。
现在给你增加个附加条件,比如你只能通过纸条来传递给我你今天走了多少米,
但是每张纸条上最多只能写下5位数,并且你只要两次书写的机会,该怎么写呢?
我们可以用“段地址*10H(16)+偏移地址=物理地址”来尝试书写,当然这里是现实中我们用的十进制,所有换成“段地址*10+偏移地址”,第一章纸条写上25800第二张纸条写下8000,然后我们再约定一下是这么计算的,这事就这么愉快的成了。我拿到纸条一看,经过事先的约定很快就计算出来:25800(段地址)*10+8000(偏移地址)=258000(物理地址)。
现在回到计算机来,假设让计算机直寻址这个258000米的物理地址的话(换算成十六进制为3EFD0H),由于计算机有局限性我们都知道8086cpu一次性能够处理、传输、暂时存储的信息最大长度为16位,我们把所有数据替换到前边地址加法的工作过程中去,

这里我没有用书上的例子,自己参考了例子对各个数据进行更正,并把例子从计算机引到显示又引回计算机来理解这个概念,这只是我个人的理解方法,仅供参考!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

4

主题

93

帖子

3205

积分

超级月卡

Rank: 7Rank: 7Rank: 7

积分
3205
 楼主| 发表于 2020-5-25 01:15:31 | 显示全部楼层
本帖最后由 why 于 2020-6-9 19:22 编辑

段的概念
我们注意到,“段地址”这个名称中包含着“段”的概念。这种说法可能对一些学习者产生误导,使人误以为内存被划分成了一个一个的段,每一个段有一个地址。如果我们一开形成这种认识,将影响以后对汇编语言深入理解和灵活运用。
其实,内存并没有分段,段的划分来自于cpu,由于8086cpu用“基础地址(段地址*10H(16))+偏移地址=物理地址”的方式给出内存单元的物理地址,使得我们可以用分段的方式来管理内存,如下图所示,我们可以认为:地址10000H~100FFH的内存单元组成一个段,该段的起始地址(基础地址)为10000H,段地址为1000H,大小为100H(这个段地址前边我们已经说过了;段大小也就是10000H~100FFH这之间的空间,比如1厘米~2厘米之间有个1厘米的距离空间,这样就能理解段大小这个概念了,用100FFH减去10000H等于255,计算机是从0开始计数的所以是255+1=256个空间,256换算成十六进制就是FF。)我们也可以认为地址10000H~1007FH、10080H~100FFH的内存单元组成两个段,它们的起始地址(基础地址)为:10000H和10080H,段地址为:1000H和1008H,大小都为80H。

以后,在编程时可以根据需要,将若干地址连续的内存单元看作一个段,用段地址*10H(16)定位段的起始地址(基础地址),用偏移地址定位段中的内存单元。有两点需要注意:段地址*10H(16)必然是16的倍数,所以一个段的起始地址也一定是16的倍数。偏移为16位,16位地址的寻址能力为64KB,所以一个段的长度最大为64KB。

(这里我们发现一个问题,前边的例子是取123C8H这个数据最高的3位补0构成了1230H这个十六进制数来计算物理地址的,这里的段地址居然是1008。不应该只取最高位前3位吗?我们往下看)
观察下面的地址我们就清楚为什么段地址两个例子取得不一样了
    物理地址   段地址   偏移地址
    21F60H     2000H   1F60H
                    2100H   0F60H
                    21F0H   0060H
                    1F00H   2F60H
我们发现cpu可以用不同的段地址和偏移地址形成同一个物理地址!
比如cpu要访问21F60H单元,则它给出段地址SA和偏移地址EA满足SA*10H(16)+EA=21F60H即可,同时我们还发现,段地址越大偏移地址就越小,a+b=10肯定a越大b越小!
如果给定一个地址段,仅通过变化偏移地址来进行寻址,最多可定位多少个内存单元?
偏移16位变化范围为0~FFFFH(变化范围就是从最小到最大,即0000~FFFFH),仅用偏移地址来寻址最多可寻64KB个内存单元(16位地址的寻址能力为64KB,所以一个段的最大长度为64KB;在这个0~FFFFH的地址段中,实际上起始地址为0,段地址为0,段大小为FFFFH。)
比如给定段地址1000H,用偏移地址寻址cpu的寻址范围为:10000H~1FFFFH(1FFFFH减去10000H=FFFFH,即64KB)
在8086pc机中,储存单元的地址用两个元素来描述,即段地址和偏移地址。
“数据21F60H内存单元中”这句话对于8086pc机一般不这样讲,取而代之的是两种类似的说法:1>数据在内存2000:1F60单元中;2>数据在内存的2000H段中的1F60H单元中。这样两种描述都表示“数据在内存21F60H单元中”。
可以根据需要,将地址连续、起始地址为16的倍数的一组内存单元定义为一个段(这一句话要这么来理解:比如0~FFFF这个段,首先它是连续的,起始地址也为16的倍数(0可以整除16吧,虽然十进制中它是无意义的)!)。



检测点
1.给定段地址为0001H,仅通过变化偏移地址寻址,cpu的寻址范围为____到____。
   段地址*10H(16)+偏移地址=物理地址
   最小范围(偏移地址最小为0000H):0001H*10H+0000H=00010H
   最大范围(偏移地址最大为FFFFH):0001H*10H+FFFFH=1000FH
2.有一数据存放在内存20000H单元中,现给定段地址为SA,若想用偏移地址寻找到此单元,则SA应满足的条件是:最小为____,最大为_____。
  提示,反过来思考一下,当段地址给定为多少,cpu无论怎么变化偏移地址都无法寻找到20000H单元
  段地址*10H+偏移地址=物理地址
   段地址最大范围(段地址越大偏移地址越小,用最小的偏移地址0):(20000H-0000H)/10H=段地址=2000H(我们之前是乘以16,但是那个16是十进制的,因为整个式子里都是16进制,加入个10进制去算会出错的,这里特别注意一下,不信你也用16计算,肯定会出错)
   段地址最小范围(段地址越大偏移地址越小,用最大的偏移地址FFFFH):(20000H-FFFFH)/10H=段地址=10001H/10H,计算到这里我们发现出现了问题,如果用计算器计算10001H/10H的话=1000H,前边我们说了一个段的起始地址一定是16(10H)的倍数,明显这个10001H无法整除10H。那么我们只能把偏移地址来减小到可以和段地址匹配,这里注意不能直接减小计算出来的这个段地址以求达到整除10H,我们是用偏移地址算出来的段地址,只能通过减小偏移地址来重新计算段地址。我们需要一个一个尝试直到计算出能整除10H的段地址
               (20000H-FFFEH)/10H=段地址=10002H/10H
               (20000H-FFFDH)/10H=段地址=10003H/10H
               (20000H-FFFCH)/10H=段地址=10004H/10H
               (20000H-FFFBH)/10H=段地址=10005H/10H
               (20000H-FFFAH)/10H=段地址=10006H/10H
               (20000H-FFF9H)/10H=段地址=10007H/10H
               (20000H-FFF8H)/10H=段地址=10008H/10H
               (20000H-FFF7H)/10H=段地址=10009H/10H
               (20000H-FFF6H)/10H=段地址=1000AH/10H
               (20000H-FFF5H)/10H=段地址=1000BH/10H
               (20000H-FFF4H)/10H=段地址=1000CH/10H
               (20000H-FFF3H)/10H=段地址=1000DH/10H
               (20000H-FFF2H)/10H=段地址=1000EH/10H
               (20000H-FFF1H)/10H=段地址=1000FH/10H
               (20000H-FFF0H)/10H=段地址=10010H/10H=1001H
直到偏移地址最大为FFF0H时才能满足段地址整除16(10H),故段地址最小为1001H
反过来思考一下当段地址比1001H还小比2000H还大的时候cpu无论怎么变化偏移地址都找不到物理地址!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

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