目录
扫描二维码关注公众号,回复: 14301693 查看本文章![]()
目的与要求
分析和理解实验指定的问题
利用LC-3的汇编代码设计实现相关程序
熟练掌握循环、分支程序设计方法
内容与方法
- 背景
- 16名学生成绩排序,及统计分析
- 成绩分类规则
- A:全班排名前25%,且成绩在85分及以上
- B:非A成绩,全班排名前50%,且成绩在75分及以上
- C:非A、B成绩
- 要求
- 使用LC-3汇编语言,编写程序实现以上功能
- 输入
- 16名学生成绩,存储于x3200至x320F
- 每个成绩为0至100之间,由16比特无符号整数表示
- 输出
- 成绩降序排序,并存储于x4000至x400F内存位置,x4000位置成绩为最高成绩
- 得A、B成绩的学生总人数,分别存储于x4100,及x4101位置
步骤与过程
程序总体设计
- 根据题目,首先要实现的是成绩的存储。首先我用标号SCORE存储成绩首地址x3200,用data文件记录16个成绩于起始位置:.ORIG x3200。
- 其他重要地址和常量用标号表示如下:
SCORE .FILL x3200 ;成绩存放起始地址
RES .FILL x4000 ;成绩降序结果存放起始地址
Anum .FILL x4100 ;存放A地址
Bnum .FILL x4101
nAscore .FILL -85 ;A分数相反数
nBscore .FILL -75
StuNUM .FILL 16 ;学生人数
ONE .FILL 1 ;1
- 算法流程——具体实现步骤如下:
- 将成绩复制到结果区:COPY循环
- 冒泡排序:2层嵌套循环
- 计算A B人数:各2个循环(CountA CountB)
- 结果保存:STORE
核心数据结构——冒泡排序
C++代码如下:
for(int i=1;i<n;i++){
For(int j=0;j<n-I;j++){
If(score[j]<score[j+1]){
Swap(score[j],score[j+1])
}
}
}
调试过程
因为程序步骤较多,我进行分模块编写和调试,逐步完成。
成绩数据文件data编写和程序数据初始
- 代码编写编译(图1)
R1存成绩存放初始地址SCORE(x3200),R7存结果降序成绩初始地址RES(x4000)。标号编写。
Figure 1 data编写和程序数据初始
- 运行结果无误(图2)
Figure 2 数据获得和初始成功
成绩复制
先将成绩直接复制到结果区,在结果区排序。
- 编写编译运行(图3)
Figure 3 成绩复制代码编译运行
- 结果正确,x3200和x4000存放的数据一样(图4)
Figure 4 成绩复制成功
冒泡排序
- 编译通过(图5)
Figure 5 冒泡成功编译运行
- 答案错误,代码有误,经过单步调试发现是每轮冒泡循环没有把成绩指针指向首位。(图6)
Figure 6 调试过程
- 修改代码(图7)
每次循环都初始成绩指针指向第一个成绩。修改后答案正确
Figure 7 修改冒泡排序
A B计数保存
2个循环CountA和CountB遍历前4和前8个数,获得A B人数,并保存。(图8)
Figure 8 程序结果正确
核心代码
.ORIG x3000 ;程序开始
LD R1,SCORE ;R1为存放成绩初始地址
LD R7,RES ;R7存放成绩降序结果地址
LD R2,StuNUM ;R2装入学生人数
;
; 成绩复制至结果区(loop)
;
COPY LDR R3,R1,0 ;R3存成绩
STR R3,R7,0 ;成绩存结果
ADD R1,R1,1 ;下一个成绩
ADD R7,R7,1 ;结果成绩指针移向下一个
ADD R2,R2,-1 ;计数减1
BRp COPY ;继续循环直至全部复制
; 冒泡排序
;
LD R2,ONE ;R2初始1,外层循环i,轮次
;
; 外层循环LOOP1(R2 0<i<n)
LOOP1
; 内层循环(R3 0<=j<n-i)
;
LD R7,RES ;R7存放成绩降序结果首地址
AND R3,R3,0 ;R3清零, 里层循环j,下标
ADD R1,R2,-16 ;R1=-(n-i)
LOOP2 LDR R4,R7,0 ;R4存SCORE[j]
LDR R5,R7,1 ;R5存SCORE[j+1]
NOT R6,R4
ADD R6,R6,1
ADD R6,R6,R5 ;R6=SCORE[j+1]-SCORE[j]
BRnz FLAG ;如果SCORE[j+1]<=SCORE[j],不用交换直接跳过
;
; 交换SCORE[j+1] SCORE[j]
;
STR R5,R7,0
STR R4,R7,1
;
FLAG
ADD R7,R7,1 ;指向下一成绩
ADD R3,R3,1 ;j++
ADD R6,R3,R1 ;R6=j-(n-i)
BRn LOOP2 ;如果j<n-i,继续内层循环
;
; 内层循环结束
ADD R2,R2,1
ADD R6,R2,-16;R6=i-n
BRn LOOP1 ;如果i<n,继续外层循环
;
; 外层循环结束,冒泡排序完成
; 计数A B人数
;
LD R2,nAscore ;R2=-85
LD R3,nBscore
AND R1,R1,0 ;R1清零,计数
AND R5,R5,0 ;R5清零存A人数
AND R6,R6,0 ;B人数
LD R7,RES ;R7存放成绩降序结果首地址
;
; 获得的A人数
;
CountA LDR R4,R7,0
ADD R4,R4,R2 ;R4=score-85
BRn CountB ;如果score<85,开始计数B
ADD R5,R5,1 ;人数增加
ADD R7,R7,1 ;移向下一分数
ADD R1,R1,1 ;计数加1
ADD R0,R1,-4 ;R0=计数-4
BRn CountA ;计数小于4,还在前25%继续判断A人数
;
; 获得B的人数
;
CountB LDR R4,R7,0
ADD R4,R4,R3 ;R4=score-75
BRn STORE ;如果score<75,跳出B计数,进行保存
ADD R6,R6,1 ;人数增加
ADD R7,R7,1 ;移向下一分数
ADD R1,R1,1 ;计数加1
ADD R0,R1,-8 ;R0=计数-8
BRn CountB ;计数小于8,还在前50%继续判断B人数
;
; 将A B人数保存
;
STORE STI R5,Anum
STI R6,Bnum
HALT ;程序运行结束
;
SCORE .FILL x3200 ;成绩存放起始地址
RES .FILL x4000 ;成绩降序结果存放起始地址
Anum .FILL x4100 ;存放A地址
Bnum .FILL x4101
nAscore .FILL -85 ;A分数相反数
nBscore .FILL -75
StuNUM .FILL 16 ;学生人数
ONE .FILL 1 ;1
;
.END ;代码结束
结论或体会
在本次实验中,我首次尝试了在LC3利用汇编代码实现一个小程序,熟悉了了相关语法和良好的代码分割。认识到了适用标号的诸多好处,如利用LD直接加载数据常量,将地址偏移的计算交给机器负责从而增加代码的可读性;同时也熟悉了关于标号的各种操作。通过规定文件起始位置(.ORIG)实现多文件连接的可能。
另外我熟悉了利用汇编代码编写循环和分支结构的过程,第一次尝试用汇编代码实现冒泡排序。尝试了将一个实际问题通过问题分析,找到相应的算法实现流程及数据结构,进而通过逐步编写调试完成对问题的解决。
在本次实验中我也纠正了一些自己的模糊认知。比如标号地址是一个常量,不能做指针移动。其他数据标号也同样是常量,需要将其赋值给寄存器才能进行变量操作。另外lc3仅有8个寄存器。需要合理循环利用寄存器。