汇编期末笔记

8086CPU有14个寄存器

CPU=运算器+控制器+【寄存器】,器件之间通过总线相连
名称分别为:
AX,BX,CX,DX,SI,DI,SP,BP,IP,CS,SS,DS,ES,PSW
x,i,p,s,w
这些寄存器都是16位

8086CPU给出物理地址的方法

8086CPU采用一种在内部用两个16位地址合成的方法来形成一个20位的物理地址。

当8086CPU要读写内存时:

CPU中的相关部件提供两个16位的地址,一个称为段地址,另一个称为偏移地址;

地址加法器将两个16位地址合成为一个20位的物理地址;

地址加法器采用物理地址 = 段地址×16 + 偏移地址的方法用段地址和偏移地址合成物理地址。
请添加图片描述

8086CPU不支持将数据直接送入段寄存器的操作,这属于8086CPU硬件设计

通用寄存器

8086上一代CPU中的寄存器都是8位的,为了保证兼容性
这四个寄存器都是可以分为2个独立的8位寄存器使用
AX=AH+AL
BX=BH+BL
CX=CH+CL
DX=DH+DL

段寄存器(以s结尾)

我们可以将一段内存定义为一个段,用一个段地址指示段,用偏移地址访问段内的单元,可以用分段的方式来管理内存。

用一个段存放数据,将它定义为“数据段”;

用一个段存放代码,将它定义为“代码段”;

用一个段当作栈,将它定义为“栈段”。

注意:

1.一个段的起始地址一定是16的倍数
2.偏移地址为16位,变化范围为0-FFFFH,所以一个段的长度最大为64KB
3.CPU可以用不同的段地址和偏移地址形成同一个物理地址

段寄存器:8086CPU有4个段寄存器:CS、DS、SS、ES,提供内存单元的段地址。

CS和IP

1.CS为代码段寄存器,IP为指令指针寄存器

2.CPU将CS、IP中的内容当作指令的段地址偏移地址,用它们合成指令的物理地址

3.CPU将CS:IP指向的内容当作指令执行。(即PC)

8086CPU的工作过程简要描述
1.从CS:IP指向的内存单元读取指令,读取的指令进入指令缓冲器;

2.IP=IP+所读取指令的长度,从而指向下一条指令;

3.执行指令。转到步骤1,重复这个过程。

CPU将CS:IP指向的内容当作指令执行。(即PC)

jmp 段地址:偏移地址:用指令中给出的段地址修改CS,偏移地址修改IP。如:jmp 2AE3:3

jmp 某一合法寄存器:仅修改IP的内容。如:jmp ax。在含义上好似:mov IP,ax

DS 和 [address]

DS寄存器:通常用来存放要访问数据的段地址

[address]表示一个偏移地址为address的内存单元,段地址默认放在ds中

通过数据段段地址和偏移地址即可定位内存单元。

mov bx, 1000H ;8086CPU不支持将数据直接送入段寄存器的操作

mov ds, bx ;ds存放数据段地址

mov [0], al ;将al数据(1字节)存到1000H段的0偏移地址处,即10000H

mov ax, [2] ;将数据段偏移地址2处的一个字(80862字节)存放到ax寄存器

add cx, [4] ;将偏移地址4处的一个字数据加上cx寄存器数据放到cx寄存器

sub dx, [6] ;dx寄存器数据减去数据段偏移地址6处的字数据存到dx

在这里插入图片描述

栈段寄存器SS,存放段地址,SP寄存器存放偏移地址,任意时刻,SS:SP指向栈顶元素

push ax表示将寄存器ax中的数据送入栈中,由两步完成。

SP=SP-2,SS:SP指向当前栈顶前面的单元,以当前栈顶前面的单元为新的栈顶;

将ax中的内容送入SS:SP指向的内存单元处,SS:SP此时指向新栈顶。

pop ax表示从栈顶取出数据送入ax,由以下两步完成。

1.将SS:SP指向的内存单元处的数据送入ax中;

2.SP=SP+2,SS:SP指向当前栈顶下面的单元,以当前栈顶下面的单元为新的栈顶。

实验

将10000H~1000FH这段空间当作栈,初始状态栈是空的;
设置AX=001AH,BX=001BH;
将AX、BX中的数据入栈;
然后将AX、BX清零;
从栈中恢复AX、BX原来的内容。

mov ax, 1000H 
mov ss, ax 
mov sp, 0010H    ;初始化栈顶
mov ax, 001AH
mov bx, 001BH 

push ax 
push bx    ;ax、bx入栈

sub ax, ax   ;将ax清零,也可以用mov ax,0;sub ax,ax的机器码为2个字节,
             ;mov ax,0的机器码为3个字节。
        
sub bx, bx 

pop bx  ;从栈中恢复ax、bx原来的数据
pop ax  ;

已学mov指令的几个形式

    1.mov 寄存器,数据         ;立即寻址
    2.mov 寄存器,寄存器        ;寄存器寻址
    3.mov 寄存器,内存单元      ;直接寻址
    4.mov 内存单元,寄存器      ;寄存器寻址?
    5.mov 段寄存器,寄存器      ;寄存器寻址
    6.mov 寄存器,段寄存器      ;寄存器寻址
