【实验作业】微处理器原理与应用 CPUHomework2.2【分支程序实验和循环程序实验】
Navigator
实验报告
课程名称:微处理器原理与应用
实验名称:CPUHomework2.2
实验时间:2022年10月1日
实验2.2 分支程序实验和循环程序实验
【上篇】 分支程序实验
1 知识点
程序控制指令又称为控制转移指令,包括:转移指令、循环控制指令、过程调用指令和中断指令 。转移指令又分为无条件转移指令和条件转移指令
- 控制转移类指令
无条件转移指令 JMP , 条件转移指令 JCC , J也即JUNP, CC表示转移的条件

2. 单分支结构
当条件满足时,直接转到分支的下一条指令,否则执行单分支语句段,如求AX中数据的绝对值:
CMP AX,0
JGE NONEG
NEG AX
NONEG: MOV RESULT,AX
cmp是比较指令,cmp的功能相当于减法指令
它不保存结果,只是影响相应的标志位。其他的指令通过识别这些被影响的标志位来得知比较结果
JGE: 大于等于则跳转
NEG: 把操作数按位取反加一 (求一个数的相反数)
思考: 如果条件改为 JL,以上分支程序段如何改写,比较程序段的复杂度
JL也即小于则跳转, 则程序可改写为
CMP AX,0
JGE NONEG
NEG AX
NONEG: MOV RESULT,AX
- 双分支结构
条件选择任意,但要注意:当分支语句段1结束后,一定要用JMP指令跳过分支语句段2(跳到分支结束)
如判断AX中的数据符号,若为非负数,则 0 -> sign, 否则 1 -> sign
CMP AX,0
JGE NONEG
MOV SIGN, -1
JMP ENDO
NONEG: MOV SIGN,0
END0: ...
- 分支结构程序测试用例的设计
基本准则:测试用例要满足能够使每个分支都能执行一次,特别注意边界数据的测试(单独测试)
2 实验内容
- 编写一个程序,把AL寄存器中的两位十六进制数显示出来
3 实验步骤
- 用记事本编写.ASM源程序
- 对源程序进行汇编及连接,产生.EXE文件
4 流程图

5 参考程序(源代码)
1 显示AL中两位十六进制数程序: DISPHEX.ASM
CODE SEGMENT ; 定义代码段
ASSUME cs: CODE ; 伪指令ASSUME将代码段CODE与CS寄存器联系起来
START: MOV AL, 3EH ; 定义程序入口,开始代码段,并将3EH存入AL寄存器(0011 1110)
MOV BL, AL ; 将AL中的数据存入BL中,方便之后更改AH中的内容
MOV DL, AL ; 将AL中的数据存入DL中
MOV CL, 4 ; 将4存入CL中,CL在位移指令中作位移次数计数器
SHR DL, CL ; 将DL右移4位,将低位移出(0000 0011)
CMP DL, 9 ; 将DL中的内容和9作比较,也即进行DL - 9的运算
JBE NEXT1 ; 若DL中的内容低于或等于9,则跳转到NEXT1,反之执行下一条语句
ADD DL, 7 ; 把DL中的数据加7(如果DL中的数大于9,本身加37H则为对应的ASCII码)
NEXT1: ADD DL, 30H ; 把DL中的数据加30H (DEC:48)(如果DL中的小于等于9,本身加30H则为对应的ASCII码)
MOV AH, 2 ; 将2存入AH中
INT 21H ; 显示高位ASCII码(中断,此时AH中的内容为2,因此输出字符到显示器)
MOV DL, BL ; 将BL中的数据存入DL
AND DL, 0FH ; DL与0F按位进行逻辑与运算,将高位置零
CMP DL, 9 ; 将DL中的内容和9作比较,也即进行DL - 9的运算
JBE NEXT2 ; 若DL中的数据低于或等于9,则跳转到NEXT2,反之执行下一条语句
ADD DL, 7 ; 把DL中的数据加7
NEXT2: ADD DL, 30H ; 把DL中的数据加30H
MOV AH, 2
INT 21H ; 显示低位ASCII码(中断,此时AH中的内容为2,因此输出字符)
MOV AH, 4CH ; 将4C存入AH中
INT 21H ; 中断,此时AH中的内容为4C,因此返回DOS系统
CODE ENDS ; 结束代码段
END START ; 结束程序
shl和shr是逻辑移位指令, 其中shl是逻辑左移指令,它的功能为:
将一个寄存器或内存单元中的数据向左移位
将最后移出的一位写入CF中
最低位用0补充
注意:如果移动位数大于1时,必须将移动位数放在cl中
此处的shr是逻辑右移指令,它和shl所进行的操作刚好相反
一个用于无符号数,一个用于有符号数,即使是在intel的官方手册中,也易混淆
JBE:JUMP SHORT IF BELOW OR EQUAL (无符号
JLE:jump short if less or equal (有符号
below有人译为低于,less有人译为小于,一个用于无符号数,一个用于有符号数,即使是在intel的官方手册中,也易混淆0的ASCII码是30H,1的ACII码是31H,一直到9的ASCII码是39H,所以,数值0-9要显示在屏幕上,就要变成它的ASCII码,加上30H就可以了
A的ASCII码是41H,十进制10对应十六进制的A, A H + 37 H =41H
B的ASCII码是42H,十进制11对应十六进制的B, B H + 37 H =42HASCII 码是用于显示表示的. 也就是只有知道一个字符的ASCII码,才能把它显示到屏幕上
AND 逻辑与指令 :对两个操作数进行按位逻辑与操作,结果送回目的操作数,主要用于操作数的某些位保留(与1相与),某些位的清除(与0相与)
OR 逻辑或指令 :对两个操作数进行按位逻辑或操作,结果送回目的操作数,主要用于操作数的某些位保留(与0相或),某些位变为1(与1相或)
6 用记事本编写.ASM源程序并保存
将扩展名改为.asm默认使用Vim打开,编辑后保存到E:\microcomputer\masm5路径下

7 对源程序进行汇编及连接,产生.EXE文件
在DOS环境下对.asm文件进行编译, 生成.obj文件

链接生成可执行文件

顺便用dir命令查看一下当前目录的全部文件


结果打印的是3>, 显然与预期不符,后反复检查得知少写了一条ADD DL,7语句,后重新执行了之前的步骤



这一次为了与前次区别,开启了键盘大写锁定,然后一步一步执行最后成功输出3E!
【下篇】循环程序设计
1 知识点
常用循环结构的汇编语言实现
- 对于确定循环次数的循环结构,一般使用 LOOP指令 构成循环,LOOP 指令中的标号为循环体的起始位置,但在循环之前要将循环次数送 CX
- 对于循环次数不定的循环结构,一般用 JCC 指令与标号一起构成循环
- 循环结构的汇编语言程序一般包含三部分,即
循环初始部分——循环之前准备相应的条件,如循环次数,相关变量/寄存器赋初值等
循环体——重复执行的程序代码,其中包含改变与循环条件有关的值
循环控制部分——判断循环条件,决定是否哦继续循环
循环程序的测试技巧
单步调试与分段调试结合:即对循环体内部的程序段的测试用单步执行的方法,执行1~2遍循环体,观察并分析每一步的结果及程序流程;
对于整个循环体程序段的测试,一般用G指令分段调试,通过结果判断循环体的正确程度
2 实验内容
编写一个程序,判别键盘上输入的字符;
若是19字符,则显示之;若是AZ或a~z字符,均显示’c’; 若是回车字符(ASCII码为0DH),则自动结束程序,若为其他字符则不显示,循环等待新的字符输入
3 实验步骤
- 用记事本编写.ASM源程序
- 对源程序进行汇编,产生.EXE文件
4 流程图

5 程序源代码
CODE SEGMENT ; 定义代码段
ASSUME CS:CODE ; 联系CS寄存器
START: ; 代码段开始
MOV AH, 1 ; 将1存入AH
INT 21H ; 产生中断,键盘输入一个字符到AL中
MOV BL, AL ; 将AL中的内容存入BL
CMP BL, 0DH ; 将BL中的内容与0D比较
JE OVER ; 如果是回车则执行OVER,准备结束程序
CMP BL, '1' ; 将BL中的内容与'1'的ASCII码比较
JB START ; 如果小于则返回START
CMP BL, '9' ; 将BL中的内容与'9'的ASCII码比较
JBE NEXT1 ; 如果小于等于则执行NEXT1输出该字符本身
CMP BL, 'A' ; 同理
JB START ; 如果是其他字符则返回START
CMP BL, 'Z'
JBE NEXT2 ; 如果是A~Z则输出c
CMP BL, 'a' ; 同理
JB START ; 如果是其他字符则返回START
CMP BL, 'z'
JBE NEXT2 ; 如果是a~z则依旧输出c
NEXT1: MOV DL, BL; 将BL中的值传入DL
MOV AH, 2
INT 21H ; 输出数字
JMP START
NEXT2: MOV DL, 'c'; 将'c'传入DL
MOV AH, 2
INT 21H ; 输出'c'
JMP START
OVER: MOV AH, 4CH
INT 21H
CODE ENDS
END START
补充INT 21H系统调用
AH = 1 :键盘输入一个字符到AL中
AH = 2 :输出DL寄存器的字符到显示器
AH = 4C : 返回DOS系统
6 用记事本编写.ASM源程序
本次我直接将写好的源代码复制到记事本中,再将文件格式改为.asm并保存,上网查询了一下DISPHEX是displaceHEX的意思,所以文件名也延续了前面的设置为DISPHEX3.asm
7 对源程序进行汇编及连接,产生.EXE文件
编译

Link

dir命令查看一下文件

运行,成功!

【实验心得】
这次的汇编实验明显比之前的实验更有难度,首先是要自己设计好程序的大致流程,并使用流程图软件进行绘制,最后用编辑器写成可以编译连接运行的代码
通过这次实验,首先是对之前C语言和其他高级编程语言(之前学过Java基础)的分支程序和循环程序设计的一个回顾,对更底层的程序指令控制有了更深入的了解
之前画过思维导图,类与对象的关系层级图,但很少画流程图(可能是因为还没有学数据结构与算法之类的),只在计算思维和电路课上画过一些,感觉用处有限,但是这次的实验让我感觉到了流程图的梳理作用,可以让指令间各种复杂的,容易混淆的地方变得更加清晰,提高程序设计的效率
本次实验写的汇编指令是目前最多的,这也充分展示了在较多指令下注释的重要性,通过一条一条注释,更容易理解其层级关系。也正是因为指令较多,我在编写.asm源程序的时候少写了一条指令,就让程序出错了,通过思考和检查终于发现原因,这也提示我在Code的时候要严谨仔细
【知识点总结】
- 4K对齐和偶对齐我已经在前面的作业中提过了,这里再提一下:随着时代发展,硬盘容量不断扩展,使得之前定义的每个扇区512字节不再是那么的合理,于是将每个扇区512字节改为每个扇区4096 个字节,也就是现在常说的“4K扇区”。随着NTFS成为了标准的硬盘文件系统,其文件系统的默认分配单元大小(簇)也是4096字节,为了使簇与扇区相对应,即使物理硬盘分区与计算机使用的逻辑分区对齐,保证硬盘读写效率,所以就有了“4K对齐”的概念
NTFS(New Technology File System)是Windows NT内核的系列操作系统支持的、一个特别为网络和磁盘配额、文件加密等管理安全特性设计的磁盘格式,提供长文件名、数据保护和恢复,能通过目录和文件许可实现安全性,并支持跨越分区
-
EQU伪指令
EQU伪指令可以定义非整数,语法为:name EQU expression
name EQU symbol
name EQUEQU伪指令是通过文本替换的方式完成,定义非整数可以用 name EQU
的形式,当汇编器在程序后面遇到name时会将它替换成 里的内容, 注意,EQU伪指令 不可被重定义 -
等号伪指令用于定义整数或整数表达式的符号常量,语法为:
name = expression
如果“expression”为整数表达式则需要将它括起来。如:COUNT = (10 * 10),等号伪指令定义的符号常量是可以被重定义的
-
ORG指令是连接时使用的,而不是汇编那一步使用的。即不是CPU的一条指令,而是给编译器看的伪指令,在51单片机、x86 dos、win32 exe中实现都有差异
ORG是Origin的缩写:起始地址源,在汇编语言源程序的开始通常都用一条ORG伪指令来实现规定程序的起始地址。如果不用ORG规定则汇编得到的目标程序将从0000H开始
-
PTR 是 pointer(指针)的缩写。
汇编里面 ptr 是用来临时指定类型的(也即ptr是临时的类型转换,相当于C语言中的强制类型转换)
如 mov ax,bx ; 是把BX寄存器里的值赋予AX,由于二者都是寄存器,长度已定(word型),所以没有必要加“WORD”
mov ax,word ptr [bx]; 是把内存地址等于“BX寄存器的值”的地方所存放的数据,赋予ax。由于只是给出一个内存地址,不知道希望赋予ax的,是byte还是word,所以可以用word明确指出;如果不用,也即mov ax, [bx] ; 则在8086中是默认传递一个字给ax。
所以有寄存器时一般不用ptr,没有时一定要用(防止当两个操作数的宽度不一样)
更多推荐






所有评论(0)