3.1 内存中字的存储
CPU中16位寄存器存储一个字:高8位在高字节,低8位在低字节。
内存中,内存单元也是字节单元,所以一个内存单元存放一个字节也就是8bit。
用此图举例。
存放的数据4E20 h存放在地址0处。其中高位字节在地址1处,低位字节在地址0处。
存放的数据0012 h是一样的。0012h存放在地址2处,高字节为00h,低字节为12h。
将起始位置为N的字单元简称为N地址字单元。
字单元:存放一个字型数据,就按照上述例子存储。
问题 3.1
(1) 20H; 地址单元应该是一个字节。
(2) 4E20H,字型数据应该是一个字单元。
(3) 12H
(4) 0012H
(5) 124EH
3.2 DS 和 [address]
CPU操作内存中的数据时。
需要指定 内存操作的 段地址:偏移地址。
所以将段地址放入ds
将偏移地址用中括号括住。
注意:8086CPU ds不能直接被赋数,要通过通用寄存器来获取.
例如:读取1000h单元的内容
mov bx, 1000h
mov ds, bx
mov al, [0]
通过bx通用寄存器将段地址存放在ds中,在中括号中使用偏移地址就可以。
问题 3.2
mov bx,1000h
mov ds,bx
mov [0],al
3.3 字的传送
因为8086CPU数据线为16根,所以能一次传16bit,2个Byte,一个字。
mov bx,1000h
mov ds,bx
mov ax,[0]
mov [0],cx
问题 3.3
ax bx cx ds
1000h
1000h 1000h
1123h 1000h
1123h 6622h 1000h
1123h 6622h 2211h 1000h
1123h 8833h 2211h 1000h
1123h 8833h 8833h 1000h
问题 3.4
mov ax,1000h ; ax = 1000h
mov ds,ax ; ds = 1000h
mov ax,11316 ; ax = 2c34h
mov [0],ax ; 1000:0000 = 2c34h
mov bx,[0] ; bx = 2c34h
sub bx,[2] ; bx = 1b12h
mov [2],bx ; 1000:0002 = 1b12h
3.4 mov、add、sub 指令
推测:
mov 段寄存器,寄存器
mov 寄存器,段寄存器 ;寄存器中得到的是段寄存器中的值
;;;;;;;;;;;;;;;;;;;;;
mov 内存单元,寄存器
mov 内存单元,段寄存器
mov 段寄存器,内存单元
总结下mov能进行的操作:
数据,寄存器,内存单元,段寄存器:
寄存器,数据
寄存器,寄存器
寄存器,内存单元
寄存器,段寄存器
内存单元,寄存器
内存单元,段寄存器
段寄存器,寄存器
段寄存器,内存单元
add 和 sub 同 mov 一样都有两个操作对象。
可以进行操作的是 :
数据,寄存器,内存单元。
add 和 sub 两者能进行的操作是相同的:
寄存器,数据
寄存器,寄存器
寄存器,内存单元
内存单元,寄存器
段寄存器不可以出现在算术指令中
3.5 数据段
根据需要,将一组内存单元定义为一个段。将一组长度为N(N<= 64KB)地址连续,起始地址为16倍数的内存单元当作专门存储数据的内存空间。
问题 3.5
mov bx, 1000h
mov ds,bx
mov ax,[0]
add ax,[2]
add ax,[4]
3.1-3.5 小结
检测点 3.1
mov ax,1
mov ds,ax ;ds = 0001h ; 后续都是 0001:XXXX
mov ax,[0000] ;ax = 2662h
mov bx,[0001] ;bx = e626h
mov ax,bx ;ax = e626h
mov ax,[0000] ;ax = 2662h
mov ,bx[0002] ;bx = D6E6h
add ax,bx ;ax = FD48h
add ax,[0004] ;ax = 2C14h
mov ax,0 ;ax = 0000h
mov al,[0002] ;ax = 00E6h
mov bx,0 ;bx = 0000h
mov bl,[000C] ;bx = 0026h
add al,bl ;ax = 000Ch
mov ax,6622h
jmp 0ff0:0100
mov ax,2000h
mov ds,ax
mov ax,[0008]
mov ax,[0002]
3.6 栈
LIFO (last in first out) 后进先出。
3.7 CPU提供的栈机制
两个最基本操作:push,pop
8086CPU的入栈和出栈都是以字为单位。
8086CPU中有两个寄存器SS和寄存器SP。
任意时刻: SS:SP指向栈顶的元素。
push ax
- SP = SP-2,SS:SP指向当前栈顶前面的单元,以当前前面的单元为新的栈顶
- 将ax中的内容送到SS:SP指向的内存单元出。此时SS:SP指向新的栈顶。
pop ax 操作相反
- 将SS:SP指向的数据pop到ax中。
- SP = SP+2
问题 3.6
;因为 栈操作的push操作是从大向小压栈。所以压入第一个数据时要 SP-2,也就是1000:000E。所以,SP = 000E+2 = 0010,所以SP应当为 0010h。
3.8 栈顶超界的问题
8086CPU不能保证对栈的操作不会越界,所以全凭写程序的人自己操心。
3.9 push 、pop 指令
两者可以进行的操作:
- push/pop 寄存器/段寄存器/内存单元
问题 3.7
mov ax,1000h
mov ss,ax
mov sp,0001h ;SS:SP已经组装完毕
push ax ;地址1000Fh
push bx ;地址1000Dh
push ds ;地址1000Bh
问题 3.8
;(1)
mov ax, 1000h
mov ss, ax
mov sp, 0001h
;栈已经组装好
;(2)
mov ax,001Ah
mov bx,001Bh
;(3)
push ax
push bx
;(4)
mov ax,0
mov bx,0
;(5)
pop bx
pop ax
问题 3.9
;(1)
mov ax,1000h
mov ss,ax
mov sp,0001h
;(2)
mov ax,001Ah
mov bx,001Bh
;(3)
push ax
push bx
pop ax
pop bx
问题 3.10
;用栈
mov ax,1000h
mov bx,ss
mov cx,sp
mov ss,ax
mov sp,0002h
mov ax,2266h
push ax
mov ss,bx
mov cx,cx
3.10 栈段
问题3.11
;因为10000h-1FFFFh这段矿建当作栈段,所以栈顶从最大+2开始 (因为push时,SP要先减2,得到1FFFFh 所以减去之前为加2),也就是SP=1FFFFh+2=20001h
所以此时的SP=20001h
问题 3.12
因为在压栈的时候是 SP-2 而 SP的范围是从 0000h~FFFFh,也就是说是2^16 Byte 也就是64KB。
检测点 3.2
mov ax,2000h
mov ss,ax
mov sp,0011h
mov ax,1000h
mov ss,ax
mov sp,0000h
实验 2 用机器指令和汇编指令编程
注意这里的SS和SP一起变化的,尽管是单步执行的情况下也是一同改变的。
目前只知道:Debug的T命令在执行修改寄存器SS的指令时,下一条指令也紧接着被执行。
2. 实验任务
ax = c0ea
ax = c0fc
bx = 30f0
bx = 6021
sp = 00FE ;2200:00FE C0FC
sp = 00FC ;2200:00FC 6021
sp = 00FE ;ax = 6021
sp = 0100 ;bx = C0FC
sp = 00FE 2200:00FE 30F0
sp = 00FC 2200:00FC 2F31