2.add、sub同mov一样,都有两个操作对象
    1.add的用法
        1.add 寄存器,数据      ;立即寻址
        2.add 寄存器,寄存器    ;寄存器寻址
        3.add 寄存器,内存单元  ;直接寻址
        4.add 内存单元,寄存器  ;
    2.sub的用法
        【不带借位的减法】
        指令格式 sub op1,op2    ;意为:op1=op1-op2
        1.sub 寄存器,数据      ;立即寻址
        2.sub 寄存器,寄存器    ;寄存器寻址
        3.sub 寄存器,内存单元  ;直接寻址
        4.sub 内存单元,寄存器  ;

第一个程序

1、汇编程序从写出到执行的过程请添加图片描述
加载后,CPU的CS:IP指向程序的第一条指令(即程序的入口)

;1.asm
assume cs:codesg ;将用作代码段的段codesg和段寄存器cs联系起来。

codesg segment ;定义一个段,段的名称为“codesg”,这个段从此开始
			   ;codesg是一个标号,作为一个段的名称,最终被编译连接成一个段的段地址

	mov ax, 0123H
	mov bx, 0456H 
	add ax, bx
	add ax, ax 
	
	mov ax, 4c00H 
	int 21H ;这两条指令实现程序的返回
	
codesg ends ;名称为“codesg”的段到此结束

end ;编译器在编译汇编程序的过程中,碰到了伪指令end,结束对源程序的编译

[bx] 和 loop指令

[bx] 的含义:[bx]同样表示一个内存单元,它的偏移地址在bx中,段地址默认在ds中
在这里插入图片描述

loop指令的格式是:loop 标号,CPU执行loop指令的时候,要进行两步操作,

(cx) = (cx) - 1;

判断 cx 中的值,不为零则转至标号处执行程序,如果为零则向下执行。
loop:

1[bx] 和 loop指令
**[bx] 的含义:[bx]同样表示一个内存单元,它的偏移地址在bx中,段地址默认在ds中**

loop指令的格式是:loop 标号,CPU执行loop指令的时候,要进行两步操作,

(cx) = (cx) - 1;

判断 cx 中的值,不为零则转至标号处执行程序,如果为零则向下执行。

例如:计算212

assume cs:code 

code segment 
	mov ax, 2
	
	mov cx, 11 ;循环次数
s:  add ax, ax 
	loop s     ;在汇编语言中,标号代表一个地址,标号s实际上标识了一个地址,
               ;这个地址处有一条指令:add ax,ax。
               ;执行loop s时,首先要将(cx)减1,然后若(cx)不为0,则向前
               ;转至s处执行add ax,ax。所以,可以利用cx来控制add ax,ax的执行次数。
	
	mov ax,4c00h 
	int 21h 
code ends 
end

loop 和 [bx] 的联合应用


计算ffff:0 ~ ffff:b单元中的数据的和,结果存储在dx中

问题分析:

这些内存单元都是字节型数据范围0 ~ 25512个字节数据和不会超过65535,dx可以存下
对于8位数据,但不能直接加到 dx
解决方案:

用一个16位寄存器来做中介。将内存单元中的8位数据赋值到一个16位寄存器a中,再将ax中的数据加到dx

assume cs:code 

code segment 
	mov ax, 0ffffh ;在汇编源程序中,数据不能以字母开头,所以要在前面加0。
	mov ds, ax 
	mov bx, 0   ;初始化ds:bx指向ffff:0
	mov dx, 0   ;初始化累加寄存器dx,(dx)= 0
	
	mov cx, 12  ;初始化循环计数寄存器cx,(cx)= 12
s:  mov al, [bx];
	mov ah, 0
	add dx, ax  ;间接向dx中加上((ds)* 16 +(bx))单元的数值
	inc bx      ;ds:bx指向下一个单元
	loop s 
	
	mov ax, 4c00h 
	int 21h 
code ends 
end

在这里插入图片描述

段前缀

在这里插入图片描述
段前缀的使用
在这里插入图片描述

在这里插入图片描述

四个16位寄存器

寄存器AX和AL通常称为累加器(Accumulator),用累加器进行的操作可能需要更少时间。累加器可用于乘、除、输入/输出等操作,它们的使用频率很高;

     寄存器BX称为**基地址**寄存器(Base Register)。它可作为存储器指针来使用;

    寄存器CX称为**计数**寄存器(Count Register)。在循环和字符串操作时,要用它来控制循环次数;在位操作中,当移多位时,要用CL来指明移位的位数;

    寄存器DX称为**数据**寄存器(Data Register)。在进行乘、除运算时,它可作为默认的操作数参与运算,也可用于存放I/O的端口地址。

包含多个段的程序

绿色:第二行中将用作代码段的段codesg和段寄存器cs联系起来,相当于cs是一个数组,存储着八个字形数据

在这里插入图片描述

更灵活的定位内存地址的方法

