274 lines
8.1 KiB
Markdown
274 lines
8.1 KiB
Markdown
# 实验四:循环程序设计
|
||
|
||
## 一、实验目的
|
||
|
||
1. 掌握循环程序的基本结构和设计方法
|
||
2. 理解LOOP指令的工作原理和使用方法
|
||
3. 掌握多重循环程序的设计技术
|
||
4. 理解循环计数器的作用和设置方法
|
||
|
||
---
|
||
|
||
## 二、基础性实验
|
||
|
||
### 实验4_1 循环结构一:求累加和
|
||
|
||
#### 实验目的
|
||
掌握利用LOOP指令实现循环程序的设计方法。
|
||
|
||
#### 实验内容
|
||
利用循环程序求1+2+3+...+10的和。
|
||
|
||
#### 程序代码
|
||
```asm
|
||
DATAS SEGMENT
|
||
LIST DB 01H,02H,03H,04H,05H,06H,07H,08H,09H,0AH
|
||
COUNT EQU 10
|
||
RESULT DB ?
|
||
DATAS ENDS
|
||
|
||
CODES SEGMENT
|
||
ASSUME CS:CODES, DS:DATAS
|
||
START:
|
||
MOV AX, DATAS
|
||
MOV DS, AX
|
||
|
||
LEA SI, LIST ; SI指向数据表首地址
|
||
MOV CX, COUNT ; 设置循环计数初值
|
||
XOR BL, BL ; BL清0,累加和初值为0
|
||
XOR BH, BH ; BH清0
|
||
|
||
L1:
|
||
MOV AL, [SI] ; 取出数据
|
||
ADD BL, AL ; 累加到BL
|
||
INC SI ; SI指向下一个数据
|
||
LOOP L1 ; CX!=0,继续循环
|
||
|
||
MOV RESULT, BL ; 保存结果
|
||
|
||
MOV AH, 4CH
|
||
INT 21H
|
||
CODES ENDS
|
||
END START
|
||
```
|
||
|
||
#### 程序分析
|
||
1. **数据段定义**:
|
||
- `LIST DB 01H,02H,03H,04H,05H,06H,07H,08H,09H,0AH` 定义了一个数据表,包含10个数据:01H,02H,...,0AH(即1,2,...,10)
|
||
- `COUNT EQU 10` 定义了数据个数为10
|
||
- `RESULT DB ?` 用于存储累加结果
|
||
|
||
2. **循环结构**:
|
||
- 使用SI作为指针(变址寄存器),通过 `LEA SI, LIST` 初始化为数据表首地址
|
||
- 使用CX作为循环计数器,初值为10
|
||
- 使用BL寄存器存储累加和,初值为0
|
||
|
||
3. **指令说明**:
|
||
- `MOV AL, [SI]`:从内存读取数据到AL
|
||
- `ADD BL, AL`:将AL中的数据累加到BL
|
||
- `INC SI`:SI指向下一个数据
|
||
- `LOOP L1`:CX自动减1,如果CX≠0则跳转到L1继续循环
|
||
|
||
4. **累加结果**:
|
||
- 1+2+3+...+10 = 55 = 37H
|
||
- 结果存储在BL中,即RESULT单元
|
||
|
||
#### 验证结果
|
||
运行程序后,RESULT中保存累加和37H(55)。
|
||
|
||
---
|
||
|
||
## 三、加强性实验
|
||
|
||
### 实验4_2 循环结构二:多重循环求累加和
|
||
|
||
#### 实验目的
|
||
掌握多重循环程序的设计方法,理解内嵌循环的汇编实现。
|
||
|
||
#### 实验内容
|
||
利用二重循环求累加和,体会外层循环和内层循环的配合。
|
||
|
||
#### 程序代码
|
||
```asm
|
||
DATAS SEGMENT
|
||
LIST DB 01H,02H,03H,04H,05H,06H,07H,08H,09H,0AH
|
||
COUNT EQU 10
|
||
RESULT DB ?
|
||
DATAS ENDS
|
||
|
||
CODES SEGMENT
|
||
ASSUME CS:CODES, DS:DATAS
|
||
START:
|
||
MOV AX, DATAS
|
||
MOV DS, AX
|
||
|
||
LEA SI, LIST ; SI指向数据表首地址
|
||
MOV CX, COUNT ; 外层循环计数
|
||
XOR BL, BL ; BL清0,累加和初值为0
|
||
|
||
L1:
|
||
PUSH CX ; 保存外层循环计数
|
||
MOV CX, COUNT ; 内层循环计数
|
||
XOR BH, BH ; BH清0
|
||
|
||
L2:
|
||
MOV AL, [SI] ; 取出数据
|
||
ADD BH, AL ; 内层累加到BH
|
||
INC SI ; SI指向下一个数据
|
||
LOOP L2 ; 内层循环
|
||
|
||
POP CX ; 恢复外层循环计数
|
||
ADD BL, BH ; 外层累加
|
||
LOOP L1 ; 外层循环
|
||
|
||
MOV RESULT, BL ; 保存结果
|
||
|
||
MOV AH, 4CH
|
||
INT 21H
|
||
CODES ENDS
|
||
END START
|
||
```
|
||
|
||
#### 程序分析
|
||
1. **二重循环结构**:
|
||
- **外层循环(L1)**:控制内层循环的执行次数
|
||
- **内层循环(L2)**:完成每次内层循环的累加操作
|
||
|
||
2. **寄存器保护**:
|
||
- `PUSH CX`:在进入内层循环前保存外层循环计数器的值
|
||
- `POP CX`:在内层循环结束后恢复外层循环计数器的值
|
||
- 这是多重循环中保护外层计数器的重要技巧
|
||
|
||
3. **执行流程**:
|
||
- 外层循环第1次:内层循环累加10个数到BH,然后BL+=BH
|
||
- 外层循环第2次:内层循环再次累加10个数到BH,然后BL+=BH
|
||
- 重复上述过程,直到外层循环结束
|
||
|
||
4. **累加原理**:
|
||
- 内层循环将10个数据累加到BH
|
||
- 外层循环将每次内层循环的BH结果累加到BL
|
||
- 最终结果仍然是所有数据的总和(55=37H)
|
||
|
||
5. **注意问题**:
|
||
- 8位寄存器(BL、BH)最大只能存储255,累加和不应超过这个范围
|
||
- 本例中10个数的累加和为55,小于255,结果正确
|
||
|
||
#### 验证结果
|
||
运行程序后,RESULT中保存最终的累加和37H(55),与实验4_1结果相同。
|
||
|
||
---
|
||
|
||
## 四、实验步骤
|
||
|
||
### 4.1 单重循环程序实验步骤
|
||
|
||
1. **编辑源程序**:在编辑器中输入实验4_1的源代码,保存为 `实验4_1_循环结构一.asm`
|
||
|
||
2. **汇编连接**:
|
||
```
|
||
MASM 实验4_1_循环结构一.asm;
|
||
LINK 实验4_1_循环结构一.obj;
|
||
```
|
||
|
||
3. **运行程序**:
|
||
```
|
||
实验4_1_循环结构一.exe
|
||
```
|
||
|
||
4. **调试观察**:
|
||
- 在DEBUG中加载程序:`DEBUG 实验4_1_循环结构一.exe`
|
||
- 使用 `T` 命令单步执行,观察CX的变化
|
||
- 使用 `R` 命令查看寄存器状态
|
||
- 使用 `D` 命令查看RESULT单元的内容
|
||
|
||
### 4.2 多重循环程序实验步骤
|
||
|
||
1. **编辑源程序**:在编辑器中输入实验4_2的源代码,保存为 `实验4_2_循环结构二.asm`
|
||
|
||
2. **汇编连接**:
|
||
```
|
||
MASM 实验4_2_循环结构二.asm;
|
||
LINK 实验4_2_循环结构二.obj;
|
||
```
|
||
|
||
3. **运行程序**:
|
||
```
|
||
实验4_2_循环结构二.exe
|
||
```
|
||
|
||
4. **调试观察**:
|
||
- 在DEBUG中观察PUSH/POP对栈的影响
|
||
- 跟踪内层循环L2和外层循环L1的执行
|
||
- 验证BH和BL的变化过程
|
||
|
||
---
|
||
|
||
## 五、思考题
|
||
|
||
### 5.1 LOOP指令的工作原理是什么?
|
||
|
||
LOOP指令是8086汇编语言中实现循环的基本指令,它完成以下操作:
|
||
1. 将CX寄存器减1
|
||
2. 如果CX≠0,则跳转到指定的标号处继续执行
|
||
3. 如果CX=0,则继续执行下一条指令(循环结束)
|
||
|
||
LOOP指令相当于以下两条指令的组合:
|
||
```
|
||
DEC CX
|
||
JNZ label
|
||
```
|
||
|
||
### 5.2 循环程序设计中需要注意哪些问题?
|
||
|
||
1. **循环计数器的初始化**:在循环开始前必须给CX设置正确的初值
|
||
|
||
2. **循环条件的设置**:确保循环能够正确终止,避免死循环
|
||
|
||
3. **寄存器的保护**:在多重循环中,需要保护外层循环的计数器,使用PUSH/POP指令
|
||
|
||
4. **数据指针的更新**:如果使用指针访问数据,必须正确更新指针(如INC SI)
|
||
|
||
5. **寄存器的选择**:根据数据范围选择合适的寄存器宽度,避免溢出
|
||
|
||
### 5.3 多重循环中为什么要保护外层循环计数器?
|
||
|
||
在多重循环中,内层循环也会使用CX作为计数器。如果不保护外层循环的CX值,当内层循环结束时,CX会被内层循环修改为0,导致外层循环无法正确继续。
|
||
|
||
通过PUSH指令在进入内层循环前保存CX的值,内层循环结束后用POP指令恢复,这样外层循环就能继续正确执行。
|
||
|
||
### 5.4 单重循环和多重循环有何区别?
|
||
|
||
1. **结构复杂度**:
|
||
- 单重循环:只有一层循环结构
|
||
- 多重循环:有多层循环嵌套,外层循环包含内层循环
|
||
|
||
2. **计数器使用**:
|
||
- 单重循环:CX在整个循环过程中只需要一个值
|
||
- 多重循环:需要保护外层循环计数器,内层循环可以复用CX
|
||
|
||
3. **应用场景**:
|
||
- 单重循环:处理简单的重复操作,如累加一个数组
|
||
- 多重循环:处理矩阵运算、多维数组遍历等复杂问题
|
||
|
||
---
|
||
|
||
## 六、实验总结
|
||
|
||
1. **循环程序的基本结构**:初始化循环计数器 → 循环体 → 更新循环条件 → LOOP指令跳转
|
||
|
||
2. **LOOP指令的理解**:LOOP指令自动完成CX减1和条件判断跳转,是实现循环的关键指令
|
||
|
||
3. **单重循环的应用**:适用于处理线性结构的数据,如数组求和、数据查找等
|
||
|
||
4. **多重循环的设计要点**:
|
||
- 外层循环控制执行次数
|
||
- 内层循环完成具体操作
|
||
- 使用PUSH/POP保护外层计数器
|
||
- 注意内外层循环的配合
|
||
|
||
5. **循环程序调试技巧**:
|
||
- 观察CX的变化,确认循环次数正确
|
||
- 检查指针更新,确保数据访问正确
|
||
- 注意寄存器的值,避免溢出
|
||
|
||
6. **循环程序设计的优势**:使用循环结构可以大大减少重复代码,提高程序的可读性和效率 |