真值: 用+、-分别表示正、负的数称为真值
原码:原码的最高位表示真值的数符,其余位为数值位,且与真值的数值位相同,必要时在数值位前加上前0。
反码:正数的反码=原码;负数的反码=原码数值位取反。
补码:当一个数为正数,则其补码就是该数本身;为负数,则其补码等于模值与该数绝对值之差。
补码的加减法运算:补码加法规则 [X+Y]补=[X]补+[Y]补;补码减法规则:[X-Y]补=[X]补+[-Y]补
接口的功能
(1)执行CPU命令
接口电路对CPU发来的命令信息(在命令寄存器中,称为命令口)进行识别和分析,分解成若干个控制信号,传送到I/O设备,使其产生具体的操作。
CPU不是直接把命令送到被控对象,而是通过接口电路进行控制。
(2)返回外设状态信息
接口执行CPU的命令后,将整个过程的状态存在接口的状态寄存器(状态口)中,供CPU读取。状态是:“忙”,“闲”,“就绪”,“错”等。
(3)数据缓冲能力
避免因速度的差异而丢失数据。接口中一般都有数据缓冲寄存器,称为数据口。数据缓冲器分为输入和输出缓冲器两种。
(4)信号转换功能
由于外设提供或需要的信号与CPU的总线不兼容,因此信号必须转换。
(5)设备选择功能(大型的部门)
微机系统中一般有多个外设,一个外设中也有多个端口,接口中必须有端口选择能力。
(6)数据宽度与数据格式转换的功能
如:并/串转换、串/并转换等。
接口的组成
(1)接口逻辑电路
包括:命令寄存器,状态寄存器,数据缓冲寄存器(数据收发速率不匹配时)。
可编程大规模集成芯片中都包含这些电路。
(2)端口地址译码电路
作用是进行设备选择。需由用户自行设计。
(3)附加电路
需根据接口不同的任务和功能添加的功能模块电路。
接口的软件编程
(1)初始化程序段
对可编程接口芯片进行初始化,完成设置。
(2)传送方式处理程序段
传送方式的处理。如:查询,中断,DMA等传送过程中的处理程序。
(3)主控程序段
完成接口任务的程序段。
(4)程序终止与退出程序段
包括程序结束前对接口中硬件的保护程序段。
(5)配置段
包括人-机对话,菜单设计等内容。
CPU与接口交换数据的方式
查询方式,中断方式, DMA方式
接口电路的分析与设计基本方法(如何当好中层干部?)
(1)两侧分析法
凡是接口都有两侧,一侧是CPU,另一侧是外设。
对CPU一侧就是三总线,因此分析比较容易主要搞清楚是什么类型的CPU以及数据总线、地址总线的宽度和控制线的逻辑定义,时序关系。
对外设一侧情况很复杂,这是因为被控对象外设种类繁多,所提供的信号线五花八门;其逻辑定义,时序关系,电平高低差异甚大。要搞清两点:一是外设的信号引脚的功能定义和逻辑定义(外部表现),二是了解被控外设的工作过程(内部原理)。
(2)硬软结合法
指令执行部件(EU)
功能:负责指令译码、数据运算和指令执行(控制和执行指令)
组成:算术逻辑运算部件ALU、EU单元控制系统、寄存器(所有的寄存器和数据线都是16位的)
指令执行的两个主要阶段:取指和执行
取指:EU不直接同外部总线相连,它从总线接口单元BIU的指令队列中获取指令
执行:执行指令时,若需要访问存储器或外部设备,EU就向BIU发出操作请求,由BIU完成相应的操作。
总线接口部件(BIU)
功能:负责管理与系统总线的接口,负责对存储器和外设访问(预取指令和数据,总线 操作,信息传递)
组成:指令队列、指令指针寄存器、地址加法器和总线控制逻辑
8个16位寄存器分别为AX、BX、CX、DX、SP、BP、SI和DI,标志寄存器为FLAGS。
指令预取
控制寄存器
特别说明:堆栈的两种访问方式:
随机访问方式:用BP寄存器来指示随机访问地址是内存!
先进后出访问方式:用SP寄存器来表示栈顶也是堆栈!
寄存器与存储器的比较:
寄存器 | 存储器 |
---|---|
在CPU内部 ,访问速度快 ,容量小,成本高 ,用名字表示,没有地址 | 在CPU外部,访问速度慢,容量大,成本低用地址表示,地址可用各种方式形成 |
标志寄存器 ( FLAGS/PSW )
标志寄存器的格式以及各位的含义
状态标志——记录程序运行结果的状态信息
最基本的标志,有6个
例1:00111010+01111100= 10110110
最高位无进位, CF=0
例2:10101010+01111100 = [1]00100110
最高位有进位,CF=1
例1:00111010+01111100 = 10110110
超出表达范围,OF=1
例2:10101010+01111100 = [1]00100110
未超出表达范围,OF=0
进位和溢出的区别
- CF反映无符号整数运算结果是否超出范围
有进位,加上进位或借位后运算结果仍然正确- OF反映有符号整数运算结果是否超出范围
有溢出,运算结果已经不正确- 处理器按照无符号整数求得结果
设置进位标志CF
设置溢出标志OF- 程序员决定
操作数是无符号数,关心进位
操作数是有符号数,注意溢出
溢出标志的判断
- 处理器硬件判断规则
最高位和次高位同时有进位或同时无进位,无溢出;最高位和次高位进位状态不同,有溢出- 人工判断的简单规则
只有当两个相同符号数相加(含两个不同符号数相减),而运算结果的符号与原数据符号相反时,产生溢出;其他情况下,不会产生溢出
例1:00111010+01111100 = 10110110
结果不是0,ZF=0
例2:10000100+01111100 = [1]00000000
结果是0,ZF=1
例1:00111010+01111100 = 10110110
最高位为1,SF=1
例2:10000100+01111100 = [1]00000000
最高位为0,SF=0
例1:00111010+01111100 = 10110110
“1”的个数为5个,PF=0
例2:10000100+01111100 = [1]00000000
“1”的个数为0个,PF=1
控制标志
方向标志 DF(Direction Flag)
仅用于串操作指令,控制地址的变化方向
设置DF=0,每次串操作后的存储器地址就自动增加,即从低地址向高地址处理数据串
设置DF=1,每次串操作后的存储器地址就自动减少,即从高地址向低地址处理数据串
执行CLD指令设置DF=0
执行STD指令设置DF=1
中断允许标志IF(Interrupt-enable Flag)
追踪标志TF(Trace Flag)
段寄存器
段是安排相关代码或数据的主存区域
段寄存器表明段在主存中的位置
3个16位段寄存器:CS DS SS
存储器的组织采用分段方式,20位的物理地址由16位的段地址和16位的偏移地址形成,每个段的最大寻址空间为64KB; 段地址必须是16的倍数,即末尾4位必须为0。
字单元由两个字节单元组成,其地址采用它的低地址来表示。
字存入存储器:低位字节存入低地址单元,高位字节存入高地址单元。(小端存储)
因为地址一定是16位的,所以(0004H)对应的字内容是5678H
(5678H)可能是字单位或者字节单位,对应的值可能是1EH或者2F1EH
段地址和偏移地址
段地址:表示一个段的开始
偏移地址:在段内相对于段起始地址的偏移值
优点: 允许程序在存储器内重定位;有利于程序和数据的分离。
物理地址的形成
物理地址:每一个存储单元有一个唯一的20位地址
表示范围:00000H~FFFFFH 。
物理地址形成:段地址左移4位再加上偏移地址值
存储器的逻辑地址与物理地址
逻辑地址的形式:指令操作数,指令间的相对地址
物理地址:MEM的绝对地址
逻辑地址到物理地址的转换过程因CPU ARCH的不同而不同
存储器的分段:
20 根地址线: 地址范围 00000H ~ FFFFFH (1MB)
机器字长16位:仅能表示地址范围 0000H ~ FFFFH (64KB)
小段:
小段的首地址 小段的尾地址
00000 H ~ 0000F H
00010 H ~ 0001F H
00020 H ~ 0002F H
…
FFFF0 H ~ FFFFF H
每16个字节为一小段,共有64K个小段
段起始地址:小段首地址
段地址与段寄存器
实模式下,在8086~Pentium微处理机中,代码段的段地址放在CS中;数据段的段地址放在DS中;堆栈段的段地址存放在SS中;附加段的段地址存放在ES中。
将CS,DS,SS,ES称为段寄存器
各段在存储器中的分配是由操作系统负责的。一般情况下,根据需求量分配。 注意:只有CS段寄存器是OS分配的,应用程序可读但不可写,其它的段寄存器都可以被修改。
隐含段和偏移寄存器
8086~Pentium微处理机中,段寄存器和偏移寄存器组合有一定规则。
段 | 偏移 | 主要用途 |
---|---|---|
CS | IP | 指令寻址 |
SS | SP或BP | 堆栈寻址 |
DS | BX,DI,SI或16位数 | 数据寻址 |
ES | 串指令 | 目标串寻址 |
注意:当BX/BP与SI/DI组合作为偏移地址时,默认的段寄存器是BX/BP所在段的寄存器,而不是SI/DI所在段的寄存器。
例1:(DS) = 2100H, (BX) = 0500H
物理地址 = 21000H + 0500H = 21500H
例2:(CS) = 3000H, (IP) = 1000H
物理地址 = 30000H + 1000H = 31000H
例3:(SS) = 1000H, (SP) = 0010H
物理地址 = 10000H + 0010H = 10010H
例4:(DS) = 3100H, (SI) = 1000H
物理地址 = 31000H + 1000H = 32000H
按照小段存储模式,低位字节放在低地址,高位字节放在高地址。且按照低地址的位置表示存储位置。故存储情况如下图所示:
30022H 字节单元
内容 : AB H
30024H 字节单元
内容 : EF H
30021H 字单元
内容 : AB34 H
30022H 字单元
内容 : CDAB H
段地址和偏移地址为3017H:000AH的存储单元的物理地址= 30170H+000AH =3017AH
段地址和偏移地址为3015H:002AH的存储单元的物理地址= 30150H+002AH =3017AH
段地址和偏移地址为3010H:007AH的存储单元的物理地址= 30100H+007AH =3017AH
物理地址=0A7F00H+2B40H=0AAA40H
寻址方式
为取得操作数或指令地址所使用的方法
(1)操作数包含在指令中——立即数寻址
(2)操作数在CPU的内部寄存器中——寄存器寻址
(3)操作数在存储器中 ——存储器寻址
MOV AX,BX
(1) 段寄存器的默认和超越
访问存储器的方式 | 默认 | 可超越 | 偏移地址 |
---|---|---|---|
取指令 | CS | 无 | IP |
堆栈操作 | SS | 无 | SP |
一般数据访问 | DS | CS、ES、SS、FS、GS | 有效地址EA |
一般数据访问 | SS | CS、ES、SS、FS、GS | 有效地址EA |
串操作的源操作数 | DS | CS、ES、SS、FS、GS | SI |
串操作的目的操作数 | ES | 无 | DI |
(2) 偏移地址的组成
16位有效地址
EA=基址寄存器+变址寄存器+位移量
基址寄存器:BX或BP
变址寄存器:SI或DI
位移量:8或16位有符号值
一般情况下,由基址寄存器决定哪个段寄存器作为段指针(如果不使用段超越越前缀)
(3) 存储器寻址的5种方式
试比较下列指令中源操作数的寻址方式(VARW是内存字变量):
MOV AX, 1234H MOV AX, [1234H] ;前者是立即寻址,后者是直接寻址
MOV AX, VARW MOV AX, [VARW] ;两者是等效的,均为直接寻址
1.直接地址可用数值表示,包括在[ ]之中,也可以用变量表示,例如:MOV AL,VALUE;这里,VALUE为变量,变量是有属性的,它由数据段中定义数据的伪指令确定(伪指令将在第4章介绍)。
2. 若操作数在代码段、堆栈段或附加段中,则应在操作数地址之前使用前缀指出段寄存器名,这种前缀称为段超越前缀.段超越前缀也可以用于其他存储器寻址方式中,以使得给定的段寄存器取代默认的段寄存器。
MOV AL,ES:[2000H]; 将ES段2000H单元的内容传入AL中
3. 直接寻址方式适合于处理存储器的单个单元。IBM-PC机中为了避免指令字的长度过长,规定双操作数指令除立即寻址方式之外必须有一个操作数使用寄存器或段寄存器,这就是一个变量常常先要送到寄存器中去的原因
EA= (BX)/ (BP) / (SI) / (DI)
PA=16*(DS) + (BX)/(SI)/(DI)
PA=16*(SS)+BP
有效地址=(BX)/(BP)/(SI)/(DI) + 8/16 位移量
例子:
MOV AL, [BP][80H]
MOV AL,[BP+80H]
MOV AX, ARRAY1[SI]
MOV ARRAY2[DI],AX
有效地址=(BX)/(BP) + (SI)/(DI)
MOV AX, [BX][BP] 错误
MOV AX, [SI][DI] 错误
有效地址= (BX)/(BP)+ (SI)/(DI) +8/16位位移量。
例: JMP NEAR PTR NEXT; 近转移 -32768 ~ +32767
汇编时,位移量为16位
JMP SHORT NEXT; 短转移 -128 ~ +127
汇编时,位移量为8位
例: TABLE = 20A1H (BX) = 1256H (SI) = 528FH (DS) = 2000H (232F7H) = 3280H (264E5H)= 2450H
JMP BX ; (IP)=1256H
JMP TABLE[BX]
JMP WORD PTR TABLE[BX] ; (IP)=3280H
JMP [BX][SI]
JMP WORD PTR [BX][SI] ; (IP)=2450H
JMP 1234H:5678H ;
(CS)=1234H ,(IP)=5678H
1、现有(DS)=2000H,(BX)=0100H,(SI)=0002H,(20100)=12H,(20101)=34H,(20102)=56H,(20103)=78H,(21200)=2AH,(21201)=4CH,(21202)=0B7H,(21203)=65H,试说明下面各条指令执行后AX寄存器的内容。
(1)MOV AX,1200H
(2)MOV AX,BX
(3)MOV AX,[1200H]
(4)MOV AX,[BX]
(5)MOV AX,1100[BX]
(6)MOV AX,[BX][SI]
(7)MOV AX,1100[BX][SI]
Answer:
2、假设(DS)=2000H,(ES)=2100H,(SS)=1500H,(SI)=00A0H,(BX)=0100H,(BP)=0010H,数据段中的变量名VAL的偏移地址值为0050H,试指出下列源操作数的寻址方式试什么?其物理地址值是什么?
(1)MOV AX,0BAH
(2)MOV AX,[100H]
(3)MOV AX,[BX]
(4)MOV AX,[BP]
(5)MOV AX,[BX+10]
(6)MOV AX,[BX][SI]
(7)MOV AX,BX
(8)MOV AX,VAL
(9)MOV AX,ES: [BX]
(10)MOV AX, [SI]
(11)MOV AX,VAL [BX]
(12)MOV AX,VAL [BX][SI]
Answer :
汇编语句格式
[名字:] 操作码 [操作数[,操作数]][;注释]
[名字:]伪操作码 [操作数[,操作数]][;注释]
[名字]
:由用户按一定规则定义的标识符
组成:英文字母、数字、特殊符号
形式:标号和变量;
[;注释]
: 语句的说明部分
[操作码]
:含义:指明操作的性质或功能。
书写规则:操作码与操作数之间用空格分开
[操作数]
: 含义:指定参与操作的数据。
个数:一般指令,1个或2个,也可以没有;
伪指令和宏指令,可以有多个。
书写规则:操作数多于1个时,操作数之间用
逗号分开
伪指令的功能
data segment; 定义数据段
...
data ends
stack segment; 定义堆栈段
...
stack ends
code segment; 定义代码段
assume cs:code, ds:data, ss:stack
start:
mov ax,data
mov ds,ax;
...
code ends
end start
ASSUME <段寄存器名>:<段名>[,<段寄存器名>:<段名>…]
功能:建立段寄存器与段的缺省关系
结束
END(S) [ label ]
数据的定义和存储器的分配
[变量] 助记符 操作数[,操作数,…][;注释]
助记符:DB DW DD DF DQ(64位) DT(80位)
DB: 定义字节
DW:定义字
DD: 定义双字
例:操作数用复制操作符DUP,表示操作数重复若干次
VAR DB 100 DUP (?) # 占100个空位置
DB 2 DUP (0,2 DUP(1,2),3) # 0212302123
PAR1 DB 100,20H
PAR2 DW 300H,400H
ADDR_TABL1 DW PAR1,PAR2 ;存放偏移地址16位
ADDR_TABL2 DD PAR1,PAR2 ;存放偏移和段地址各16位
表达式名 EQU 表达式
ALPHA EQU 9
BETA EQU ALPHA+18
表达式名=表达式
注意:EQU指令不占用内存空间!
如: BUF1 DW 1,2,3
INTT EQU 5
BUF2 DW 4,5,6
那么3和4的地址是连续的!
EQU与=的差异
同一个程序中“=”可以对一个符号重复定义,但EQU不能对同一个符号重复定义
Y1=7
Y1=128 √
Y1 EQU 7
Y1 EQU 128 ×
解除定义伪指令PURGE
格式:PURGE <符号1,符号2,…,符号n>
功能:解除指定符号的定义
例:
Y1 EQU 7
PURGE Y1
Y1 EQU 128
ORG $+8 ; 跳过8个字节的存储区
JNE $+6 ; 转向地址是 JNE 的地址 +6
JMP $+2 ; 转向下一条指令
例:BUF1 DB 1,2,3,4,5
CNT1 EQU $ -BUF1 (常用)
BUF2 DW 1,2,3,4,5
CNT2 EQU ($-BUF2)/2
CNT1、CNT2分别为数组BUF1、BUF2中数据元素的个数
OFFSET / SEG 变量 / 标号
LENGTH 变量
SIZE 变量
例:
ARRAY DW 100 DUP (?)
TABLE DB ‘ABCD’
MOV CX, LENGTH ARRAY ; MOV CX, 100
MOV CX, LENGTH TABLE ; MOV CX, 1
MOV CX, SIZE ARRAY ; MOV CX, 200
MOV CX, SIZE TABLE ; MOV CX, 1
(5) 属性修改的伪指令: PTR
用于暂时改变内存变量或标号的原有属性,但不能修改寄存器的原有属性
格式: 新属性 PTR (旧属性的)表达式
MOV WORD PTR [BX], 5
PTR指令的应用场合
1、有一些指令中,操作数或表达式的属性是不明显
的,需要加以明确,如:
例:CALL DWORD PTR [BX] ;远调用
CALL BYTE PTR [BX] ;段内近调用
2、需要修改操作数或表达式的属性的,如:
例:F1 DW 1234H
MOV AL,BYTE PTR F1 ;AL=34H
例:F2 DB 23H,56H,18H
MOV BX,WORD PTR F2 ;BX=5623H
例如: code segment para ‘code’
1、画图说明下列语句所分配的存储空间及初始化的数据
(1)AA DB ‘BYTE’,12,-12H, 3 DUP(0,?,2 DUP(1,2),?)
(2)BB DW 5 DUP(0,1,2),?,-5,‘BY’, ‘TE’,256H
(2)如下图(注意: 左边为低地址,右边为高地址)
2、假设程序中的数据定义如下:
PARTNO DW ?
PNAME DB 16 DUP(?)
COUNT DD ?
PLENTH EQU $-PARTNO
问PLENTH的值是多少?它表示什么意义?
PLENTH的值为2+16+4=22=16H
表示PARTNO、PNAME、COUNT 这三个变量所占用的字节数的和 (即这段代码之前数据段的长度)
3、请设置一个数据段DATASG,其中定义以下变量
(1)FLD1为字符串变量:‘computer’
(2)FLD2为十进制字节变量:32
(3)FLD3为十六进制字节变量:20
(4)FLD4为二进制字节变量:01011001
(5)FLD5为10个0的字节变量
(6)FLD6为数字的ASCII字符字节变量32654
(7)FLD7为包括5个十进制数的字变量:5,6,7,8,9
(8)FLD8为100个字变量
DATASG SEGMENT
FLD1 db 'computer'
FLD2 db 32
FLD3 db 20H
FLD4 db 01011001B
FLD5 db 10DUP(0)
FLD6 db '32654'
FLD7 dw 5,6,7,8,9
LFD8 dw 100DUP(?)
DATASG ENDS
易错点总结
// 汇编程序:
mov al,'a'
mov ax,'a'
mov ax,'ab'
//执行后的结果
al = 61h
ax = 0061h
ax = 6162h
参考博客
传送指令:MOV DST, SRC
执行操作:(DST)<-(SRC)
注意:
- DST,RST 不能同时为段寄存器
- 立即数不能直接送至段寄存器
- 不能使用AX、CX、DX存放EA
- DST不能是立即数和CS (CS和IP寄存器的修改只能使用JMP XX:YY指令进行修改,不能用MOV指令修改。通常来说,CS都是由OS分配的,应用程序不能对其进行修改。)
- DST 和SRC不能同时为存储器寻址,因为两者的位宽是否匹配不确定
- 不影响标志位(对所有的数据传输指令而言)
进栈指令:PUSH SRC
执行操作: SP <- SP – 2 ; (SP+1), (SP) <-(SRC)
出栈指令:POP DST
执行操作:(DST) <- (SP+1), (SP) ; SP <- SP + 2
堆栈:“先进后出”的存储区。段地址存放在SS中,SP在任何时候都指向栈顶,进出栈后自动修改SP
堆栈用于保存子程序返回地址和断点地址以及主程序通用寄存器内容的保护和恢复
因为堆栈遵从“后进先出”原则,在保存寄存器和恢复寄存器的内容时要按照相反的顺序执行一组压入和弹出指令。
8086/8088堆栈操作都是字操作,不允许对字节操作。例如:PUSH AH不是正确指令。
注意
- 堆栈操作必须以字为单位
- 不影响标志位
- 不能用立即寻址方式
- DST不能是CS (CS只能用JMP指令间接修改)
交换指令: XCHG OPR1,OPR2
执行操作: (OPR1) <-> (OPR2)
注意
- 不影响标志位
- 不允许使用段寄存器和立即数
- 两个操作数必须有一个在寄存器中(内存之间不能相互传送数据,因为不知位宽是否匹配)
累加器专用传送指令(IN/OUT)
输入指令:IN
执行操作: (I/O->CPU)
长格式: IN AL, PORT
(字节) IN AX, PORT
(字)
执行操作:AL <-(PORT) (字节)AX <- (PORT+1),(PORT) (字)
短格式: IN AL, DX
(字节)IN AX, DX
(字)
执行操作:AL <- (DX) (字节) AX <- (DX+1),(DX) (字)
输出指令 OUT
执行操作:(CPU -> I/O)
长格式: OUT PORT, AL
(字节) OUT PORT, AX
(字)
执行操作:(PORT) <- AL (字节) (PORT+1),(PORT) <- AX(字)
短格式: OUT DX, AL
(字节) OUT DX, AX
(字)
执行操作: (DX) <- AL (字节) (DX+1),(DX) <- AX(字)
注意:
- 不影响标志位
- 前256个端口号00H~FFH可直接在指令中指定(长格式)
- 如果端口号>= 256,端口号-> DX(短格式)
换码指令:XLAT
或 XLAT OPR
执行操作:AL <- ( BX + AL )
功能:AL给出偏移量,然后存储该偏移地址处的内容
例子: MOV BX, OFFSET TABLE ; BX=0040H
MOV AL, 3
XLAT TABLE
指令执行后 AL=33H
注意
- 不影响标志位
- BX是16位寄存器,AL是8位寄存器,偏移地址AL只有8位二进制,所以表格的最大容量是256字节
- BX中存放段首地址,段首地址可以是DS,也可以是用户定义的DATA;
- xlat查表指令只能是字节操作;每次偏移一个字节;
有效地址送寄存器指令:LEA REG, SRC
执行操作: REG<- SRC (将源操作数的有效地址EA传送给通用寄存器)
SRC:不能是立即寻址,寄存器寻址
MOV BX,0408H
MOV SI,2000H
LEA BP,[BX+SI+6]; 将240EH送BP, 而不是240EH单元的内容送BP
指针(地址的地址)送寄存器和DS指令:LDS REG, SRC
执行操作: REG<- (SRC) : 将源操作数指定的存储单元中的双字(通常为段地址和有效地址)传送给DS及目的操作数,高两字节送DS,低两字节送目的操作数。
获取DS段的指针 DS<-(SRC+2)
相继二字-> 寄存器、DS
指针送寄存器和ES指令:LES REG, SRC
执行操作: REG <-(SRC)
获取ES段的指针 ES <- (SRC+2)
相继二字 ->寄存器、ES
注意:
- 不影响标志位
- REG 只能是16位通用寄存器,不能是段寄存器,SRC 必须为存储器寻址方式
- LEA指令与LDS、LES指令所传送的有效地址有区别。LEA指令所传送的有效地址为源操作数的有效地址,而LDS及LES指令所传送的有效地址在源操作数所指的存储单元中
(FLAGS为16位寄存器)
标志送AH指令: LAHF
执行操作: AH <- (FLAGS的低字节) : 将标志寄存器低8位送AH。
AH送标志寄存器指令:SAHF
执行操作: (FLAGS的低字节) <-AH : 将(AH)送标志寄存器低8位。
标志进栈指令: PUSHF (FLAGS的高和低两字节)
执行操作: (SP) <- (SP) - 2
( (SP)+1, (SP) ) <- (FLAGS)
标志出栈指令: POPF(FLAGS的高和低两字节)
执行操作: (FLAGS) <- ( (SP)+1, (SP) )
(SP) <- (SP) + 2
注意:
数据传送指令中仅SAHF及POPF影响标志寄存器的内容。
有关符号位加减法指令中的OF
1、计算机中,当确定为有符号数运算时,符号数一律用补码表示,运算时符号位和数字位一起参加运算。
2、在加法/减法运算中的OF含义说明:
不溢出(OF=0),说明运算结果正确。
溢出(OF=1),说明运算结果错误。
3、 O F = A n ‾ ⋅ B n ‾ ⋅ S n + A n ⋅ B n ⋅ S n ‾ O F=\overline{A n} \cdot \overline{B n} \cdot S_{n}+A n \cdot B_{n} \cdot \overline{S_{n}} OF=An⋅Bn⋅Sn+An⋅Bn⋅Sn
An、Bn分别代表两个加数符号位,Sn代表结果的符号位。
4、在加法/减法运算中的溢出情况总结:
异号数相加或同号数相减不会溢出(OF=0)。
同号数相加或异号数相减时有可能发生溢出(OF=1)。
加法指令: ADD DST, SRC
执行操作: (DST) <- (SRC) + (DST)
带进位加法指令:ADC DST, SRC
执行操作: (DST) <- (SRC) + (DST) + CF
加1指令: INC OPR
执行操作: (OPR) <- (OPR) + 1
注意
除INC指令不影响CF标志外(硬件结构决定的),均对条件标志位有影响。
MOV DX,2000H;
MOV AX,8A04H
ADD AX, 9D00H
ADC DX,45H
此程序段实现多字节数20008A04H与459D00H的相加。DX存放有被加数的高两字节,AX存放有被加数的低两字节。ADD指令实现两数低两字节的相加,相加后(AX)=2704H,CF=1(相加结果超过两个字节)。ADC指令实现两数高两字节的相加,且将CF(即低两字节相加产生的进位)加至DX,使DX内容为2046H。
减法指令: SUB DST, SRC
执行操作: (DST) <- (DST) - (SRC)
带借位减法指令:SBB DST, SRC
执行操作: (DST) <- (DST) - (SRC) - CF
减1指令: DEC OPR
执行操作: (OPR) <- (OPR) - 1
求补指令: NEG OPR
执行操作: (OPR) <- (OPR)
即将操作数按位求反后末位加1,因而执行的操作也可以表示为:(OPR)<- 0FFFFH-(OPR)+1
比较指令: CMP OPR1, OPR2
执行操作: (OPR1) - (OPR2)
CMP指令与SUB指令一样执行减法操作,但它并不保存结果,只是根据结果设置条件标志位。
CMP指令后往往跟一条条件转移指令,根据比较结果产生不同的程序分支。
说明:OPRT1和OPRT2可以是寄存器或存储器,但不能同时为存储器,OPRT2还可以为立即数。
无符号数乘法指令:MUL SRC
带符号数乘法指令:IMUL SRC
执行操作:
字节操作数 AX<- AL * (SRC)
字操作数 (DX,AX) <- AX * (SRC)
MUL CL; AL,CL 中的无符号之积送AX
MUL [SI]; 计算机无法判断源操作数是字节操作数还是字操作数MUL
MUL WORD PTR [SI]; AX中的无符号数与SI所指单元的字无符号数相乘,乘积送DX和AX
注意:
- AL (AX) 为隐含的乘数寄存器。
- AX (DX,AX) 为隐含的乘积寄存器。
- SRC不能为立即数,因为位宽不详。
- 除CF和OF外,对条件标志位无定义
乘法指令对 CF/OF 的影响:
乘法指令不会产生溢出和进位,这时用OF和CF位来表示乘积有效数字的长度:
若乘积的高半部分(字节乘法为AH,字乘法为DX)有效,即:
MUL指令中是指AH或DX中的内容不为0
IMUL指令指的则是AH或DX中的内容不是符号位的扩展
则CF和OF都为1,表示DX或AH中含有乘积的有效数字,否则CF和OF为0。
DIV源操作数
MOV AX,1001H;
MOV CL, 20H;
DIV CL;
IDIV源操作数
功能与DIV指令基本相同,区别在于,该指令实现有符号数除法运算
MOV CX,4
IDIV CX;
CBW
MOV AL,76H;
CBW;
CWD
SHL SHR SAL SAR
移位指令影响除AF外的5个标志位,对AF没定义
ROL ROR RCL RCR
循环移位指令影响CF和OF,对SF ZF PF没影响,对AF没定义
(略,非考点)
注意:只能使用段内直接寻址的8 位位移量; 超过60条指令就要小心了!
参考带符号数的CMP指令或减法指令对SF/OF的影响
适用于带符号数的比较
循环指令:LOOP OPR
测试条件:(CX) !=0
为零或相等时循环指令:LOOPZ(LOOPE) OPR
测试条件:ZF=1 且 (CX) != 0
不为零或不相等时循环指令:LOOPNZ(LOOPNE) OPR
测试条件:ZF=0 且 (CX) != 0
执行步骤:
(1) (CX) ← (CX) - 1
(2) 检查是否满足测试条件,如满足则 (IP) ← (IP) + 8位位移量,实行循环;不满足则 IP 不变,退出循环。
注意:CX 中存放循环次数; 只能使用段内直接寻址的8 位位移量; 超过60条指令就要小心了!
CALL DST
(DST为子程序名)CALL DST
(DST为寄存器如BX或存储器地址 WORD PTR [BX])RET
RET EXP
中断发生时,从中断向量表中取出相应的值赋值给CS和IP的过程是由系统硬件自动完成的,程序员不可见! 程序员能够做的就是修改中断向量表中存储的值。
在8086中,reset不算是中断,不在中断向量表内。reset时CS=FFFFH,IP=0000H; 在内存FFFF0处存放了一个JMP指令!
INT
指令时,经过某些操作,转去执行中断服务程序。这些操作是由硬件直接实现的,把它称为中断隐指令,其操作过程程序员不可见。中断隐指令并不是指令系统中的一条真正的指令,它没有操作码,所以中断隐指令是一种特殊指令注意:
TYPE (0~255) 是中断类型号
INT 指令还把 IF 和 TF 置0,但不影响其它标志位
IRET 指令执行完,标志位由堆栈中取出的值确定
CLC
、 STC
、 CMC
:对CF位清零/置位/取反
CLD
、STD
: 字符串移动方向增/减标志
CLI
、STI
:开/关中断
控制CPU工作方式的指令,多用于多任务处理
NOP
WAIT
HLT
LOCK
1、指出下列指令的错误
(1) MOV AH,BX
(2) MOV [BX],[SI]
(3) MOV AX,[DI ][SI]
(4) MOV MYDAT[BX][SI],ES:AX
(5) MOV CS,AX
Answer:
2、下列哪些指令是非法的
(1) CMP 15,BX
(2) CMP BYTE PTR OP1,25
(3) CMP OP1,OP2
(4) CMP AX,OP1
Answer:
3、假设下列指令中的所有标示符均为类型属性为字的变量,请指出下列指令中哪些是非法的?它们的错误是什么?
(1) MOV BP,AL
(2) MOV WORD_OP[BX+4*3][DI],SP
(3) MOV WORD_OP1,WORD_OP2
(4) MOV AX,WORD_OP1[DX]
(5) MOV SAVE_WORD,DS
(6) MOV SP,SS:DATA_WORD[BX][SI]
(7) MOV [BX][SI],2
Answer:
4、假设程序中的数据定义如下:
LNAME DB 30 DUP(?)
ADDRESS DB 30 DUP(?)
CITY DB 15 DUP(?)
CODE_LIST DB 1,7,8,3,2
(1) 用一条MOV指令将LNAME的偏移地址放入AX。
(2) 用一条指令将CODE_LIST的头两个字节的内容放到SI。
(3) 写一条伪操作使CODE_LENGHT的值等于CODE_LIST域的实际长度
5、试说明下述指令中哪些需要加上PTR伪操作:
BVAL DB 10H,20H
WVAL DW 1000H
(1) MOV AL,BVAL
(2) MOV DL,[BX]
(3) SUB [BX],2
(4) MOV CL,WVAL
(5) ADD AL,BVAL+1
Answer:
6、若TABLE为数据段0032H单元的符号名,其中存放的内容为1234H,试问下列两条指令有什么区别?执行完指令后,AX寄存器中的内容是什么?
MOV AX,TABLE
LEA AX,TABLE
Answer:
7、已知程序段如下:
MOV AX,1234H
MOV CL,4
ROL AX,CL
DEC AX
MOV CX,4
MUL CX
试问:
(1)每条指令执行后,AX的内容是什么?
(2)每条指令执行后,CF、SF和ZF的值是什么?
(3)程序执行完后,AX和CX的内容是什么?
Answer:
MOV AX,1234H; (AX)=1234H, CF、SF、ZF的值保持不变(因为此处不知道标志寄存器的初值,所以无法判断具体的值)
MOV CL,4; (AX)=1234H, CF、SF、ZF的值保持不变
ROL AX,CL; (AX)=2341H, CF=1, SF、ZF的值保持不变
DEC AX; (AX)=2340H, CF不变,SF=ZF=0
MOV CX,4; AX、CF、SF、ZF的值保持不变
MUL CX; (AX) =8D00H, SF=1,CF=ZF=0
程序执行完后,(DX)=0000H, (AX)=8D00H
小结:
- SHL SHR SAL SAR
移位指令影响除AF外的5个标志位,对AF没定义- ROL ROR RCL RCR
循环移位指令影响CF和OF,对SF ZF PF没影响,对AF没定义- INC DEC
增一、减一指令不影响CF,会影响其他的标志位
SHL AL,1;
JC NT1
MOV DL,30H
JMP NT2
NT1: MOV DL,31H
NT2: MOV AH,02H
INT 21H
DOS 功能调用
功能号02H,用于从显示屏幕上输出单个字符
【例】: 显示输出字符’A’MOV DL,'A'; 调用参数,输出字符 MOV AH,02; DOS功能号: 显示输出 INT 21H;DOS 调用
DOS功能调用:
功能号09H,用于从显示屏幕上输出字符串
例:显示输出字符串‘computer’STR DB ‘computer’,‘$’ ;在数据段定义 … MOV DX,OFFSET STR ; 调用参数: 输出字符串 MOV AH,09H ; DOS功能号: 显示输出串 INT 21H ; DOS调用
CMP AX,0
JGE NT
NEG AX
NT: MOV RES,AX
【例】设计字符比较程序,两个字符相同时,显示YES; 否则显示NO。
DATA SEGMENT
D1 DB 'A'
D2 DB 'B'
RES1 DB 'YES' ,'$'
RES2 DB 'NO' , '$'
DATA ENDS
CODE SEGMENT
ASSUME CS:CODE,DS:DATA
START:
MOV AX,DATA
MOV DS,AX
MOV AL,D1
MOV BL,D2
CMP AL,BL
JE NEXT1
LEA DX,RES2
JMP NEXT2
NEXT1: LEA DX,RES1
NEXT2: MOV AH,09H
INT 21H
MOV AH,4CH
INT 21H
CODE ENDS
END START
【例】设存储单元A和B各有
一无符号字节数,比较大小,将较大数送A单元
DATA SEGMENT
A DB 39H
B DB 0B4H
DATA ENDS
CODE SEGMENT
ASSUME CS:CODE,DS:DATA
START:
MOV AX,DATA
MOV DS,AX
MOV AL,A
CMP AL,B
JNB NEXT
XCHG AL,B
MOV A,AL
NEXT:
MOV AH,4CH
INT 21H
CODE ENDS
END START
实现方法:
用多个双分支结构实现多分支结构
利用地址表法实现多分支结构
利用转移表法实现多分支结构
利用逻辑分解法实现多分支结构
DATA SEGMENT
X DB 0B9H
Y DB ?
DATA ENDS
CODE SEGMENT
ASSUME CS:CODE, DS: DATA
START:
MOV AX,DATA
MOV DS, AX
MOV AL,X
CMP AL,0
JL NEXT1
CMP AL,0
JG NEXT2
MOV Y,0
JMP RES
NEXT1: MOV Y,0FFH
JMP RES
NEXT2:MOV Y,1
RES:
MOV AH,4CH
INT 21H
CODE ENDS
END START
【例】用地址表法编写程序实现从低到高逐位检测一个字节数据,找出第一个非0的位数。检测时,为0则继续检测,为1则转移到对应的处理程序段显示相应的位数。
DATA SEGMENT
NUM DB 78H
ADTAB DW AD0,AD1,AD2,AD3,AD4,AD5,AD6,AD74
DATA ENDS
CODE SEGMENT
ASSUME CS:CODE, DS:DATA
START:
MOV AX,DATA
MOV DS, AX
MOV AL,NUM
MOV DL,'?'
CMP AL,0
JZ DISP
MOV BX,0
AGAIN:
SHR AL,1
JC NEXT
INC BX
JMP AGAIN
NEXT:
SHL BX,1
JMP ADTAB [BX]
AD0:MOV DL,'0'
JMP DISP
AD0:MOV DL,'1'
JMP DISP
AD0:MOV DL,'2'
JMP DISP
AD0:MOV DL,'3'
JMP DISP
AD0:MOV DL,'4'
JMP DISP
AD0:MOV DL,'5'
JMP DISP
AD0:MOV DL,'6'
JMP DISP
AD0:MOV DL,'7'
JMP DISP
DISP:
MOV AH,2
INT 21H
MOV AH,4CH
INT 21H
CODE ENDS
END START
CODE SEGMENT
ASSUME CS:CODE
START:
LEA BX,TAB
MOV AH,1
INT 21H
SUB AL,30H
MOV AH,0
ADD AX,AX
ADD BX,AX
JMP BX
TAB:
JMP SHORT MODE1
JMP SHORT MODE 2
JMP SHORT MODE3
JMP SHORT MODE4
MODE0:
MOV DL, 30H
JMP EXIT
MODE1:
MOV DL, 31H
JMP EXIT
MODE2:
MOV DL, 32H
JMP EXIT
MODE3:
MOV DL, 33H
JMP EXIT
MODE4:
MOV DL, 34H
JMP EXIT
EXIT:
MOV AH,2
INT 21H
MOV AH,4CH
INT 21H
CODE ENDS
END START
说明:转移表中每条转移指令(段内短转移)占用2个字节, 计算公式如下:表地址=模式字*2+转移表首地址
设计方法:将多分支结构采用逻辑等效的方法,按条件的先后,依次分解成下图所示的一串双分支结构,然后使用双分支的方法来进行程序设计。
【例】 根据AL中的值(0~4),执行不同的操作,用逻辑分解法编写程序
DATA SEGMENT
NUM DB 2
DATA ENDS
CODE SEGMENT
ASSUME CS:CODE,DS:DATA
START:
MOV AX,DATA
MOV DS,AX
MOV AL,NUM
CMP AL,0
JZ NEXT0
CMP AL,1
JZ NEXT1
CMP AL,2
JZ NEXT2
CMP AL,3
JZ NEXT3
CMP AL,4
JZ NEXT4
NEXT0: MOV DL,30H
JMP EXIT
NEXT0: MOV DL,31H
JMP EXIT
NEXT0: MOV DL,32H
JMP EXIT
NEXT0: MOV DL,33H
JMP EXIT
NEXT0: MOV DL,34H
EXIT:
MOV AH,2
INT 21H
MOV AH,4CH
INT 21H
CODE ENDS
END START
1、内存有一个字节变量VAL中存放着小写字符’a’,请将该字符转换为大写字符并在屏幕中显示出来(要求在debug中调试出该程序)
DSEG SEGMENT
VAL DB 'a';
DSEG ENDS
CSEG SEGMENT
ASSUME CS:CSEG,DS: DSEG
START:
MOV AX, DSEG;将段地址送往DS
MOV DS, AX
MOV AL, VAL;
SUB AL,20H; 转换为大写字母
MOV DL,AL ; 显示一个字符的DOS调用
MOV AH,02H; DOS输出功能调用
INT 21H;
MOV AH,4CH; 返回DOS调用
INT 21H;
CSEG ENDS
END START
2、设存储单元A和B各有一带符号字节数,比较大小和正负,要求将较大数送RES1单元;如果有负数,将一个负数送RES2,否则RES2送-1(要求在debug中调试出该程序)。
DSEG SEGMENT
A DB 5
B DB -3
RES1 DB ?
RES2 DB ?
DSEG ENDS
CSEG SEGMENT
ASSUME CS:CSEG,DS: DSEG
START:
MOV AX, DSEG;将段地址送往DS
MOV DS, AX
MOV DL,A;
MOV DH,B;
CMP DL,DH;
JG AGB
MOV RES1,DH;B>=A
MOV CL,DL; 将小的数送往CL
JMP FU;
AGB:
MOV RES1,DL; A>B
MOV CL,DH ; 将小的数送往CL
FU:
CMP CL,0;
JL FSS;
MOV RES2,-1; 不存在负数
JMP EXIT; 返回
FSS:
MOV RES2,CL;存在负数
EXIT:
MOV AH,4CH; 返回DOS调用
INT 21H;d
CSEG ENDS
END START
循环指令:LOOP OPR
测试条件:(CX) != 0
为零或相等时循环指令:LOOPZ(LOOPE) OPR
测试条件:ZF=1 且 (CX)!= 0
不为零或不相等时循环指令:LOOPNZ(LOOPNE) OPR
测试条件:ZF=0 且 (CX) !=0
执行步骤:
(1) (CX) ← (CX) - 1
(2) 检查是否满足测试条件,如满足则
(IP) ← (IP) + 8位位移量,实行循环;
不满足则 IP 不变,退出循环。
注意:LOOP指令执行时CX是否为0不影响ZF和CF的变化,等价于DEC指令!所以LOOP指令和LOOPZ指令才有区别!
循环程序结构:
初始化:设置循环的初始状态
循环体:循环的工作部分及修改部分
控制条件:计数控制,特征值控制,地址边界控制
【例】在STR开始的缓冲区中存放有一个字符串,计算该字符串的长度并存入LEN单元。
DATA SEGMENT
STR DB 'computer$'
LEN DB ?
DATA ENDS
CODE SEGMENT
ASSUME CS: CODE, DS:DATA
START:
MOV AX,DATA
MOV DS,AX
LEA SI,STR; 串首地址
XOR BL,BL; 计数器清零
LOP:
MOV AL, [SI]; 取一个字节
CMP AL,24H; 和$ 进行比较
JZ STOP ; 相等则结束
INC BL;否则计数器加1
INC SI; 地址指针加1
JMP LOP; 转回到LOP
STOP:
MOV LEN, BL ; 存储字符的个数
MOV AH,4CH
INT 21H
CODE ENDS
END START
【例】求以BUF为首地址的10个内存单元的无符号数据和。已知其和小于等于255,将结果存入第11个内存单元
DATA SEGMENT
BUF DB 12H, 38H, 46H, 0BH, 09H, 41H, 32H, 56, 02H, 26H
RES DB ?
DATA ENDS
CODE SEGMENT
ASSUME CS:CODE,DS: DATA
START:
MOV AX,DATA
MOV DS,AX
MOV AL,0; 存放累加之和
MOV CX,0AH; 累加次数
LEA BX, BUF; 数据表的首地址
LP:
ADD AL,[BX];
INC BX
LOOP LP
MOV AH,4CH
INT 21H
CODE ENDS
END START
【例】在字节数组中找出第一个非0的数据,并将其下标存入RES单元,假设其下标值小于10
DATA SEGMENT
ARR DB 0,0,38H,46H
DB 89H,67H,0H,92H
CNT EQU $-ARR
RES DW ?
DATA ENDS
CODE SEGMENT
ASSUME CS:CODE, DS: DATA
START:
MOV AX,DATA
MOV DS,AX
MOV CX,CNT;
MOV DI,-1
AGAIN :
INC DI
CMP ARR[DI],0
LOOPZ AGAIN
JZ EXIT
MOV RES,DI
EXIT:
MOV AH,4CH
INT 21H
CODE ENDS
END START
【例】在字符串中从前向后查找空格字符(ASCII码为20H),找到显示Y,否则就显示N
DATA SEGMENT
STR DB 'ASDFK LIO OP'
LEN EQU $-STR
DATA ENDS
CODE SEGMENT
ASSUME CS:CODE,DS:DATA
START:
MOV AX,DATA
MOV DS,AX
MOV CX,LEN
MOV SI,-1
MOV AL,20H
NEXT:
INC SI
CMP AL,STR[SI]
LOOPNE NEXT
JNZ NFIND
MOV DL,'Y'
MOV AH,2
INT 21H
JMP EXIT
NFIND:
MOV DL,'N'
MOV AH,2
INT 21H
EXIT:
MOV AH,4CH
INT 21H
CODE ENDS
END START
DATA SEGMENT
BUF DB -32,25,36,-18,-64,0,-3
COUNT EQU $-BUF
PLUS DB ?;
MINUS DB ?;
DATA ENDS
CODE SEGMENT
ASSUME CS:CODE DS: DATA
START:
MOV AX,DATA
MOV DS,AX
MOV BL,0; 负数个数
MOV DL,0; 正数个数
MOV SI,OFFSET BUF; 指针
MOV CX,0;循环初值
LOP1:
MOV AL,[SI]
CMP AL,0
JGE NEXT0
INC BL
JMP NEXT1
NEXT0:
INC DL
NEXT1:
INC SI
INC CX
CMP CX, COUNT;
JL LOP1
MOV MINUS,BL
MOV PLUS,DL
MOV AH,4CH
INT 21H
CODE ENDS
END START
【例】将BUF数据单元开始的100个字节存储单元全部清零
DATA SEGMENT
BUF DB 100 DUP(?)
DATA ENDS
CODE SEGMENT
ASSUME CS: CODE,DS: DATA
START:
MOV AX,DATA
MOV DS,AX
MOV BX, OFFSET BUF;地址指针
MOV CX,64H;计数初值
LP:
MOV BYTE PTR [BX],0; 清零
INC BX;地址加1
LOOP LP;循环次数减1,不为0,则继续循环
MOV AH,4CH
INT 21H
CODE ENDS
END START
DATA SEGMENT
NUM DB 75H
RES DB ?
DATA ENDS
CODE SEGMENT
ASSUME CS: CODE,DS:DATA
START:
MOV AX,DATA
MOV DS,AX
MOV BL,NUM
XOR DL,DL
AGAIN:
TEST BL,00H
JZ NEXT
SHR BL,1
ADC DL,0
JMP AGAIN
NEXT:
MOV RES,DL
MOV AH,4CH
INT 21H
CODE ENDS
END START
【例】在以BUF为起始地址的内存中放有若干个字节型无符号数,假定逻辑变量的长度为一个字节(其值为10010101 ),若它的D0~ D7位对应着BUF ~ BUF+7单元内容的运算。即某位为0,则将相应单元内容的最高位求反,其它位不变;而某位为1,则将相应单元内容之高低四位互换。
DATA SEGMENT
BUF DB 75H,12H,87H,98H
DB 81H,56H,73H,51H
B EQU 8
C EQU 10010101B
DATA ENDS
CODE SEGMENT
ASSUME CS: CODE,DS: DATA
START:
MOV AX,DATA
MOV DS,AX
MOV AH, B
MOV CH, C
LEA BX,BUF
LP:
MOV AL,[BX]
SHR CH,1
LEA BX,BUF
LP:
MOV AL,[BX]
SHR CH,1
JNC NEXT
MOV CL,4
ROL AL,CL
JMP RES
NEXT:
XOR AL,80H
RES:
MOV [BX],AL
INC BX
DEC AH
JNZ LP
MOV AH,4CH
INT 21H
CODE ENDS
END START
【例】设在以EXST为首址的存储区中依次存放着某考区245个理科生的七门成绩,现要统计每个考生的总成绩,并将其存放在该考生单科成绩之后的两个单元
DATA SEGMENT
EXST DB 01,75,82,92,78,49,85,00,00
DB 02,83,92,63,76,82,58,69,00,00
..
DATA ENDS
CODE SEGMENT
ASSUME CS:CODE, DS: DATA
MOV AX, DATA
MOV DS,AX
START:
LEA SI,EXST; 数据表的首地址
MOV BL, 245; 245个学生,外循环次数
LOP2: MOV CX,7; 7门课的成绩,内循环的次数
XOR AX,AX; 清0,存总成绩
INC SI;跳过准考证号
LOP1: ADD AL,[SI]; 单科成绩累加
ADC AH,0; 加进位位
INC SI; 修改地址指针
LOOP LOP1; 没累加完单科成绩,则继续
MOV WORD PTR [SI],AX; 累加完,存总成绩
INC SI ; 跳过存总成绩的两个单元
INC SI
SUB BL,1; 外循环次数减1,如果是DEC指令则不影响ZF
JNZ LOP2; 不为0,则求下一个学生的成绩
MOV AH,4CH
INT 21H
CODE ENDS
END START
【例】将N个不同的无符号数a1,a2,…,an由小到大进行排序。若每个数占一个字, 则N个数可定义如下:
A DW a1,a2,a3,…,an,它们的内存分配分别为: A[0],A[2],A[4],…,A[2n]
DATA SEGMENT
A DW 1223,83,456,355,89
DW 9845,123,789,567
CNT EQU ($-A) /2
DATA ENDS
CODE SEGMENT
ASSUME CS: CODE, DS: DATA
START:
MOV AX, DATA
MOV DS,AX
MOV CX,CNT-1
MOV BX,0
LOOP1:
MOV DX,CX
MOV SI,2
LOOP2:
MOV AX,A[BX]
CMP AX,A[BX+SI]
JNA L1
XCHG AX,A[BX+SI]
MOV A[BX],AX
L1:
ADD SI,2
LOOP LOOP2
ADD BX,2
MOV CX,DX
LOOP LOOP1
MOV AH,4CH
INT 21H
CODE ENDS
END START
1、 在STR到STR+99单元中存放着一个字符串,试编写程序测试该字符串中是否有数字,若有将CL置1,否则CL置0 (要求在debug中调试出该程序)。
DSEG SEGMENT
STR DB 'A5AAAAAAAABBBBBBBBBBCCCCCCCCCCDDDDDDDDDDEEEEEEEEEE'
DB 'AAAAAAAAAABBBBBBBBBBCCCCCCCCCCDDDDDDDDDDEEEEEEEEEE'
DSEG ENDS
CSEG SEGMENT
ASSUME CS:CSEG,DS: DSEG
START:
MOV AX, DSEG;将段地址送往DS
MOV DS, AX
MOV BX,OFFSET STR; 地址指针
MOV CX,64H; 计数器初值,100次循环
LP:
MOV AL,[BX];
CMP AL,'0';
JB NS; 小于0
CMP AL,'9'
JA NS; 大于9
MOV CL,1; 存在数字,跳出循环。
JMP EXIT;
NS: ; 不是数字
INC BX; 地址加1
LOOP LP; 循环次数减1,不为0则继续循环。
MOV CL,0; 不存在数字
EXIT:
MOV AH,4CH; 返回DOS调用
INT 21H;
CSEG ENDS
END START
2、在字节数组中找出第一个负数,并将该负数存入RES单元中;假设该数组中包含20个带符号数且至少有1个负数(要求在debug中调试出该程序)。
DSEG SEGMENT
RES DB ?
DATA DB 1,-1,2,3,4,5,6,7,8,9
DB 0,3,4,-5,6,7,8,-9,0,2
DSEG ENDS
CSEG SEGMENT
ASSUME CS:CSEG,DS: DSEG
START:
MOV AX, DSEG;将段地址送往DS
MOV DS, AX
MOV CX,20; 循环的次数设为20
MOV DI,0;地址指针
LP:
CMP DATA[DI],0;判断是否为负数
JL EXIT; 如果小于0,则退出
INC DI; 地址指针加1
LOOP LP;继续循环
EXIT:
MOV AL,DATA[DI]
MOV RES,AL;
MOV AH,4CH; 返回DOS调用
INT 21H;
CSEG ENDS
END START
子程序的运行方式:
特点:主动调用,而不是随机的(中断则相反)。
CALL调用指令
段内直接近调用:CALL DST
执行操作:
(SP) ← (SP) - 2
( (SP)+1,(SP) ) ← (IP)
(IP) ← (IP) + 16位位移量
段内间接近调用:CALL DST
执行操作:
(SP) ← (SP) - 2
( (SP)+1,(SP) ) ← (IP)
(IP) ←(EA)
RET返回指令
段内近返回:RET
执行操作:
(IP) ← ( (SP)+1,(SP) )
(SP) ← (SP) + 2
段内带立即数近返回:RET EXP
过程名 PROC NEAR(FAR)
...
过程名 ENDP
(1)NEAR 属性:调用程序和子程序在同一代码段中(段内调用)
(2)FAR 属性:调用程序和子程序不在同一代码段中(如同一汇编文件的多个代码段或多个汇编文件的多个代码段时)(段间调用)
2. 子程序的调用和返回
子程序调用:隐含使用堆栈保存返回地址
call near ptr subp
(1) 保存返回地址:仅offset地址
(2) 转子程序
call far ptr subp
(1) 保存返回地址:seg+offset
(2) 转子程序
段内近返回:RET
执行操作:
(IP) ← ((SP)+1,(SP))
(SP) ← (SP) + 2
subt proc near(far)
push ax
push bx
push cx
push dx
……
……
pop dx
pop cx
pop bx
pop ax
ret
subt endp
【例】利用子程序完成乘法运算(通过寄存器传送参数)
data segment
x db 5
y dw ?
data ends
stack segment
db 64 dup('s')
stack ends
code segment para ’code‘
assume cs:code,ds:data,ss:stack
star proc far
push ds;
mov ax,data; 搬移DS段
mov ds,ax
mov bl,1; 入口参数放到bl中
call mulx
ret
star endp
mulx proc near
push ax
mov al,x
mul bl
mov y,ax
pop ax
ret
mul endp
code ends
end star
在没有定义堆栈段的情况下,程序开始时的栈顶指向程序的第一个段,如:先定义代码段,后定义数据段,就指向代码段;
【例】将给定的一组字数据X、Y代入Z=((X+Y)×2-X)×4 公式中,计算相应的Z值。假设Z的值不会超过16位。
DATA SEGMENT
X DW 5,3,8,9,2,5,3,4,7,6
Y DW 3,7,4,5,8,8,4,1,0,7
Z DW 10DUP(?)
DATA ENDS;
CODE SEGMENT
ASSUME CS:CODE, DS:DATA
START:
MOV AX,DATA
MOV DS,AX
LEA SI,X
LEA DI,Y
LEA BX,Z
MOV CX,Y-X ; 字节数
SHR CX,1;数组元素个数
REAPT
MOV AX,[SI]
MOV DX,[DI]
CALL SUBR
MOV [BX],AX
ADD SI,2
ADD DI,2
ADD BX,2
LOOP REAPT
EXIT:
MOV AH,4CH
INT 21H
SUB PROC NEAR
PUSH BX
PUSH CX
MOV BX,AX;BX=X
ADD AX,DX; AX=X+Y
SAL AX,1;AX=(X+Y)*2
SUB AX,BX;AX=(X+Y)*2-X
MOV CL,2
SAL AX,CL; AX=((X+Y)*2-X)*4
POP CX;
POP BX
RET
SUB ENDP
CODE ENDS
END START
【例】累加数组中的元素(通过存储器传送参数)
DATA SEGMENT
ary dw 1,2,3,4,5,6,7,8,9,10
count dw 10
sum dw ?
DATA ENDS;
CODE SEGMENT
ASSUME CS:CODE, DS:DATA
START:
MOV AX,DATA
MOV DS,AX
CALL PROADD
MOV AH,4CH
INT 21H
PROADD PROC NEAR
PUSH AX
PUSH CX
LEA SI,ARY
MOV CX,COUNT
XOR AX,AX
NEXT:
ADD AX,[SI]
ADD SI,2
LOOP NEXT
MOV SUM,AX
POP SI
POP CX
POP AX
RET
PROADD ENDP
CODE ENDS
END START
- 试编写一个汇编程序,能对键盘输入的小写字母用大写字母显示出来(要求采用子程序格式,即采用子程序完成将小写字母转化成大写字母)。
DSEG SEGMENT
DSEG ENDS
CSEG SEGMENT
ASSUME CS:CSEG,DS: DSEG
START:
MOV AX, DSEG;将段地址送往DS
MOV DS, AX
MOV AH,01; 从键盘中接收一个字符
INT 21H;
CALL SUB1;
MOV DL,AL ; 显示一个字符的DOS调用
MOV AH,02H; DOS输出功能调用
INT 21H;
MOV AH,4CH; 返回DOS调用
INT 21H;
SUB1 PROC
SUB AL,20H; 转换为大写字母
SUB1 ENDP
CSEG ENDS
END START
2、有2个数组:
ary1 db 12,-35,0,126,-90,-5,68,120,1,-19
ary2 db 24,25,0,-38,-89,99,68,100,2,-20
比较两个数组的对应位,将大的数放在ary1数组中,小的数放在ary2中(要求采用子程序格式)
DSEG SEGMENT
ARY1 DB 12,-35,0,126,-90,-5,68,120,1,-19
COUNT EQU $-ARY1
ARY2 DB 24,25,0,-38,-89,99,68,100,2,-20
DSEG ENDS
CSEG SEGMENT
ASSUME CS:CSEG,DS: DSEG
START:
MOV AX, DSEG;将段地址送往DS
MOV DS, AX
MOV CX,COUNT;CX为入口参数,保存数组元素的个数
LEA SI,ARY1; SI为入口参数, 保存数组1的起始位置
LEA DI,ARY2; DI为入口参数, 保存数组2的起始位置
CALL SUB1;
MOV AH,4CH; 返回DOS调用
INT 21H;
SUB1 PROC
LP:
MOV AX,[SI]
MOV DX,[DI]
CMP AX,DX;
JG AGB;
MOV [SI],DX;如果数组1的对应位置元素小于数组2对应位置元素,则交换两数
MOV [DI],AX;
AGB:
ADD SI,1
ADD DI,1
LOOP LP
RET;
SUB1 ENDP
CSEG ENDS
END START
3、用DOS的10号功能调用输入一个字符串,并用DOS的9号功能调用将这个字符串输出到屏幕上显示。
DSEG SEGMENT
STRING DB 100
LEN DB ?
BUF DB 100 DUP(?)
DSEG ENDS
CSEG SEGMENT
ASSUME CS:CSEG,DS:DSEG
START:
MOV AX,DSEG
MOV DS,AX
LEA DX,STRING;字符串的输入
MOV AH,0AH;
INT 21H;
MOV DL,0AH;输出换行
MOV AH,02H
INT 21H;
XOR CH,CH
MOV CL,LEN
MOV DX,OFFSET BUF
MOV BX,DX
ADD BX,CX
MOV BYTE PTR [BX],'$'
MOV AH,09H;显示字符串
INT 21H;
MOV AX,4CH; 返回DOS
INT 21H
CSEG ENDS
END START
BIOS和DOS基本调用:
调用方法
1、将调用参数装入指定的寄存器中;
2、BIOS或DOS功能号装入AH;
3、如需子功能号,把它装入AL;
4、按中断号调用DOS或BIOS中断(INT);
5、检查或取得返回参数。
【例】DOS调用:键盘输入,显示输出
MOV AH, 01 ;DOS功能号1:键盘输入
INT 21H ;DOS调用
MOV CHAR, AL ;返回参数: 键入字符的;ASCII码(在AL中)
MOV DL, ’A’ ;调用参数: 输出字符
MOV AH, 02 ;DOS功能号2: 显示输出
INT 21H ;DOS调用
again:
mov ah,02h
int 16h
mov bx,ax
call binihex; 该子程序对二进制和16进 制进行了转换
mov dl,0dh
mov ah,02h
int 21h
jmp again
MOV AH, 01;DOS功能号:键盘输入
INT 21H;DOS调用
MOV CHAR, AL;返回参数:键入字符的ASCII码(AL)
DATA SEGMENT
MAXLEN DB 32
ACTLEN DB ?
STRING DB 32 DUP(?)
DATA ENDS
CODE SEGMENT
ASSUME CS;CODE, DS: DATA
START: MOV AX, DATA
MOV DS,AX
LEA DX, MAXLEN; 把MAXLEN所在地址赋值给DX;并且21h的0a号功能规定了缓冲区的长度设置、存放的内容和顺序,回车符(0DH)表示输入结束,见右上图
MOV AH,0AH;屏幕上出现光标,让用户输入字符串
INT 21H;
CODE ENDS
END START
MOV DL, 'A'; 调用参数,输出字符
MOV AH, 02; DOS 功能号:显示输出
INT 21H; DOS 调用
【例】 显示字符串
MESSAGE DB'The sort operation is finished.' ,13,10,'$'
MOV AH,9
MOV DX,SEG MESSAGE
MOV DS,DX
MOV DX,OFFSET MESSAGE
INT 21H
I/O 端口的概念
I/O端口(port):是接口电路中能被CPU直接访问的寄存器。CPU通过这些端口向接口中的寄存器发送命令,读取状态和传送数据。因此,一个接口可以有几个端口,如命令口、状态口和数据口,分别对应于命令寄存器、状态寄存器和数据寄存器
I/O 端口共用技术
一般情况下,一个端口只允许接纳一种信息,但有些接口芯片中,一个端口即可作命令口又可作状态口使用,或允许同一个命令口写多个命令字,由此产生了端口的共用
I/O 端口地址编制方式
1. 独立的编址
端口地址单独编址,不和存储器地址空间合在一起
。IBM-PC系列就采用这种方式。
优点:
I/O端口地址不占用存储器地址空间。
I/O指令短,执行速度快。
由于专门I/O指令与存储器访问指令有明 显的区别,使程序中I/O操作和存储器操作层次清晰,程序的可读性强。
缺点:需要专门访问I/O端口的指令。
2. 统一编址
从存储器地址空间中划出一部分地址给I/O设备,将I/O接口中的端口当作存储器单元一样进行访问,不设置专门的I/O指令
优点:指令类型多,功能齐全。
缺点:端口占用了存储器的地址空间,使存储器容量减小,另外指令长度比专门I/O指令要长,因而执行速度较慢
PORT EQU 0F4H
IN AL,PORT ;输入
IN AX,PORT
OUT PORT,AL ;输出
OUT PORT,AX
对I/O端口的访问就是CPU对端口的读/写操作。即指I/O端口与CPU的累加器之间的数据传送,并不涉及数据是否传送到存储器的问题。
例如:输入时
MOV DX,300H ; I/O端口
IN AL,DX ; 从端口读数据到AL
MOV [DI],AL ; 将数据从AL→存储器
例如:输出时
MOV DX,301H ; I/O端口
MOV AL,[SI] ; 从内存取数到AL
OUT DX,AL ; 数据从AL→端口
输入时:
IN AX,0E0H ;直接寻址
MOV DX,300H ;端口300H
IN AX,DX ;从端口300H读数据到AX
输出时
OUT 0E0H, AX ;直接寻址
MOV DX,300H
OUT DX,AX ;间接寻址
(1) 端口地址范围
直接寻址:端口地址8位,可寻址256个端口
间接寻址:端口地址16位,可寻址2^16=64K个端口
例:MOV DX, XXXXH
IN AL, DX ;
IN AX,60H ;
(2) 传送数据的宽度
例:IN AL, DX
IN AX, DX
PC微机I/O地址的分配
现代微机I/O地址的分配
windows操作系统具有即插即用的资源配置机制,因此I/O端口地址的分配是动态的
I/O端口地址选用的原则
凡是被系统配置占用了的地址一律不能使用
② 未被占用的地址,用户可以使用,但对计算机厂家申明保留的地址,不要使用。
③ 用户可使用的地址为:300H-31FH
82C55A:300H-303H
82C54A:304H-307H
8251A:308H-30BH
8279A:30CH-30DH
I/O地址译码方法
1、全译码
地址线A0-A9全部参加译码,一般在采用单端口时使用
2、部分译码
只有高位地址线参加译码,产生片选信号;而低位地址线直接接芯片,作为片内寻址。一般用于具有多个接口芯片的系统。
3、开关译码法
在部分译码方法的基础上,加上地址开关(如PC主板上的超频开关)来改变端口地址。
I/O地址译码电路的输入输出信号
1、译码电路的输入信号
I/O地址译码电路不仅仅与地址信号有关,而且
与控制信号有关。例如:
AEN信号:当AEN=1时,为DMA方式
IOR和IOW信号:控制对端口的读/写等
2、译码电路的输出信号
产生一个片选信号CS。CS=0有效,产生唯一低
电平信号,选中芯片内的寄存器端口;否则芯片
未被选中
其中 E 1 E_1 E1, E 2 E_2 E2为低电频有效, E 3 E_3 E3为高电频有效,因此 A 5 A_5 A5~ A 7 A_7 A7 分别为001。
由于OUT口的编号范围是0~2,因此 A 1 A_1 A1 A 0 A_0 A0的取值范围为00,01,10。
由于还可以选择控制口,所以 A 1 A_1 A1 A 0 A_0 A0还可以取11。
综上, A 7 A_7 A7到 A 0 A_0 A0可以取到10000000B、10000001B、10000010B、10000011B。 因此其端口地址可以为080H—083H。
G 2 A G_2A G2A和 G 2 B G_2B G2B均为低电频有效,所以 A 6 A_6 A6和 A 5 A_5 A5为00。
因为CS为低电频有效,倒推其译码的结果是2,所以输入的 A 4 A_4 A4~ A 2 A_2 A2分别为010。
由图可知,既可以选择A端口,也可以选择B端口,所以 A 1 A 0 A_1A_0 A1A0和可以取值为00或者01。
综上, A 8 A_8 A8 到 A 0 A_0 A0分别可以取到为0001 1000 1000——0001 1000 1011。因此端口地址可以为0188H—018BH。