一.内容摘要
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 Huo Xiaoxiao
; @number 201821030208
; @date 2020-9-29
; @brief 顺序结构:两个十六进制数相加
; @blog https://blog.csdn.net/weixin_43470383/article/details/108625923
;*****************************************************************************
;data segmentX DW 2020H ; 被加数Y DW 2019H ; 加数RESULT DW ? ; 分配数存放单元
data endsstack segmentdw 128 dup(0)
stack endscode segment assume cs:code,ds:data ; 段假设
start:MOV AX, DATAMOV DS, AX; 给除CS以外的其他用到的段的段寄存器赋值MOV AX, XADD AX, YMOV RESULT, AX; 处理并存储结果MOV AH, 4CHINT 21H ; 程序运行结束,关闭并返回操作系统
code endsend start
2.分支结构
指令执行过程中,需要进行判断、选择,来决定下一步执行的程序段。例如:
;
;*****************************************************************************
; @file pos_neg.asm
; @author Huo Xiaoxiao
; @number 201821030208
; @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 , DATAMOV DS, AX ;初始化DSMOV AL, MEMS ;将MEMS中数据送入AL中CMP AL,0 ;将(Al)=08H与0进行比较JGE NEXT ;≥0,转到标号NEXT处执行MOV AL,-1 ; <0,结果为-1JMP DONE ; 无条件跳转到标号DONE处执行NEXT: JE DONE ; =0,跳转到标号DONE处执行MOV AL,1 ; >0,结果为1 DONE: MOV MEMD,AL ; 将(AL)内容送入(MEMD)中MOV AX, 4C00HINT 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 Huo Xiaoxiao
; @number 201821030208
; @date 2020-9-29
; @brief 循环结构:在ES中从2000H单元开始存放了10个字符,寻找其中有无"A"
; @blog https://blog.csdn.net/weixin_43470383/article/details/108625923
;*****************************************************************************
;
data segmentDATA1 DW 0DATA2 DW 0
endsstack segmentdw 128 dup(0)
endscode segment assume cs:code,ds:data,ss:stack
start:mov ax, datamov ds, axmov es, axMOV DI, 2000HMOV BX, DI ; 偏移地址MOV CX, 0AH ; 10个字符MOV AL, 'A' ; 待检索数据CLD ; (SI、DI)地址自增REPNZ SCASB ; 重复JZ FOUNDMOV DI, 0JMP DONEFOUND:DEC DIMOV DATA2, DIINC DISUB DI, BX ; 搜索次数DONE:MOV DATA1, DI HLTmov ax, 4c00h int 21h
endsend start ; set entry point and stop the assembler.
程序中的 REPNZ SCASB 即根据标志位 CX 和 ZF 判断是否循环进行串搜索 SCAS 指令。每执行一次 SCAS 指令,CX寄存器自动减1,若 CX ≠ 0 且 ZF = 0,搜索操作继续进行。
点击执行下一步指令 REPNZ SCASB。
CX ≠ 0 且 ZF = 0,经判断满足继续循环的条件。
执行完 SCAS 指令,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 SEGMENTrandom_number DW 20 DUP(0)odd_number DW 20 DUP(0)even_number DW 20 DUP(0)count DW 0odd_count DW 0even_count DW 0
DATA ENDSSTACK SEGMENTDW 128 DUP()
STACK ENDSCODE SEGMENT
ASSUME CS:CODE, DS:DATA, SS:STACKSTART: MOV AX,DATAMOV DS,AXMOV CX,20 ; 20次循环LOOP_PRO:CALL RAND ; 产生 WORD 随机数,保存在 BX 中MOV SI, countINC countSHL SI, 1MOV random_number[SI], BXMOV AX, BXAND AX, 0x0001JZ EVEN_PROODD_PRO:MOV SI, odd_countINC odd_countSHL SI, 1MOV odd_number[SI], BXLOOP LOOP_PROJMP $EVEN_PRO:MOV SI, even_countINC even_countSHL SI, 1MOV even_number[SI], BXLOOP LOOP_PROJMP $RAND PROCPUSH CXPUSH DXPUSH AXSTI ; IF置1,允许响应可屏蔽中断MOV AH,0 ;读时钟计数器值INT 1AHMOV BX,DX ;随机数存BXPOP AXPOP DXPOP CXRET
RAND ENDPCODE ENDS
END START
这段程序中包含1个子程序,RAND 子程序用于产生随机数。
LOOP_PRO 段调用 RAND 子程序,用于传递随机数,并判断奇偶性。
ODD_PRO 段用于处理奇数(存储数据并计数),EVEN_PRO 段用于处理偶数(存储数据并计数)。
参考:《微机原理与接口技术》(第4版)电子工业出版社