汇编语言是指直接工作在硬件之上的语言,但不是机器语言,机器语言是机器指令的集合。汇编语言是汇编指令的集合,汇编指令是便于记忆的机器指令的另一种书写方式,也就是说是机器指令的助记符。
汇编指令与数据在内存中存储都是二进制形式存储,因此CPU是无法直接区分一块内存是地址还是数据,但是CPU在与内存(这里指得所有芯片内存)进行数据传输时,将传输总线分成三大类:地址总线、数据总线、控制总线。这三类不同的总线读过来的内存值就分别对应的机器指令、机器数据、机器控制命令。
CPU通过地址总线来指定存储单元,因此地址总线上能传送多少不同信息,CPU就可以对多少个存储单元进行寻址。通常意义上的32位,64位CPU指得就是这个地址总线宽度。一个CPU有N根地址总线,就表示这个CPU最多可以寻找2的N次方个内存单元。
CPU向内存发送取址1011(注意上面是低位,下面是高位),内存就到指定地址取址。
CPU通过数据总线来传输数据,因此,数据总线的宽度决定了CPU与外界数据传输速度。如下图所示:
前面是8088CPU ,每次传送8,传送16位数据需传送两次。后面是8086CPU,一次就可以传输16位数据
CPU对外部器件的控制是通过控制总线来进行的,有多少根控制总线,意味着CPU可以控制多少个外部器件,因此,控制总线的宽度决定了CPU对外部器件的控制能力。
如上图,CPU向读信号控制线输出读信号,内存就收到读命令。同样写信号输出控制线负责CPU向外传送写信号。
CPU通过总线控制主板上各种器件和接口卡连接上来的显示器等。内存是由存储器提供,存储器分为随机存储器(RAM,通常所说的内存)和只读存储器(ROM,比喻说主板或各类接口卡上的ROM,用来存储BIOS系统)
前张图是从物理上来分析存储器,后面是以CPU的角度来看存储器。对CPU来说,存储器是按线性虚拟进行分配的,它不知道具体这个地址是对应到哪个具体器件。因此,不同的CPU架构默认对内存空间进行了地址划分。
比喻8086PC就这样划分了存储地址。
通常一个典型的CPU架构是由运算器,控制器、寄存器等器件组成,这些内部器件之间由内部总线相互连接。其中8086CPU有14个寄存器,分别为AX、BX、CX、DX、SI、DI、SP、BP、IP、CS、SS、DS、ES、PSW。
AX、BX、CX、DX称之为通用寄存器,存储过程就是将数值转换为二进制,如18转成二进制是10010,将这些二进制填进寄器对应位,并其它位全置为0.
这些寄存器是前后兼容的,它的兼容方式就是当它与8位兼容时,16位寄存器成两个AH、AL,其它类推,这时8位只用低位寄存器空间位AL、BL、CL、DL等。32位CPU称之为EAX、EBX、ECX、EDX,原理跟上面一样。
这里有个技巧是二进制每四位刚好是一个十六进制的一位。二进制每三位是一个八进制的一位。
汇编指令是不区分大小写的,下面学习几个基本的汇编指令。
其中进位1会被寄存器另存到另位一个地方。
对al/ah/bl/bh这类寄存器,它同样也不能自动进位到其它的寄存器。它们的进位都要保存到别的地方。
8086CPU是16位结构的CPU,它有以下几个特征:
【1】运算器一次可以处理16位数据
【2】寄存器的最大宽度是16位
【3】寄存器与运算器之间的通路是16位的。
【4】地址总线20位,可以达到1MB寻址能力。
8086CPU内部是16位,但是外部是20位,因此它采用一种在内部用两个16位地址合成的方法来形成一个20位的物理地址。
如上图所示,当CPU要读内存时,CPU提供两个16位地址,一个称之为段地址,另一个称之为偏移地址,段地址和偏移地址通过内部总线送到一个地址加法器,由地址加法器转换成一个20位地址。
地址加法器计算方法是,物理地址=段地址*16+偏移地址(这里说明对任何一个进制的数据,左移一位,相当于在原值基础上乘以进制,比喻16进制左移1位,相当于乘以16)。
当CPU要取的内存物理地址一定时,CPU给出何种段址和偏移地址,这个是不一定的。也就是说CPU可以用不同的段地址和偏移地址形成一个物理地址。如下图所示。
以前有些人根据计算机体系架构书的一些描述,错误的认为内存划分成不同的段,实际上这是一个错误概念,内存没有被分成一个一个的段,段的划分来源于CPU,CPU采用分段方式来管理线性地址。
因此,从上图左边可以看出,内存自身没有划分段,划分段是从CPU的角度来进行划分,因此怎么划分也是由CPU决定的。从程序员的角度来说,可以认为一段连续的内存就可以看成一个段,用段地址*16定位段的起始地址(基础地址),所以段的起始地址肯定是16的倍数。用偏移地址定位段中的内存单元,因为偏移地址为16位,变化范围上0~FFFFH,所以段的长度最大是64K。
从CPU内部结构来说,8086CPU设置了四个段寄存器CS、DS、SS、ES来提供段地址,其中CS和IP是8086中两个最关键的寄存喊叫,CS为代码段寄存器,IP为指针寄存器,也就是段地址和偏移地址。
上图所示的是CPU的工作流程:
【1】地址加法器从CS:IP中读取段地址2000*16加上偏移地址000H,得到内存地20000H,送入地址总线,地址总线定位出内存段地址2000H。
【2】根据汇编指令地址B8(代表MOV AX),取出三个地址,送入数据总线B82301,数据总线根据数据总线的长度是一次性读取还是多次读取。读取后放入指令缓存器,送入CPU的执行单元(ALU)。一旦指令被读取,IP自动根据指令的宽度计算下一次指令读取的偏移地址。如上图变成0003H
【3】ALU计算后,将结果放入AX寄存器。至一次一个指令运行完毕,重复下一个指令。
对8086CPU加电启动或复位后,默认CS指向FFFH,IP指向000H。因此开机后第一条指令是FFFF0H。
在任何时候,CPU根据CS:IP指向的内存单元中的内容看作指令,这样就将内存中的数据与指令区分开来。如果想要修改CS:IP的地址可以用jmp指令。
jmp 段地址:偏移地址同时修改CS:IP
jmp 某一合法寄存器,仅修改IP,偏移地址。
由前面可以知道内存是连续的,并没有分段,但在编程时,可以根据编程需要,将一组内存单元定义为一个段,并将长度为N(小于64KB)的一段代码放入其中,形成一个代码段,如要执行这段代码,必须设置CS:IP地址为这个段的首地址。