and 和 or
and指令:逻辑与指令,按位进行与运算。

mov al, 01100011B
and al, 00111011B

执行后:al=00100011B即都为1才为1

or指令:逻辑或指令,按位进行或运算。

mov al, 01100011B
or al, 00111011B
执行后:al=01111011B 即只要有一个为1就为1
小写转大写
绿色:
在这里插入图片描述

在这里插入图片描述
大写转小写
在这里插入图片描述

[bx+idata]

[bx+idata]表示一个内存单元, 例如:mov ax, [bx+200]
该指令也可以写成如下格式:

mov ax, [200+bx]

mov ax, 200[bx]

mov ax, [bx].200
4、不同的寻址方式的灵活应用
[idata]用一个常量来表示地址,可用于直接定位一个内存单元
[bx]用一个变量来表示内存地址,可用于间接定位一个内存单元
[bx+idata]用一个变量和常量表示地址,可在一个起始地址的基础上用变量间接定位一个内存单元
[bx+si]用两个变量表示地址;
[bx+si+idata]用两个变量和一个常量表示地址。

assume cs:codesg,ds:datasg 

datasg segment 
	db 'BaSiC';转为大写
	db 'MinIx';转为小写
datasg ends

codesg segment
	start:
		mov ax, datasg 
		mov ds, ax 
		mov bx, 0  ;初始ds:bx
	
		mov cx, 5
	s:	mov al, 0[bx]  
		and al, 11011111b ;转为大写字母
		mov 0[bx], al ;写回
		mov al, 5[bx]  ;[5 + bx]
		or al, 00100000b ;转为小写字母
		mov 5[bx], al 
		inc bx
		loop s
		
		mov ax, 4c00h 
		int 21h
codesg ends
end start

bx、si、di和bp

在8086CPU中,只有这4个寄存器可以用在“[…]”中来进行内存单元的寻址

在[ ]中,这4个寄存器可以单个出现,或只能以4种组合出现:bx和si、bx和di、bp和si、bp和di

只要在[……]中使用寄存器bp,而指令中没有显性地给出段地址, 段地址就默认在ss

2、机器指令处理的数据在什么地方

数据处理大致可分为3类:读取、写入、运算。

在机器指令这一层来讲,并不关心数据的值是多少,而关心指令执行前一刻,它将要处理的数据所在的位置。指令在执行前,所要处理的数据可以在3个地方:CPU内部、内存、端口

汇编语言中数据位置的表达

汇编语言中用3个概念来表达数据的位置

立即数(idata)

mov ax, 1                 ;对于直接包含在机器指令中的数据(执行前在CPU的指令缓冲器中)
add bx, 2000h             ;在汇编语言中称为:立即数(idata)
or bx, 00010000b
mov al, 'a'

寄存器

mov ax, bx     ;指令要处理的数据在寄存器中,在汇编指令中给出相应的寄存器名。
mov ds, ax 
push bx 
mov ds:[0], bx 
push ds 
mov ss, ax
mov sp, ax

段地址(SA)和偏移地址(EA)

;指令要处理的数据在内存中,在汇编指令中可用[X]的格式给出EA,SA在某个段寄存器中。
mov ax, [0]
mov ax, [di]
mov ax, [bx+8]
mov ax, [bx+si]
mov ax, [bx+si+8]   ;以上段地址默认在ds中

mov ax, [bp]
mov ax, [bp+8]
mov ax, [bp+si]
mov ax, [bp+si+8]   ;以上段地址默认在ss中

mov ax, ds:[bp]
mov ax, es:[bx]
mov ax, ss:[bx+si]
mov ax, cs:[bx+si+8] ;显式给出存放段地址的寄存

寻址方式

请添加图片描述

;利用除法指令计算1001/100

mov ax, 1001
mov bl, 100
div b1

伪指令dd

db和dw定义字节型数据和字型数据。

dd是用来定义dword(double word,双字)型数据的伪指令

操作符dup

dup在汇编语言中同db、dw、dd等一样,也是由编译器识别处理的符号。
它和db、dw、dd等数据定义伪指令配合使用,用来进行数据的重复

db 3 dup (0) ;定义了3个字节,它们的值都是0,相当于db 0,0,0。
db 3 dup (0, 1, 2) ;定义了9个字节,它们是0、1、2、0、1、2、0、1、2,相当于db 0,1,2,0,1,2,0,1,2。
db 3 dup (‘abc’, ‘ABC’) ;定义了18个字节,它们是abcABCabcABCabcABCC,相当于db ‘abc’, ‘ABC’ ,‘abc’ , 'ABC, ‘abc’, ‘ABC’。

mul 指令

mul是乘法指令,使用 mul 做乘法的时候:相乘的两个数:要么都是8位,要么都是16位。

8 位: AL中和 8位寄存器或内存字节单元中;

16 位: AX中和 16 位寄存器或内存字单元中。

;计算100*10
;10010小于255,可以做8位乘法
mov al,100
mov bl,10
mul bl

;结果: (ax)=100003E8H) 
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值