汇编语言期末复习——第五章 模块化程序设计
Posted hotaru蛍
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了汇编语言期末复习——第五章 模块化程序设计相关的知识,希望对你有一定的参考价值。
一、子程序结构
- 子程序=函数=过程
- 子程序指令
- 子程序调用指令
-
CALL LABEL ;调用标号、子程序名指定的子程序
- 分成近调用(段内调用)和远调用(段间调用)
- 入栈返回地址:将CALL下条指令的地址压入堆栈
- 近调用:IP入栈
- 远调用:CS和IP都入栈
-
- 子程序返回指令
-
RET
- 分为有参数返回和无参数返回,都是出栈返回地址
-
- 过程定义伪指令
-
过程名 PROC ………… ………… 过程名 ENDP
过程定义应该书写于.EXIT和END之间;也可以安排在主程序开始执行的第一条语句之前
- PROC后面可以加参数:NEAR/FAR
-
- 子程序调用指令
- 子程序设计
- 利用过程定义伪指令声明
- 最后利用RET返回主程序,主程序执行CALL指令调用子程序
- 压入弹出成对使用使堆栈保持平衡
- 子程序开始时保护用到的寄存器内容,返回前逆序弹出恢复到原来的寄存器中。
- 安排在代码段的主程序之外
- 允许嵌套和递归
- 例:回车换行子程序
-
;eg502.asm .model small .stack .data .code .startup call dispcrlf .exit dispcrlf proc ;回车换行子程序 push ax ;保护寄存器 push dx mov dl,0dh ;输出回车字符 mov ah,2 int 21h mov dl,0ah ;输出换行字符 mov ah,2 int 21h pop dx ;恢复寄存器 pop ax ret ;子程序返回 dispcrlf endp end
-
二、参数传递
- 传递参数的多少反应程序模块间的耦合程度
- 传递的内容:
- 数据本身
- 数据的存储地址
- 传递方法:
- 寄存器
- 变量
- 堆栈
- 寄存器传递参数
- 把参数存于约定的寄存器
- 少量数据直接传递数值
- 大量数据只能传递地址
- 带有出口参数的寄存器不能保存和恢复
- 使用低八位寄存器时不保证不影响高八位数据
- 例:显示一个数据的数值(数值和ASC码的转换)
-
;eg410.asm .model small .stack .data STRING DB \'AX=\',4 DUP(?),\'H\',\'$\' .CODE .startup MOV AX,123AH MOV CX,4 XOR BX,BX AGAIN: ROL AX,1 ROL AX,1 ROL AX,1 ROL AX,1 PUSH AX CALL HTOASC MOV STRING+3[BX],AL INC BX POP AX LOOP AGAIN MOV AH,9 MOV DX,OFFSET STRING INT 21H .exit HTOASC PROC AND AL,0FH OR AL,30H CMP AL,\'9\' JBE ABCD ADD AL,7 ABCD: RET HTOASC ENDP end
-
- 有符号十进制整数的显示
-
;eg504.asm .model small .stack .data array dw 6789,-1234,0,1,-9876,32767,-32768,5678,-5678,9000 count = lengthof array .code .startup mov cx,count xor bx,bx again: mov ax,array[bx] ;将AX=入口参数 call dispsiw ;调用子程序,显示一个数据 add bx,type array call dispcrlf ;光标回车换行以便显示下一个数据 loop again .exit dispsiw proc ;显示有符号十进制数的通用子程序 push ax ;入口参数:AX=欲显示的数据(补码) push bx push dx test ax,ax ;判断数据是零、正数或负数 jnz dsiw1 mov dl,\'0\' ;是零,显示“0”后退出 mov ah,2 int 21h jmp dsiw5 dsiw1: jns dsiw2 ;是负数,显示“-” mov bx,ax ;AX数据暂存于BX mov dl,\'-\' mov ah,2 int 21h mov ax,bx neg ax ;数据求补(绝对值) dsiw2: mov bx,10 push bx ;10压入堆栈,作为退出标志 dsiw3: cmp ax,0 ;数据(商)为零,转向显示 jz dsiw4 xor dx,dx ;扩展被除数DX.AX div bx ;数据除以10:DX.AX÷10 add dl,30h ;余数(0~9)转换为ASCII码 push dx ;数据各位先低位后高位压入堆栈 jmp dsiw3 dsiw4: pop dx ;数据各位先高位后低位弹出堆栈 cmp dl,10 ;是结束标志10,则退出 je dsiw5 mov ah,2 ;进行显示 int 21h jmp dsiw4 dsiw5: pop dx pop bx pop ax ret ;子程序返回 dispsiw endp dispcrlf proc ;回车换行子程序 push ax ;保护寄存器 push dx mov dl,0dh ;输出回车字符 mov ah,2 int 21h mov dl,0ah ;输出换行字符 mov ah,2 int 21h pop dx ;恢复寄存器 pop ax ret ;子程序返回 dispcrlf endp end
-
- 把参数存于约定的寄存器
- 变量传递参数
- 子程序和主程序如果在同一模块不需要特殊说明
- 如果不在同一个模块需要利用PUBLEC EXTREN说明
- 例:
- 二进制输入程序
;eg505.asm .model small .stack .data count = 5 array dw count dup(0) temp dw ? ;共享变量 .code .startup mov cx,count mov bx,offset array again: call readbw ;调用子程序,输入一个数据 mov ax,temp ;获得出口参数 mov [bx],ax ;存放到数据缓冲区 add bx,type array call dispcrlf ;光标回车换行以便输入下一个数据 loop again .exit readbw proc ;二进制输入子程序 push ax ;出口参数:共享变量TEMP push bx push cx rdbw1: xor bx,bx ;BX用于存放二进制结果 mov cx,16 ;限制输入字符的个数 rdbw2: mov ah,1 ;输入一个字符 int 21h cmp al,\'0\' ;检测键入字符是否合法 jb rderr ;不合法则返回重新输入 cmp al,\'1\' ja rderr sub al,\'0\' ;对输入的字符进行转化 shl bx,1 ;BX的值乘以2 or bl,al ;BL和AL相加 loop rdbw2 ;循环键入字符 mov temp,bx ;把BX的二进制结果存放TEMP返回 pop cx pop bx pop ax ret rderr: push ds ;保护DS mov ax,cs ;因信息保存在代码段,所以需要设置DS=CS mov ds,ax lea dx,errmsg ;显示错误信息 mov ah,9 int 21h pop ds ;恢复DS jmp rdbw1 errmsg db 0dh,0ah,\'Input error, enter again: $\' readbw endp dispcrlf proc ;回车换行子程序 push ax ;保护寄存器 push dx mov dl,0dh ;输出回车字符 mov ah,2 int 21h mov dl,0ah ;输出换行字符 mov ah,2 int 21h pop dx ;恢复寄存器 pop ax ret ;子程序返回 dispcrlf endp end
- 有符号十进制数输入程序
;eg506.asm .model small .stack .data count = 5 array dw count dup(0) temp dw ? ;共享变量 .code .startup mov cx,count mov bx,offset array again: call readsiw ;调用子程序,输入一个数据 mov ax,temp ;获得出口参数 mov [bx],ax ;保存到数据缓冲区 add bx,2 call dispcrlf ;分行 loop again .exit readsiw proc ;输入有符号十进制数的通用子程序 push ax ;出口参数:变量TEMP=补码表示的二进制数值 push bx ;说明:负数用“-”引导 push cx xor bx,bx ;BX保存结果 xor cx,cx ;CX为正负标志,0为正,-1为负 rsiw0: mov ah,1 ;输入一个字符 int 21h cmp al,\'+\' ;是“+”,继续输入字符 jz rsiw1 cmp al,\'-\' ;是“-”,设置-1标志 jnz rsiw2 mov cx,-1 rsiw1: mov ah,1 ;继续输入字符 int 21h rsiw2: cmp al,\'0\' ;不是0~9之间的字符,则输入数据结束 jb rsiw3 cmp al,\'9\' ja rsiw3 sub al,30h ;是0~9之间的字符,则转换为二进制数 xor ah,ah ;AL零位扩展为AX shl bx,1 ;利用移位和加法实现数值乘10:BX←BX×10 mov dx,bx ;参见例3-8 shl bx,1 shl bx,1 add bx,1 add bx,ax ;已输入数值乘10后,与新输入数值相加 jmp rsiw1 ;继续输入字符 rsiw3: cmp cx,0 ;是负数,进行求补 jz rsiw4 neg bx rsiw4: mov temp,bx ;设置出口参数 pop cx pop bx pop ax ret ;子程序返回 readsiw endp dispcrlf proc ;回车换行子程序 push ax ;保护寄存器 push dx mov dl,0dh ;输出回车字符 mov ah,2 int 21h mov dl,0ah ;输出换行字符 mov ah,2 int 21h pop dx ;恢复寄存器 pop ax ret ;子程序返回 dispcrlf endp end
- 二进制输入程序
- 堆栈传递参数
- 注意PUSH后不能是常数
- 例子:
- 计算有符号数的平均值程序
;eg507.asm .model small .stack .data array dw 675, 354, -34, 198, 267, 0, 9, 2371, -67, 4257 .code .startup mov ax,lengthof array push ax ;压入数据个数 mov bx,offset array push bx ;压入数组的偏移地址 call mean ;调用求平均值子程序,出口参数:AX=平均值(整数部分) add sp,4 ;平衡堆栈(压入了4个字节数据) call dispsiw ;显示 .exit mean proc ;计算16位有符号数平均值子程序 push bp ;入口参数:顺序压入数据个数和数组偏移地址 mov bp,sp ;出口参数:AX=平均值 push bx ;保护寄存器 push cx push dx mov bx,[bp+4] ;BX=堆栈中取出的偏移地址 mov cx,[bp+6] ;CX=堆栈中取出的数据个数 xor ax,ax ;AX保存和值 mean1: add ax,[bx] ;求和 add bx,type array ;指向下一个数据 loop mean1 ;循环 cwd ;将累加和AX符号扩展到DX idiv word ptr [bp+6] ;有符号数除法,AX=平均值(余数在DX中) pop dx ;恢复寄存器 pop cx pop bx pop bp ret mean endp dispsiw proc ;显示有符号十进制数的通用子程序 push ax ;入口参数:AX=欲显示的数据(补码) push bx push dx test ax,ax ;判断数据是零、正数或负数 jnz dsiw1 mov dl,\'0\' ;是零,显示“0”后退出 mov ah,2 int 21h jmp dsiw5 dsiw1: jns dsiw2 ;是负数,显示“-” mov bx,ax ;AX数据暂存于BX mov dl,\'-\' mov ah,2 int 21h mov ax,bx neg ax ;数据求补(绝对值) dsiw2: mov bx,10 push bx ;10压入堆栈,作为退出标志 dsiw3: cmp ax,0 ;数据(商)为零,转向显示 jz dsiw4 xor dx,dx ;扩展被除数DX.AX div bx ;数据除以10:DX.AX÷10 add dl,30h ;余数(0~9)转换为ASCII码 push dx ;数据各位先低位后高位压入堆栈 jmp dsiw3 dsiw4: pop dx ;数据各位先高位后低位弹出堆栈 cmp dl,10 ;是结束标志10,则退出 je dsiw5 mov ah,2 ;进行显示 int 21h jmp dsiw4 dsiw5: pop dx pop bx pop ax ret ;子程序返回 dispsiw endp end
- 计算有符号数的平均值程序
三、宏结构
- 宏汇编
- 定义和调用
-
;声明
宏名 MACRO[形参表] …… …… ENDM
;调用
宏名 实参列表 - 例:
- 宏定义
WriteString macro msg push ax push dx lea dx,msg mov ah,9 int 21h pop dx pop ax endm
- 宏调用
WriteString msg
- 宏展开
push ax push dx lea dx,msg mov ah,9 int 21h pop dx pop ax
- 宏定义
-
- 宏和子程序
- 宏:
- 仅是源程序级的简化:宏调用在汇编时进行程序语句的展开,不需要返回;不减小目标程序,执行速度没有改变
-
通过形参、实参结合实现参数传递,简捷直观、灵活多变
-
当程序段较短或要求较快执行时,应选用宏
-
子程序
-
还是目标程序级的简化:子程序调用在执行时由CALL指令转向、RET指令返回;形成的目标代码较短,执行速度减慢
-
需要利用寄存器、存储单元或堆栈等传递参数
-
当程序段较长或为减小目标代码时,要选用子程序
-
- 宏:
- 定义和调用
-
一些其他的说明
-
MASM具体支持的多模块程序结构的方法:
-
源文件包含
-
模块连接
-
子程序库
-
库文件包含
-
-
源文件包含
-
各种常量定义、声明语句等组织在包含文件(*.inc)
-
常用的或有价值的宏定义放在宏定义文件(*.mac)
-
常用的子程序形成汇编语言源文件(*.asm)
-
-
使用源文件包含伪指令INCLUDE将指定的文本文件内容插入主题源程序文件。
-
四、课后习题!
5.1(1)指令“CALL BX“采用了指令的什么寻址方式?
寄存器间接寻址
(5)子程序采用堆栈传递参数,为什么要特别注意堆栈平衡问题?
子程序保持堆栈平衡才能保证执行RET指令时当前栈顶的内容是正确的返回地址。
主程序保持平衡才能释放传递参数占用的堆栈空间,否则多次调用可能使堆栈溢出。
5.2 判断题
(2)CALL指令的执行并不影响堆栈指针SP。
错,IP入栈 sp-2
(5)子程序需要保护寄存器,包括保护传递入口参数和出口参数的通用寄存器。
错,出口参数寄存器不能保护。
(6)利用INCLUDE包含的源文件实际上只是源程序的一部分。
对。
(7)宏调用与子程序调用一样都要使用CALL指令实现。
错。宏调用:宏名+参数列表
(8)宏定义可以与子程序一样,书写与主程序之后。
错,不可以。
5.3 填空题
(1)指令”RET i16"的功能相当于"RET"指令和“ADD SP, 2 .”组合。
(4)数值10在计算机内部用二进制“1010”编码表示,用十六进制表达是: 0AF .如果将该编码加37H,则为 41H ,他是字符 A 的ASCII码值。
(5)利用堆栈传递子程序参数的方法是固定的,例如寻址堆栈段数据的寄存器是 BP 。
(7)过程定义开始是“TEST PROC"语句,则过程定义结束的语句是 TEST ENDP 。宏定义开始是”DISP MACRO"语句,则宏定义结束的语句是 ENDM 。
5.5 请按如下说明编写子程序。
子程序功能:把用ASCII码表示的两位十进制数转换为压缩BCD码
入口参数:DH=十位数的ASCII码,DL=个位数的ASCII码
出口参数:AL=对应BCD码
;把用asc码表示的两位十进制数转换称压缩的BCD码 ;入口参数:DH=十位数的ASC码,DL=个位数的ASC码 ;出口参数:AL=对应的BCD码 .model small .stack .data ;数据段 inmsg db \'Enter two numbers(0-9): $\' errmsg db 0dh,0ah,\'Input error, enter again: $\' .code ;代码段,主程序 .startup mov dx,offset inmsg mov ah,9 int 21h ;输入两位十进制数字,结果分别保存到DH和DL rdhw1: xor dx,dx ;;DX一开始是0哇 mov bx,2 ;限制输入字符的个数 mov cl,8 rdhw2: mov ah,1 int 21h ;输入一个字符;;输入进AL cmp al,\'0\' ;检测键入字符是否合法 jb rderr ;不合法则返回重新输入 cmp al,\'9\' ja rderr ;不合法则返回重新输入 shl dx,cl;;将十位上的数左移至高八位DH上 在第二次循环的时候起作用!! or dl,al;;这步应该是相当于ADD DL,AL吧 dec bx jnz rdhw2 ;继续输入 call btobcd ;调用子程序 int 3 ;中断 jmp done rderr: mov dl,0dh ;输出回车字符 mov ah,2 int 21h mov dl,0ah ;输出换行字符 mov ah,2 int 21h lea dx,errmsg ;显示错误信息 mov ah,9 int 21h jmp rdhw1 ;重新输入 done: nop .exit ;主程序结束,退出 btobcd proc ;子程序 ;出口参数:AL=输入的数据 push cx xor ax,ax mov cl,4 and dh,0fh ;dh高4位清零 or al,dh ;AL和DH相加;;AL不是零么??? and dl,0fh ;减30H;;为啥不直接用SUB呢???为什么??? shl ax,cl ;AX左移4位 or al,dl ;AL和DL相加 pop cx ret btobcd endp end ;为什么子程序保护了CX不保护DX?? 入口参数不用保护嘛??
5.7 编写一个程序,在键盘上按一个键,将其返回的ASCII码值表示出来,如果按下ESC键(1BH)则退出。
;显示输入字符的ASC码 ;如果输入的是ESC(1BH)则退出 .model small .stack .data asc db \'00H\',13,10,\'$\' crlf db 13,10,\'$\' .code .startup ReadAsc: mov ah,1 int 21h cmp al,1Bh jz done ;输入一个字符,输入ESC退出;ESC的ASCii码为1BH mov dx,offset crlf mov ah,9 int 21h ;输出回车换行 mov cx,2 xor bx,bx;;BX用做asc数组下标 again: rol al,1 ;高4位循环移位进入低4位,作为子程序的入口参数 rol al,计算机组成原理期末复习必备知识点大全——第五章(输入输出系统)
前文导读:
一、概述
1)输入输出系统的发展
输入输出系统发展共经历4个阶段:
早期阶段→接口模块和DMA阶段→通道阶段→I/O处理机阶段
1.早期阶段:CPU和外设分散连接、串行工作、耦合性强,机器速度慢、价格高。
2.接口模块和DMA阶段:具有总线模式,主机通过各种接口连接外设,具有中断或DMA功能。
3.通道阶段:
通道是用来负责管理I/O设备以及实现主存与I/O设备之间交换信息的部件,可视为从属于CPU的专用处理器。
通道具有专门指令,能独立执行由通道指令编写的输入输出程序。
4.I/O处理机阶段: 外围处理机又称为I/O处理机,独立于主机工作,除了具备通道功能之外,还具备码制转换、格式处理、数据校验等功能。
2)输入输出系统的组成
输入输出系统由I/O软件和I/O硬件组成两部分组成。
3)I/O设备与主机的联系方式
I/O设备编址方式:
统一编址: I/O占用存储器地址空间,无须专门的I/O指令。减少了存储器最大容量。采用不同地址码来区分访问对象。
独立编址: I/O地址与存储器地址分开,采用专门指令来访问I/O。不占用主存容量。采用不同指令形式来区分访问对象。
设备寻址:每台设备都有设备号,启动设备时,由I/O指令的设备码字段直接指出设备号,经接口中的设备选择电路选中设备。
传送方式:
并行:多位同时传送,需要多条数据线,速度快。
串行:一条数据线和一条地线,逐位传送,速度慢,适用于远距离传送。
4)I/O设备与主机信息传送控制方式
程序查询方式:CPU和I/O串行工作, I/O工作时CPU原地踏步。
中断方式:CPU和I/O部分并行工作,在中断服务子程序中完成数据的传送。
中断程序消除了CPU原地踏步的情况,但是,CPU在响应中断请求后,必须暂停现程序,转而去执行中断服务子程序,消耗了CPU资源,并且,中断处理过程是有开销的。
DMA方式:在主存和I/O之间建立数据传送的直接通道,由DMA控制器来完成信息传送,不需要中断CPU的运行。进一步提高了CPU和I/O的并行程度。
周期窃取:若出现DMA和CPU同时访问主存,CPU总是将总线占有权让给DMA,通常把DMA的这种占有称为窃取或挪用。窃取的时间一般是一个存取周期,所以称为窃取周期。
三种方式比较:
通道方式:
外围处理机方式:
二、I/O设备
三、I/O接口
接口可以看做两个系统或部件之间的交接部分,它既是两种硬件设备之间的连接电路,也可以看做两个软件之间的共同逻辑边界。
每一台I/O设备都是通过I/O接口挂到系统总线上的。I/O总线包括数据线、设备选择线、命令线和状态线。
I/O接口的基本组成
数据线:数据线是I/O设备与主机之间数据代码的传输线。
设备选择线:设备选择线是用来传送设备码的。
命令线:命令线主要是用以传输CPU向设备发出的各种命令信号。
状态线:状态线是将I/O设备的状态向主机报告的信号线。
程序查询方式
程序查询方式的核心问题在于每时每刻需不断查询I/O设备是否准备就绪。
传送一个数据的流程
程序中断方式
中断 :计算机在执行程序的过程中,当出现异常情况或特殊请求时,CPU停止现行程序的运行,转向对这些异常情况或特殊请求的处理,处理结束后再返回到现行程序的断点处,继续执行原程序,这就是中断。
中断接口电路:
INTR 中断请求触发器 INTR=1有请求
MASK中断屏蔽触发器 MASK=1被屏蔽
D 完成触发器
例题:结合程序中断方式,简要说明I/O设备向CPU提出中断请求的条件
没有中断屏蔽信号mask=0,收到来自CPU中断查询,d触发器为1,设备工作结束
程序中断方式接口电路的基本组成
CPU响应中断的条件和时间
条件:CPU允许中断:中断允许触发器EINT=1。(开中断、关中断指令可以改变EINT)
相关中断的掩码(MASK)为0
时间:每条指令执行结束(CPU发出中断查询信号(将INTR置1))
中断处理的五个阶段:
中断请求:INTR
中断判优:链式排队
中断响应:INTA,得到中断号
中断服务:根据中断号查中断向量表,得到中断入口地址,跳转到中断服务程序
中断返回:从中断服务程序中返回到源程序继续执行
中断服务程序流程
保护现场
断点保护: 中断隐指令完成
保存寄存器值:进栈指令
中断服务:(视情形开中断)
恢复现场
出栈指令
中断返回
中断返回指令
单重中断与多重中断
单重中断:不允许中断现行的中断服务程序
多重中断(中断嵌套):允许更高级别的中断源中断现行的中断服务程序
DMA方式
DMA访问主存有三种可能:
CPU此时不访存:总线立刻交给DMA
CPU此时正访存:CPU访存结束后总线立刻交DMA
CPU与DMA同时请求访存:总线交DMA
以上是关于汇编语言期末复习——第五章 模块化程序设计的主要内容,如果未能解决你的问题,请参考以下文章
华南理工大学 电力电子技术(王兆安) 期末复习笔记3 第五章第六章第七章
华南理工大学 电力电子技术(王兆安) 期末复习笔记3 第五章第六章第七章
华南理工大学 电力电子技术(王兆安) 期末复习笔记3 第五章第六章第七章