用e命令向内存中写入字符或字符串
e 1000:0 '1' 'a' 'b' 'c' *//写入字符*
e 1000:0 "abcde" 2 'x' "1+2+3=?" *//写入字符串*
N地址单元存放的字节型数据
N地址字单元存放的字型数据——N地址为起始
8086CPU以 段地址:偏移地址的形式操作内存单元
程序中默认在DS寄存器中存放段地址
程序中以[address]的形式表示偏移地址
8086CPU中不允许直接改变段地址寄存器的值
例如:读取100066H地址单元的字节
mov ax,1000
mov ds,ax
mov bl,[66] //解释:mov bl,1000:66
SS和SP分别存放栈的段地址和偏移地址
8086CPU入栈和出栈都是以字为单位操作的
入栈时,栈指针由高地址向低地址移动
出栈时,栈指针由低地址向高地址移动
栈的大小:为16的倍数
支持三种形式
push/pop 寄存器/段地址寄存器/内存单元
mov ax,1000
mov ds,ax
push [0] //mov ss:sp 1000:0
push指令的执行步骤:1)sp -= 2; 2)将ss:sp中的字型数据取出
pop指令的执行步骤: 1)将ss:sp中的字型数据取出;2)sp += 2
注意:Debug中用t命令执行指令时,若修改段地址寄存器SS,则下一条语句会被自动执行。
asume cs:code
code segment
mov ax,0123h
mov bx,0456h
add ax,bx
add ax,ax
mov ax,4c00h
int 21h
code ends
end
汇编语言的源程序包含两种指令:
1)伪指令——编译器执行
a)定义程序段
xxxx segment
…
xxxx ends
b)结束编译:end
c)关联段地址寄存器:asume
asume cs:code,ds:data,ss:stack
2)汇编指令——CPU执行
程序返回指令:
mov ax,4c00h
int 21h
执行程序载入之后:
1)CX寄存器中存放的值表示程序的大小
2)CS:IP存放程序执行地址
3)DS寄存器存放PSP的地址,PSP区大小为256个字节,PSP之后紧跟代码区
即 CS:IP = DS + 10h
[bx]表示一个地址单元,偏移放在bx寄存器中
mov ax,[bx] //(ax) = ((ds)*16+(bx))
计算 2^10
mov ax,2
mov cx,9
lp: add ax,ax
loop lp
p:可以执行到循环结束
g 偏移地址:相当于断点执行到ds:偏移地址的地方
debug中:mov ax,[0] 相当于 mov ax,ds:0
masm编译:mov ax,[0] 相当与 mov ax,0
访问ds:0处的内存单元应写成:
mov bx,0
mov ax,[bx]
或者
mov ax,ds:[0]
mov ax,20h
mov es,ax
mov es:[0h],ax
出现在访问内存单元的指令中,用于显示的表示内存单元段地址的“ds”,“cs”,“ss”,“es”,在汇编语言中称之为段前缀。
1)dw 0123h,0456h,0789h
dw(define word)的含义是定义字型数据
db(define byte)的含义时定义字节型数据
2)代码结束时end后面加标号,则指明代码入口
assume cs:code
code segment
....
数据
....
start: ....
....
code ends
end start //指明代码入口在start处
1)and指令:按位与指令——将相应位置零
mov al,01000011B
and al,01110001B
执行后:al=01000001B
2)or指令:按位或指令——将相应位置一
mov al,01000011B
or al,01110001B
执行后:al=01110011B
[bx+idata]表示一个地址单元,地址单元的段地址放在ds中,偏移地址为(bx)+idata。
[bx+idata]还常表示为:idata[bx]或[bx].idata
mov ax,[bx+200]
mov ax,200[bx]
mov ax,[bx].200
都表示读取(ds)*16+(bx)+200地址字单元的内容到寄存器ax中
si和di是8086CPU中功能和bx相近的两个寄存器,si和di不能分成两个8位寄存器来使用
mov ax,[bx]
mov ax,[si]
mov ax,[di]
mov ax,[bx+si]也可以表示为:mov ax,[bx][si]
mov ax,[bx+di]也可以表示为:mov ax,[bx][di]
[bx+si+idata]和[bx+di+idata]用法相同
mov ax,[bx+si+200]
mov ax,[200+bx+si]
mov ax,200[bx][si]
mov ax,[bx].200[si]
mov ax,[bx][si].200
以上语句表示同一个意思
1)处理的数据放在什么地方
2)要处理的数据有多长
1)在8086CPU中只有这4个寄存器可以放在[…]中进行内存的寻址
2)在[…]中这4个寄存器可以单独出现,或只能以4种组合方式出现:[bx+si],[bx+di],[bp+si],[bp+di]。
3)只要在[…]中出现bp,而没有显示的给出段地址,则默认段地址存放在ss中。其它默认在ds中。
在指令执行前,要处理的数据可以在3个地方:
1)CPU内部
2)内存
3)端口
1)立即数
2)寄存器
3)段地址+地址偏移
1)通过寄存器名指明要处理的数据的长度
a)字操作
mov ax,ds:[0]
b)字节操作
mov al,ds:[0]
2)用操作符word ptr或byte ptr 显式的指明要操作的数据长度
a)字操作
mov word ptr ds:[0],1
inc word ptr ds:[0]
add word ptr ds:[2],2
b)字节操作
mov byte ptr ds:[0],1
inc byte ptr ds:[0]
add byte ptr ds:[2],2
格式:
1)div 寄存器
2)div 内存单元
概念:
1)除数有8位和16位两种,对应被除数有16位和32位两种
2)如果除数为8位,则被除数为16位,位于ax中
3)如果除数位16位,则被除数位32位,低16位在ax中,高16位在dx中
4)如果除数为8位,则商在al中,余数在ah中
5)如果除数位16位,则商在ax中,余数在dx中
例子:
div byte ptr ds:[0]
// al = ax / (ds:[0])
// ah = ax % (ds:[0])
div word ptr ds:[0]
// ax = ((dx<<16)+ax) / (ds:[0])
// dx = ((dx<<16)+ax) % (ds:[0])
div bl
// al = ax / bl
// ah = ax % bl
div bx
// ax = ((dx*10000h) + ax) / bx
// dx = ((dx*10000h) + ax) % bx
dd定义双字类型数据,占32位
dup和db,dw,dd等数据定义伪指令一起配合使用,用来进行数据的重复。
格式:db/dw/dd 重复的个数 dup(重复的数据)
db 3 dup(0) //db 0,0,0
db 3 dup(0,1,2) //db 0,1,2,0,1,2,0,1,2
db 3 dup(‘ab’,‘AB’) //db ‘abABabABabAB’
1)修改IP或同时修改CS:IP的指令统称为转移指令
2)转移行为分类
a)段内转移,只修改IP:jmp ax
a.1)短转移:IP的修改范围:-128~127
a.2)近转移:IP的修改范围:-32768~32767
b)段间转移,同时修改CS:IP:jmp 1000:0
3)8086CPU转移指令分类
a)无条件转移(如jmp)
b)条件转移
c)循环指令(如loop)
d)过程
e)中断
offset的功能是取得标号的偏移地址
code segment
start: mov ax,offset start ;相当于mov ax 0
s: mov ax,offset s ;相当于mov ax 3
code ends
实现段内转移,将程序转到标号处执行指令,对IP的修改范围为-128~127
jmp short 标号的含义:IP = IP + 8位位移
1)8位位移 = 标号处的地址 - jmp指令后第一个字节的地址
2)short指出位移为8位,范围为-128~127
3)8位位移有编译器在编译时算出
jmp near ptr 标号:IP = IP + 16位位移
assume cs:code
code segment
start: mov ax,0
jmp short s
add ax,1
s: inc ax
code end
end start
段间转移,指明用标号的段地址和偏移修改CS和IP
IP = 16位reg
1)jmp word ptr 内存单元 (段内转移)
2)jmp dword ptr 内存的那元 (段间转移)
CS = 高字,IP = 低字
jcxz位有条件转移指令,所有的有条件转移都是短转移,在对应机器码中包含的是转移位移,而不是目标地址。对IP修改范围为:-128~127。
格式:jcxz 标号
解释:如果(CX) = 0,则转移到标号处执行
8086CPU中,内存B8000H~B8FFFH共32KB,为80x25(行x列)彩色字符模式的显示缓冲区。在80x25彩色字符模式下,可以显示25行,每行80个字符,每个字符2个字节,低字节存放ASCII码,高字节存放属性,属性定义如下:
显示缓冲区分为8页,每页4KB(约4000个字节),显示器可以显示任意一页的内容,通常情况显示第0页的内容,即B8000H~B8F9FH的4000个字节会显示在屏幕上。第1页缓冲区中:
000~09F对应显示器上的第1行
0A0~13F对应显示器上的第2行
140~1DF对应显示器上的第3行
…
F00~F9F对应显示器上的第25行
以下代码在屏幕中央显示绿底红字:
assume cs:code,ds:data
data segment
db 'welcome to masm!'
data ends
code segment
start: mov ax,data
mov ds,ax
mov ax,0b800h ;显示段地址
mov es,ax
mov bx,780h ;中间行
mov si,0 ;列数
mov cx,16 ;循环次数
s: mov al,[si] ;字符
mov ah,24h ;字符属性
mov dx,si
add si,si
mov es:[bx].72[si],ax
mov si,dx
inc si
loop s
mov ax,4c00h
int 21h
code ends
end start
ret用栈中的数据修改IP的内容,相当于:
pop ip
retf用栈中的数据修改IP和CS的内容,相当于:
pop ip
pop cs
call指令执行时,进行两步操作:
1)将IP或CS和IP压栈
2)转移
格式:
call 标号
解释:
1)push ip
2)jmp near ptr 标号
格式:
call far ptr 标号
解释:
push cs
push ip
jmp far ptr 标号
格式:
call 16为寄存器
解释:
push ip
jmp 16为寄存器
1)call word ptr 内存单元
解释:
push ip
jmp word ptr 内存单元
2)call dword ptr 内存单元
push cs
push ip
jmp dword ptr 内存单元
mul即乘法指令
注意:相乘的两个数,要么都是8位,要么都是16位
格式:
1)mul 寄存器
2)mul byte/word ptr 内存地址
解释:
8位相乘:一个乘数在al中,结果在ax中
16位相乘:一个乘数在ax中,结果高16位在dx中,低16位在ax中
编写子程序的标准框架:
子程序入口:子程序中要用的寄存器入栈
子程序内容
子程序中的寄存器出栈
返回(ret/retf)
8086CPU标识寄存器共使用9位标识位
标志寄存器中存储的信息常称为程序状态字(PSW)
第6位。相关指令执行后,结果为0,zf=1;结果为1,zf=0
第2位。相关指令执行后,结果中1的个数为偶数,PF=1;1的个数为技术,PF=0。
第7位。相关指令执行后,结果为负数,SF=1;否则,SF=0
第0位。在进行无符号数运算时,记录了最高有效位向更高位的进位(加法时)或借位(减法时)结果
第11位。对有符号数的运算而言
带进位加法指令,利用CF位。
带节为减法指令,利用CF位。
sbb ax,bx ;(ax) = (ax) - (bx) - CF
比较指令。操作数1-操作数二,不保存结果,只影响标志位。
格式:cmp 操作数1,操作数2
常结合cmp指令一起使用。分为两种
1)无符号数的比较结果
b——below,a——above
2)有符号数的比较结果
1)DF标志位的修改
cld //DF = 0 在串传送指令中si和di递增
std //DF = 1 在串传送指令中si和di递减
2)串传送指令
rep movsb //传送字节
//((es)*16+di) = ((ds)*16+si)
//inc di //DF=0
//inc si
或
//dec di //DF=1
//dec si
rep movsw //传送字,原理和 movsb一样
3)实例
mov ax,dstdata
mov es,ax
mov di,0 //目的数据地址
mov ax,srcdata
mov ds,ax
mov si,0 //源数据数据地址
cld //DF=0,si和di递增
mov cx,8 //传送8个数据
rep movsb
标志寄存器压栈和出栈
编程实现把以0结尾的字符串中的小写字母全部转换为大写,其余字符不变。程序如下:
;功能:将以0结尾的字符串中的小写字符变为大写字母
;参数:ds:si指向字符串的首地址
letterc:
push si
;以上位寄存器保护过程
beg:
cmp byte ptr [si],0
je finish
cmp byte ptr [si],'a'
jb next ;小于a则进入下一轮判断
cmp byte ptr [si],'z'
ja next ;大于z则进入下一轮判断
and byte ptr [si],11011111B ;小写转换为大写
next:
inc si
jmp short beg
;以下位寄存器恢复过程
finish:
pop si
ret
8086CPU内部发生四种情况,将产生内中断
序号, , 事件, 中断类型码, 备注
1, , 除法错误 , , 0 , ,,比如div溢出
2, , 单步执行 , , 1
3, , 执行into指令, 4,
4, , 执行int指令, ,,,,, int n
8086CPU中断向量表指定放在0地址处,在0000:0000~0000:03ff的1024个单元中存放中断向量表。
一个表项占两个字,即4个字节;高地址存放中断服务程序的段地址,低地址存放中断服务程序地址的偏移地址。
一般情况,系统把具有一定功能的程序作为中断处理程序共给应用程序调用,编程时可通过int指令调用这些程序。
mov ax,data
mov ds,ax
mov dx,0 ;ds:dx为显示字符的首地址
mov ah,9
int 21h
mov ax,4c00h
int 21h
以下程序在屏幕2,4,6,8行显示四行诗句
assume cs:code
data segment
db 'welcome to masm!','$'
data ends
code segment
s1:
db 'Good,better,best,','$'
s2:
db 'Never let it rest','$'
s3:
db 'Till good is better','$'
s4:
db 'And better ,best.','$'
s:
dw offset s1,offset s2,offset s3,offset s4
row:
db 2,4,6,8
main:
mov ax,cs
mov ds,ax
mov si,offset s ;显示的行
mov di,offset row
mov cx,4
next:
mov bh,0
mov dh,[di]
mov dl,36
mov ah,2
int 10h ;置光标
mov dx,[si]
mov ah,9
int 21h
add si,2
inc di
loop next
mov bh,0
mov dh,24
mov dl,0
mov ah,2
int 10h
mov ax,4c00h
int 21h
code ends
end main
在PC机系统中,CPU最多可以定位64KB个端口,端口号为0~65535。
端口的读写指令:in和out
注意:in和out指令中只能用ax和al来进行数据的读写
in al,30h
out 30h,al
1)包含一个实时钟和一个有128单元的ram存储器
2)该芯片有电池供电。关机后实时钟仍正常工作,ram中信息 不丢失
3)128字节的ram中,实时钟占用0~0dh单元来保存时间信息。
4)芯片内部有两个端口70h和71h
5)70h为地址端口,存放访问的cmos ram单元的地址;71为数据端口,存放读写的数据。对CMOS RAM的读写分为两步:
a)将地址送入端口70h:out 70h,al
b)从端口71h读写数据:in al,71h
shl是逻辑左移指令,它的功能是:
1)把数据向左移动
2)把最后移出的一位放入CF钟
3)最低位用0补充
mov al,01000000b
shl al,1
执行后:(al)=10000000b,(CF)=0
注意:如果移动的位数大于1,则必须放在cl中,如:
mov cl,3
mov al,10100001b
shl al,cl
执行后:(al)=00001000b,(CF)=1
shr是逻辑右移指令,原理和shl一样
CPU通过端口和外部设备进行联系。
在PC系统中,外中断源一共有两类:
1)可屏蔽中断
IF=1,响应中断;IF=0,不响应中断。
sti:设置IF=1
cli:设置IF=0
2)不可屏蔽中断
不可屏蔽中断的中断类型码固定为2。
几乎所有由外设引起的中断,都是可屏蔽中断。
键盘上部分按键的扫描码(通码):
断码 = 通码+80H
键盘按下按键时,将响应按键的通码送到端口寄存器60h。
字符键:送入内存的BIOS键盘缓冲区,共15个字节
控制键:送入0040:17地址单元,含义如下: