实验报告

课程名称:微处理器原理与应用

实验名称:CPUHomework2.2

实验时间:2022年10月1日

实验2.2 分支程序实验和循环程序实验

【上篇】 分支程序实验

1 知识点

程序控制指令又称为控制转移指令,包括:转移指令、循环控制指令、过程调用指令和中断指令 。转移指令又分为无条件转移指令条件转移指令

  1. 控制转移类指令

无条件转移指令 JMP , 条件转移指令 JCC , J也即JUNP, CC表示转移的条件


2. 单分支结构

当条件满足时,直接转到分支的下一条指令,否则执行单分支语句段,如求AX中数据的绝对值:

	CMP  AX,0
	JGE  NONEG
	NEG AX
NONEG: MOV RESULT,AX

cmp是比较指令,cmp的功能相当于减法指令

它不保存结果,只是影响相应的标志位。其他的指令通过识别这些被影响的标志位来得知比较结果

JGE: 大于等于则跳转

img

img

img

NEG: 把操作数按位取反加一 (求一个数的相反数)

思考: 如果条件改为 JL,以上分支程序段如何改写,比较程序段的复杂度

JL也即小于则跳转, 则程序可改写为

	CMP  AX,0
	JGE  NONEG
	NEG AX
NONEG: MOV RESULT,AX

  1. 双分支结构

条件选择任意,但要注意:当分支语句段1结束后,一定要用JMP指令跳过分支语句段2(跳到分支结束)

如判断AX中的数据符号,若为非负数,则 0 -> sign, 否则 1 -> sign

	CMP AX,0
	JGE NONEG
	MOV SIGN, -1
	JMP ENDO
NONEG: MOV SIGN,0
END0: ...
  1. 分支结构程序测试用例的设计

基本准则:测试用例要满足能够使每个分支都能执行一次,特别注意边界数据的测试(单独测试)

2 实验内容

  1. 编写一个程序,把AL寄存器中的两位十六进制数显示出来

3 实验步骤

  1. 用记事本编写.ASM源程序
  2. 对源程序进行汇编及连接,产生.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中的内容![mcu2.2](C:\Users\赵振\Desktop\mcu2.2.png)和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是逻辑左移指令,它的功能为:

  1. 将一个寄存器或内存单元中的数据向左移位

  2. 将最后移出的一位写入CF中

  3. 最低位用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 =42H

ASCII 码是用于显示表示的. 也就是只有知道一个字符的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 知识点

常用循环结构的汇编语言实现

  1. 对于确定循环次数的循环结构,一般使用 LOOP指令 构成循环,LOOP 指令中的标号为循环体的起始位置,但在循环之前要将循环次数送 CX
  2. 对于循环次数不定的循环结构,一般用 JCC 指令与标号一起构成循环
  3. 循环结构的汇编语言程序一般包含三部分,即

循环初始部分——循环之前准备相应的条件,如循环次数,相关变量/寄存器赋初值等

循环体——重复执行的程序代码,其中包含改变与循环条件有关的值

循环控制部分——判断循环条件,决定是否哦继续循环

循环程序的测试技巧

单步调试与分段调试结合:即对循环体内部的程序段的测试用单步执行的方法,执行1~2遍循环体,观察并分析每一步的结果及程序流程;

对于整个循环体程序段的测试,一般用G指令分段调试,通过结果判断循环体的正确程度

2 实验内容

编写一个程序,判别键盘上输入的字符;

若是19字符,则显示之;若是AZ或a~z字符,均显示’c’; 若是回车字符(ASCII码为0DH),则自动结束程序,若为其他字符则不显示,循环等待新的字符输入

3 实验步骤
  1. 用记事本编写.ASM源程序
  2. 对源程序进行汇编,产生.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 EQU

    EQU伪指令是通过文本替换的方式完成,定义非整数可以用 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,没有时一定要用(防止当两个操作数的宽度不一样)

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