第三章 8088汇编语言程序设计 微机原理 第2版 课后答案

更新时间:2024-05-02 20:31:02 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

第三章 8088汇编语言程序设计

本章的主要内容是汇编语言语句行的构成,源程序的结构,汇编语言程序设计方法。 3.1 重点与难点

本章的学习重点是结构化程序设计思想,顺序、分支、循环结构的程序设计,子程序结构的设计与调用,中断指令的应用。另外,汇编语言伪指令的使用、源程序的结构等也是必须掌握的。

3.1.1 汇编语言语句行的构成 1.标记

(1)标识符:由数字、字母和下划线组成,且不能以数字开头,最大长度不超过31个字符。

(2)保留字:汇编语言中保留下来的具有特殊用途的字串,如指令、伪指令、寄存器名等都是保留字。保留字不可用作标识符。

(3)界符:程序或指令中两个部分的分隔符号。汇编语言源程序中可用的界符:

′〈 〉 ; , : ? $ ( ) + - = & [ ] * / ·

(4)常量:数字常量,可以使用不同的进制D、B、H、Q;字符串常量,由引号引起来的字符串,相当给出字符所对应的ASCII码串。

2.符号及其属性

(1)寄存器:8086/8088 CPU的寄存器可以作为指令的操作数。

(2)变量:即内存单元的符号地址。变量不能与保留字、段名重名。它有三个属性: 段属性,指变量所在段的段地址;

偏移量,指变量所在段的起始地址到变量地址之间的字节数,即偏移(有效、逻辑)地址。

类型,指指变量具有的字节数,包括BYTE、WORD、DWORD、QWORD和TBYTE等。 (3)标号:即代码段中某条指令的符号地址,由编程者根据需要确定的。标号不能与保留字重名,可使用字母、数字及下划线,但不允许用数字开头,字符个数不超过31个。

标号作为符号地址也有三个属性:段、偏移量和类型(NEAR、FAR)。 3.表达式

表达式是作为语句的一个操作数,在汇编时一个表达式得到一个值。 (1)操作数

数据——常数、符号常量;存储单元地址——常用符号地址表示。 (2)运算符

算术运算符:+、-、*、/、MOD。对地址的运算仅有+(加)、-(减)运算符。 逻辑运算符:AND、OR、NOT和XOR。注意,不要将其和同样名称的指令操作码相混淆。 关系运算符:EQ、NE、LT、GT、LE和GE。参与关系运算的两个操作数必须都是数值,

或同一段中的两个存储单元地址,运算结果为0FFFFH(真,True)或0(假,False)。

分析运算符:0FFSET——取一个标号或变量的偏移地址;

SEG——取一个标号或变量所在段的段地址;

TYPE——取变量和标号的类型(BYTE、WORD、DWORD或NEAR、FAR); SIZE——计算一个存储区的字节总数;

LENGTH——计算存储区中数据单元的数目,只对数据定义中的DUP操作有效。

综合运算符:PTR——用于暂时改变变量或标号的原有属性,只在当前语句中有效;

THIS——和PTR类似,用于改变存储区的类型; SHORT——指定一个标号为短标号。

4.语句

指令语句:主要由CPU指令组成,每条语句在汇编过程中都会产生对应的目标代码。 伪操作或伪指令语句:为汇编程序提供信息,让汇编程序在汇编过程中执行特定的功能。 两者本质区别在于,伪指令在汇编过程中不形成任何代码。 这里仅对伪指令进行总结。 (1)符号定义伪指令(赋值语句) 格式:符号常量 EQU 表达式 功能:把表达式的值赋给符号名。

说明:在程序中,用EQU语句赋值的符号名不能被重新赋值,但用“=”号赋值的符号名可以被重新赋值。若要重新赋值,必须使用解除伪指令PURGE。

(2)内存数据定义伪指令 格式:[变量名] 数据定义

表达式或数据项表

符号常量 = 表达式

功能:可为数据项分配存储单元,并根据需要设置其初值。还可用符号代表数据项。 说明:数据定义符有字节DB、单字DW、双字DD、8字节DQ、10字节DT;DUP()表示数据重复,“$”表示地址计数器当前值,“?”用于预留存储空间;数据项允许为字符串。

(3)段定义伪指令

格式:段名 SEGMENT [定位方式][连接方式][‘类别名’] 段体

段名 ENDS

功能:为程序汇编和链接说明了段名、分段的各种属性以及分段的开始和结束。段名是自定义符,开始的段名与结束的段名必须相同。段的长度不超过64KB。属性参数定义:

定位方式,指定段的起始地址边界。有四种方式:页边界PAGE、段边界PARA(系统隐含)、字边界WORD、字边界BYTE。

连接方式,告诉连接程序本段与其他段的连接方式。系统隐含为不写,表示本段不与任何段链接。STACK表示此段为堆栈段。

‘类别名’,是合法的自定义符,长度不超过40。凡是类别名相同的段在连接时均按先后顺序连接在相邻存储区中。

