文章目录
一.内容摘要
1.8086基本指令
2.循环结构和分支结构及其程序的实现方法
二.8086基本指令
8086 指令系统包括六大类指令:
- 数据传送指令 ⭐
- 算术运算指令 ⭐
- 逻辑运算和移位指令 ⭐
- 串操作指令 ⭐
- 控制转移指令 ⭐
- 处理器控制指令 ⭐
具体可参考 emu8086 -> help -> documentation and tutorials -> Complete 8086 Instruction Set ⭐
1.数据传送指令
功能:将源操作数的内容传送到目的操作数中。
2.算术运算指令
功能:完成加、减、乘、除运算。
3.逻辑运算和移位指令
功能:(1)完成逻辑“反”、“与"、”或“、”异或“和测试;(2)对数据的移动
逻辑运算和移位操作指令的共同点是:
- 可以按二进制位进行操作;
- 逻辑运算指令按逻辑门电路的运算规则
- 逻辑移位指令有左移和右移,移出的位都进入CF标志
- 因移空位的补充方式不同有多种指令形式
- 逻辑移位指令中,移动超过1次则用CL寄存器做计数器
- 执行逻辑操作指令,CF均被清0
4.串操作指令
串处理指令是针对存储器操作,其的共同点是:
- 源操作数指针 DS:SI 目的操作数指针 ES:DI
- 每操作一次SI,DI修改一次,方向由DF控制
- 串操作指令前通常加上重复前缀,此时,基本操作在满足条件的情况下得到重复,直至完成预设次数。重复操作的退出: CX控制 条件控制(ZF标志)
- 指令后不带操作数,操作数在此指令前给定。
5.控制转移指令
功能:执行跳转、调子程序、中断服务等。
- 8086程序的执行顺序由代码段寄存器CS和指令指针寄存器IP的值决定。
- 程序可以按顺序执行,也可以根据情况改变程序的执行顺序。
- 控制转移指令就是通过改变CS和IP的值来实现程序的转移。
6.处理器控制指令
三.程序结构
汇编程序有4种基本结构:
- 顺序结构 ⭐
- 分支结构 ⭐
- 循环结构 ⭐
- 子程序⭐
1.顺序结构
无分支,无循环,无转移,直线运行到底。例如:
;
;*****************************************************************************
; @file add2.asm
; @author Xiaoxiao
; @date 2020-9-29
; @brief 顺序结构:两个十六进制数相加
; @blog https://blog.csdn.net/weixin_43470383/article/details/108625923
;*****************************************************************************
;
data segment
X DW 2020H ; 被加数
Y DW 2019H ; 加数
RESULT DW ? ; 分配数存放单元
data ends
stack segment
dw 128 dup(0)
stack ends
code segment
assume cs:code,ds:data ; 段假设
start:
MOV AX, DATA
MOV DS, AX
; 给除CS以外的其他用到的段的段寄存器赋值
MOV AX, X
ADD AX, Y
MOV RESULT, AX
; 处理并存储结果
MOV AH, 4CH
INT 21H
; 程序运行结束,关闭并返回操作系统
code ends
end start
2.分支结构
指令执行过程中,需要进行判断、选择,来决定下一步执行的程序段。例如:
;
;*****************************************************************************
; @file pos_neg.asm
; @author Xiaoxiao
; @date 2020-9-29
; @brief 分支结构:判断MEMS单元数据,将结果存入MEMD单元。
; 若数据>0,结果为1,;若数据<0,结果为-1;若数据=0,结果为0
; @blog https://blog.csdn.net/weixin_43470383/article/details/108625923
;*****************************************************************************
;
DATA SEGMENT ;定义数据段
MEMS DB 08H ; 定义一个字节数据
MEMD DB 0 ; 定义一个字节数据,未赋值
DATA ENDS ; 数据段结束
CODE SEGMENT ;定义代码段
ASSUME CS: CODE, DS:DATA ;段属性说明
START: ;这里是程序的入口
MOV AX , DATA
MOV DS, AX ;初始化DS
MOV AL, MEMS ;将MEMS中数据送入AL中
CMP AL,0 ;将(Al)=08H与0进行比较
JGE NEXT ;≥0,转到标号NEXT处执行
MOV AL,-1 ; <0,结果为-1
JMP DONE ; 无条件跳转到标号DONE处执行
NEXT:
JE DONE ; =0,跳转到标号DONE处执行
MOV AL,1 ; >0,结果为1
DONE:
MOV MEMD,AL ; 将(AL)内容送入(MEMD)中
MOV AX, 4C00H
INT 21H ;程序结束,返回DOS
CODE ENDS ;代码段结束
END START ;汇编程序结束,指定程序入口地址
程序中的 JGE NEXT 指令即根据标志位 SF 和 OF 判断是否转移到程序段NEXT,如果SF = OF则转移
点击 single step 下一步执行 CMP AL,0
结果标志位 SF = OF,下一步执行 JGE NEXT
由于 SF = OF,执行 JGE NEXT 之后直接跳转到 NEXT,跳过
MOV AL,-1 ; <0,结果为-1
JMP DONE ; 无条件跳转到标号DONE处执行
接下来条件判断转移指令 JE DONE 类似,若标志位 ZF = 1,则转移。
3.循环结构
满足一定条件时,重复执行一段程序。
循环控制有3种:
- 计数法:将循环次数送到 CX 寄存器,循环一次之后,执行 LOOP 指令的时候自动对 CX 寄存器做减1操作。
- 比较结束条件法:满足比较条件,则结束循环。
- 设定标志结束法:比如可以设 0FFH 为结束标志。
例程:
;
;*****************************************************************************
; @file scan.asm
; @author Xiaoxiao
; @date 2020-9-29
; @brief 循环结构:在ES中从2000H单元开始存放了10个字符,寻找其中有无"A"
; @blog https://blog.csdn.net/weixin_43470383/article/details/108625923
;*****************************************************************************
;
data segment
DATA1 DW 0
DATA2 DW 0
ends
stack segment
dw 128 dup(0)
ends
code segment
assume cs:code,ds:data,ss:stack
start:
mov ax, data
mov ds, ax
mov es, ax
MOV DI, 2000H
MOV BX, DI ; 偏移地址
MOV CX, 0AH ; 10个字符
MOV AL, 'A' ; 待检索数据
CLD ; (SI、DI)地址自增
REPNZ SCASB ; 重复
JZ FOUND
MOV DI, 0
JMP DONE
FOUND:
DEC DI
MOV DATA2, DI
INC DI
SUB DI, BX ; 搜索次数
DONE:
MOV DATA1, DI
HLT
mov ax, 4c00h
int 21h
ends
end start ; set entry point and stop the assembler.
程序中的 REPNZ SCASB 即根据标志位 CX 和 ZF 判断是否循环进行串搜索 SCASB 指令。每执行一次 SCASB 指令,CX寄存器自动减1,若 CX ≠ 0 且 ZF = 0,搜索操作继续进行。
点击执行下一步指令 REPNZ SCASB。
CX ≠ 0 且 ZF = 0,经判断满足继续循环的条件。
执行完 SCASB 指令,CX内容减1。
CX ≠ 0 且 ZF = 0,经判断满足继续循环的条件。如此循环下去,CX 由原来的 000AH 变成 0000H 时,表明搜索完10次,结束循环。循环过程中,如果 CX ≠ 0 且 ZF = 1,表明搜索到“A”,循环也会终止。
4.子程序
- 将具有特定功能的代码封装成段,即为子程序(过程)。编写子程序能使程序看起来更简洁,方便二次调用。
- 若与主程序同段,则该子程序的属性为 NEAR,调用主程序时需要将 IP 寄存器的值入栈保存;若子程序与主程序不同段,则属性为 FAR,调用主程序时需要将 CS 和 IP 寄存器的值入栈保存。
- 子程序的最后一条指令时 RET,执行该指令,返回地址从堆栈中弹出,控制返回到被调用处。
下面是我们老师给出的程序,该程序的作用是判断随机数的奇偶性,分别存储至 odd_number 和 even_number ,并计数。
DATA SEGMENT
random_number DW 20 DUP(0)
odd_number DW 20 DUP(0)
even_number DW 20 DUP(0)
count DW 0
odd_count DW 0
even_count DW 0
DATA ENDS
STACK SEGMENT
DW 128 DUP()
STACK ENDS
CODE SEGMENT
ASSUME CS:CODE, DS:DATA, SS:STACK
START:
MOV AX,DATA
MOV DS,AX
MOV CX,20 ; 20次循环
LOOP_PRO:
CALL RAND ; 产生 WORD 随机数,保存在 BX 中
MOV SI, count
INC count
SHL SI, 1
MOV random_number[SI], BX
MOV AX, BX
AND AX, 0x0001
JZ EVEN_PRO
ODD_PRO:
MOV SI, odd_count
INC odd_count
SHL SI, 1
MOV odd_number[SI], BX
LOOP LOOP_PRO
JMP $
EVEN_PRO:
MOV SI, even_count
INC even_count
SHL SI, 1
MOV even_number[SI], BX
LOOP LOOP_PRO
JMP $
RAND PROC
PUSH CX
PUSH DX
PUSH AX
STI ; IF置1,允许响应可屏蔽中断
MOV AH,0 ;读时钟计数器值
INT 1AH
MOV BX,DX ;随机数存BX
POP AX
POP DX
POP CX
RET
RAND ENDP
CODE ENDS
END START
这段程序中包含1个子程序,RAND 子程序用于产生随机数。
LOOP_PRO 段调用 RAND 子程序,用于传递随机数,并判断奇偶性。
ODD_PRO 段用于处理奇数(存储数据并计数),EVEN_PRO 段用于处理偶数(存储数据并计数)。
参考:《微机原理与接口技术》(第4版)电子工业出版社