说明:段名的命名规则和变量名以及标号一样;单模块程序中属性参数可省略不写。 (4)段址寄存器说明伪指令 格式:ASSUME

段寄存器:段定义名1[,段寄存器:段定义名2,?]

功能:告诉汇编程序在汇编时,段寄存器CS、DS、SS和ES应具有的符号段基址。段寄存器实际值(CS除外)由传送指令在执行程序时赋值。

(5)过程(子程序)定义伪指令 格式:过程名

PROC [NEAR](或FAR)

过程名 ENDP

说明:过程名是自定义符。调用格式为:CALL 过程名

过程中的RET指令,实现从过程返回调用处。选NEAR,过程是段内调用,过程中的RET是段内返回。选FAR,过程是段间调用,过程中的RET是段间返回。系统默认是近过程。

(6)模块开始伪指令 格式:NAME

模块名

功能:该伪指令指明程序模块的开始,并指出模块名。模块名是自定义符,不能与系统保留字同名。每次汇编只能出现一次。若该伪指令不写,则取TITLE语句中的页标题前6个字符;若没有TITLE语句,则取源程序文件名为模块名。

(7)建立标题伪指令 格式:TITLE

标题

功能:建立每页标题。 (8)模块结束伪指令

格式:END [启动标号或过程名]

功能:告诉汇编程序源文件结束,并给出执行程序的入口。仅用于主模块才有意义。 (9)定位伪指令 格式:ORG 表达式

功能:把该伪指令以下所定义的内存数据或程序,从表达式的值所指定的起点开始连续存放,直至遇到新的ORG指令。表达式的值是一个无符号数。

(10)系统隐含进位制伪指令 格式:RADIX 表达式

功能:定义在源程序中书写数据时隐含进位制方式。表达式的值是2~16之间的十进制数,要遇到新的RADIX伪指令以后才改变隐含进位制。

3.1.2 汇编语言源程序的结构

1.源程序结构

8088汇编语言源程序采用分段结构的形式,一个完整的汇编语言源程序通常由若干个逻辑段组成,包括数据段、附加数据段、堆栈段和代码段。

2.源程序基本框架

DSEG SEGMENT ? DSEG ENDS ESEG SEGMENT

;数据定义(DB/DW/DD)

?

ESEG ENDS

SSEG SEGMENT STACK DW 512 DUP(?) ;堆栈段大小为1024B SSEG ENDS CSEG SEGMENT ASSUME CS:CSEG,DS:DSEG,ES:ESEG;指定段寄存器与段之间的对应关系

START: MOV AX,DSEG

MOV DS,AX

MOV AX,ESDG MOV ES,AX ;DS、ES段寄存器初始化 ? ;程序部分 MOV AX,4C00H ;8088/8086为MOV AH,4CH INT 21H ;程序结束,返回DOS

CSEG ENDS

END START

说明:CS段寄存器的初值,由系统自动指定为END后的地址; ES段寄存器的初值,可以用类似DS的方法设置,或由系统指定为定义了STACK属性的段。若未定义堆栈段,则系统默认使用系统堆栈。

3.1.3 汇编语言程序设计的方法 1.顺序结构程序设计的方法

顺序结构是最基本的结构。其特点是CPU按指令排列的顺序逐条执行。 2.分支(选择)结构程序设计的方法

分支结构,根据不同的条件转到不同的程序段执行。 3.循环结构程序设计的方法

循环结构,完成需要重复执行的工作。通常由三部分组成:

初始化部分,完成对地址指针寄存器、计寄存器等循环中用到的寄存器及存储器置初值; 循环体,完成需重复执行的工作;

循环控制,用于判断循环是否结束,若结束则跳出循环,未结束则修改地址指针和计数器值,为下一轮循环做准备。

4.混合结构程序设计方法

混合结构程序设计是指上述三种设计方法的组合应用,也是程序设计中最常用的方法, 5.子程序的设计方法

子程序(或过程)是完成某项特殊功能的程序模块,可以在程序中的任何地方多次被调用。用CALL指令调用子程序,用RET指令返回主程序;用伪指令PROC和ENDP定义子程序。

RET 主、子程序关系 CALL 主程序 子程序 (1)参数传递方式

通过寄存器传递,适用于传递参数个数少的情况;

通过程序存储器中的参数表传递,在主程序中把要传送的参数直接放在调用指令的后面,而在子程序中到堆栈中取返回地址,以获得参数。

通过堆栈传递,适用于参数较多,且子程序有嵌套、递归调用的情况。主程序将要传递的参数压入堆栈,子程序中再将这些参数从堆栈中弹出。

(2)寄存器和存储单元的内容保护(保护现场)

在主程序中用到的寄存器或存储单元,要在子程序里被用到,而主程序并不希望这些单元的内容被修改,此时必须在子程序入口处将这些单元内容压入堆栈保护起来。

6.其它设计方法介绍

(1)DOS和BIOS中断功能调用

DOS和BIOS为用户提供了两组系统服务程序,用户可以采用软中断指令INT N来调用。 DOS调用与BIOS调用相比,不依赖于硬件,通用性较好,但执行效率较低。 DOS和BIOS中断功能调用的使用方法如图所示:

置功能号n →(AH) 置入口参数 执行INT 21H 分析出口参数 (2)宏指令条件汇编 条件伪操作的一般格式如下: IF ?

条件

(语句组1)

;可选的

[ELSE] ? ENDIF

(语句组2)

如果条件为真,则汇编语句组1,否则如有ELSE则汇编语句组2,如无ELSE则不生成条件块。ENDIF表示结束条件汇编。下表给出了汇编语言的条件伪操作及其意义。

DATA SEGMENT ORG 1000H DATA1 DB 1,2,3,??,50 DUP(?) DATA ENDS CODE SEGMENT ASSUME CS:CODE,DS:DATA,ES:DATA START: MOV AX,DATA MOV DS,AX MOV ES,AX MOV CX,100 LEA SI,DATA1+99 LEA DI,DATA+149 STD REP MOVSB MOV AH,4CH INT 21H CODE ENDS END START

9. 解:源程序如下:

data segment

org 0500H buffer1 db x1,x2,x3,??,x100 org 1000H buffer2 db 100 dup(?) data ends stack segment para stack ‘stack’

db 100 dup(?) stack ends code segment assume cs:code,ds:data,es:data,ss:stack start proc far begin: push ds mov ax,0 push ax mov ax,data mov ds,ax mov es,ax mov ax,stack mov ss,ax mov cx,100 cld lea si,buffer1 lea di,buffer2 again: lodsb cmp al,0 je stop stosb loop again stop: ret start endp

code ends end begin

10. 解:源程序如下: data segment array sum_e sum_o data code start: again: odd: addr: code

11.解:编程如下: data mem max data code begin:

next:

db x1,x2,??x100 db 2 dup(0) db 2 dup(0) ends segment assume cs:code,ds:data mov ax,data mov ds,ax mov sum_e,0 mov sum_e+1,0 mov sum_o,0 mov sum_o+1,0 mov cx,100 mov bx,0 mov al,array[bx] test al,01h jnz odd add sum_e,al adc sum_e+1,0 jmp short addr add sum_o,al adc sum_o+1,0 inc bx loop again mov ah,4ch int 21h ends end start segment

dw x1,x2,??,x100 dw ? ends segment

assume cs:code,ds:data mov ax,data mov ds,ax lea si,mem mov cx,100 cld lodsw

mov max,ax dec cx lodsw

test ax,0001h jnz nnop cmp ax,max jle nnop xchg ax,max nnop: loop next mov ah,4ch int 21h code ends end begin

12. 解:源程序如下:

dseg segment mem dw x1,x2,??,x100 err db ‘overflow!’,0dh,0ah,‘$’ result dw ? dseg ends cseg segment assume cs:cseg,ds:dseg begin: mov ax,dseg mov ds,ax xor ax,ax mov si,ax mov cx,100 sum: add ax,mem[si] jc ovf add si,2 loop sum mov bx,100 mov dx,0 div bx mov result,ax jmp short exit ovf: lea dx,err mov ah,9 int 21h exit: mov ah,4ch int 21h cseg ends end begin

13. 解:可编程如下:

data segment num dw a,b,c,d sum dw ? data ends stack segment para stack db 100 dup(?) top equ $-stack stack ends

stack’‘

code segment assume cs:code,ds:data,ss:stack calcul proc far start: push ds mov ax,0 push ax mov ax,data mov ds,ax mov ax,stack mov ss,ax mov ax,top mov sp,ax lea bx,num mov cx,3 mov ax,[bx] again: mov dx,ax shl ax,1 push cx mov cl,3 shl dx,cl add ax,dx add ax,[bx+2] inc bx inc bx pop cx loop again mov sum,ax ret calcul endp code ends end start

注:a*10=a*2+a*8,可用逻辑左移指令实现乘法运算。

14. 解:源程序如下: data segment X dw x1 Y dw x2 Z dw x3 U dw ? data ends code segment assume cs:code,ds:data start: mov ax,data mov ds,ax mov ax,X or ax,ax jz clear mov ax,Y or ax,ax jz clear mov ax,Z

or ax,ax jz clesr add ax,X add ax,Y mov U,ax jmp exit clear: mov X,0 mov Y,0 mov Z,0 exit: mov ah,4ch int 21h code ends end start

15. 解:源程序如下:

dseg segment

buffer db x1,x2,??,x100 result db 3 dup(0) dseg ends cseg segment assume cs:cseg,ds:dseg start: mov ax,dseg mov ds,ax mov cx,100 mov si,0

next: mov al,buffer[si] cmp al,85 jb b85 inc result jmp short addr b85: cmp al,60 jb b60 inc result+1 jmp short addr b60: inc result+2 addr: inc si loop next mov ah,4ch int 21h cseg ends end start

本文来源:https://www.bwwdw.com/article/v71g.html

Top