实验内容
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/6fc701a395c344f698eb9c6309e91913.png)
实验数据
4000 ;数据在内存地址4000处开始
004A
0055
003C
003D
0049
0054
0064
0026
0042
0035
004C
0052
0048
005F
004A
0050
实验代码
.ORIG x3000
; 初始化寄存器
AND R0, R0, #0
AND R1, R1, #0
AND R2, R2, #0
AND R3, R3, #0
AND R4, R4, #0
AND R5, R5, #0
AND R6, R6, #0
AND R7, R7, #0
; 复制成绩数据到 x5000
LD R1, SOURCE_ADDR ; 成绩源地址 x4000
LD R2, DEST_ADDR ; 目标地址 x5000
LD R3, NUM_16 ; 成绩数量
COPY_LOOP
LDR R4, R1, #0 ; 从 R1 处加载数据到 R4
STR R4, R2, #0 ; 存储 R4 到 R2 处
ADD R1, R1, #1 ; 增加 R1 地址
ADD R2, R2, #1 ; 增加 R2 地址
ADD R3, R3, #-1 ; 减少计数器 R3
BRp COPY_LOOP ; 如果 R3 > 0,继续循环
; 冒泡排序成绩
LD R1, NUM_16 ; 外层循环计数器
SORT_OUTER_LOOP
ADD R1, R1, #-1 ; 外循环计数器-1
BRz CALC_GRADES ; 如果 R1==0,结束外循环
; 内层循环
LD R2, DEST_ADDR
ADD R3, R1, #0 ; 内层循环计数器初始化
SORT_INNER_LOOP
ADD R4, R2, #1 ; R4 设置为下一个地址
LDR R5, R2, #0 ; 从 R2 处加载当前成绩到 R5
LDR R6, R4, #0 ; 从 R4 处加载下一个成绩到 R6
; 如果当前成绩大于下一个成绩,交换它们
NOT R7, R5
ADD R7, R7, R6
BRzp NOSWAP ; 如果 R5 <= R6,不交换
STR R6, R2, #0 ; 否则,交换 R5 和 R6
STR R5, R4, #0
NOSWAP
ADD R2, R2, #1 ; 增加内循环地址 R2
ADD R3, R3, #-1 ; 内循环计数器-1
BRp SORT_INNER_LOOP ; 内层循环未结束
BRnzp SORT_OUTER_LOOP ; 外层循环继续
; 计算成绩等级
CALC_GRADES
LD R0, DEST_END_ADDR ; 将 R0 设为排序后的最后一个数据地址 (x500F)
AND R4, R4, #0 ; 清零 A 等级计数器
AND R5, R5, #0 ; 清零 B 等级计数器
AND R6, R6, #0 ; 清零学生计数器
AND R7, R7, #0
LD R1, NUM_16 ; 总成绩数量 (16)
GRADE_LOOP
LDR R2, R0, #0 ; 从 R0 处加载当前成绩到 R2
ADD R0, R0, #-1 ; R0 地址减少 (倒序遍历)
ADD R6, R6, #1 ; 学生计数器增加
; 判断是否在前 25% 且 >= 85
LD R3, A_THRESH
NOT R3, R3
ADD R3, R3, #1 ;
ADD R3, R3, R2 ; 判断 R2 - A_THRESH (即 R2 是否 >= 85)
BRn CHECK_B ; 如果成绩 < 85 跳到 CHECK_B
ADD R7, R6, #-5 ; 比较计数器值,如果值 <= 4 即前25%学生
BRp CHECK_B ; 如果计数器值大于4,则跳到 CHECK_B
; 成绩在前 25% 且 >= 85
ADD R4, R4, #1 ; A 等级计数加 1
BRnzp GRADE_NEXT ; 跳到下一个成绩
CHECK_B
; 判断是否在前 50% 且 >= 75
LD R3, B_THRESH
NOT R3, R3
ADD R3, R3, #1 ;
ADD R3, R3, R2 ; 判断 R2 - B_THRESH (即 R2 是否 >= 75)
BRn GRADE_NEXT ; 如果成绩 < 75 跳到 GRADE_NEXT
ADD R7, R6, #-9 ; 比较计数器值,如果值 <= 8 即前50%学生
BRp GRADE_NEXT ; 如果计数器值大于8,则跳到 GRADE_NEXT
; 成绩在前 50% 且 >= 75
ADD R5, R5, #1 ; B 等级计数加 1
GRADE_NEXT
ADD R1, R1, #-1 ; 总学生成绩计数减 1
BRp GRADE_LOOP ; 若还有成绩,继续遍历
AND R6, R6, #0
AND R7, R7, #0
LD R6, A_COUNT
LD R7, B_COUNT
STR R4, R6, #0 ; 将 A 等级数量存储在 x5100
STR R5, R7, #0 ; 将 B 等级数量存储在 x5101
HALT ; 停止程序
; 数据段
SOURCE_ADDR .FILL x4000 ; 成绩源地址
DEST_ADDR .FILL x5000 ; 排序后来地址
A_COUNT .FILL x5100 ; A 等级储存地址
B_COUNT .FILL x5101 ; B 等级储存地址
NUM_15 .FILL #15 ; 共 15 次排序内循环
NUM_16 .FILL #16 ; 总成绩数量
NUM_4 .FILL #4 ; 前25% 数量
NUM_8 .FILL #8 ; 前50% 数量
A_THRESH .FILL #85 ; A 等级阈值
B_THRESH .FILL #75 ; B 等级阈值
DEST_END_ADDR .FILL x500F
.END
实验步骤与过程
- 准备好数据文件,每次只需加载到Simulator即可,无需手动设置
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/d1974fb3c0f14c2098b843954e61a4e4.png)
成绩分别为74,85,60,61,73,84,100,38,66,53,76,82,72,95,74,80 - 先把位于从x4000开始的数据,迁移至x5000位置
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/c77aa8e1276d4c569a648b2506671d66.png)
- 之后对成绩进行排序,这里采用的是冒泡排序
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/7c1df9cf41974d7c98a5c339a9a12b89.png)
- 统计各等级人数,C级无需统计,只需统计A和B等级的学生个数,那么如何统计呢,由于已经把成绩升序排好了,那么只需要倒着遍历即可,从最高的成绩开始,然后维护一个计数器,判断当前成绩是否大于等于85,且计数器的值是否小于等于4(前25%),若这两个条件都符合,就是等级A,等级A数量加一,否则按照类似的方式判断是否是B等级,若是B等级,等级B数量加一。最后将等级A数量存放在x5100,等级B数量存放在x5100处。
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/53dc24e0f82b416e9c411235b87491d7.png)
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/b0d88323f014494889661b79ba642f71.png)
- 实验结果
(1)加载数据和程序:
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/0a251d5cf9174619b2001e8f886c242e.png)
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/bffe668683f04161b5c0ce2e90f37680.png)
(2)运行前:
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/21fb179ed0dd4a94b1be2d934fb1852f.png)
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/34e60bad0b124260b45aea3615fd4eda.png)
(3)运行后:
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/8f7ee80d19da47c2a85b047a82dbd90a.png)
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/4865fbaee2634589a5abceff03b51196.png)
(4)验证程序正确性:
可以看到从x5100开始,成绩从低到高,符合要求:
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/d50c1b855fcb40b8bf019fc52df04a1c.png)
对成绩降序排序,查看A等级人数和B等级人数:
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/0e4e02f3799843d7b2402f2921e561fa.png)
可以看到有3人获得A,4人获得B,观察向x5100和x5101处的值,正确:
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/4f4d450af1e14d56979b89830924fb1f.png)
实验结论或体会
- 在本次实验中,我首次尝试了在LC3利用汇编代码实现一个小程序,熟悉了相关语法和良好的代码分割。认识到了适用标号的诸多好处,如利用LD直接加载数据常量,将地址偏移的计算交给机器负责从而增加代码的可读性;同时也熟悉了关于标号的各种操作。
- 另外我熟悉了利用汇编代码编写循环和分支结构的过程,第一次尝试用汇编代码实现冒泡排序。尝试了将一个实际问题通过问题分析,找到相应的算法实现流程及数据结构。
- 在本次实验中我也纠正了一些自己的模糊认知。比如标号地址是一个常量,不能做指针移动。其他数据标号也同样是常量,需要将其赋值给寄存器才能进行变量操作。另外lc3仅有8个寄存器,需要合理循环利用寄存器。
- 此次实验在找bug上我也花了大量时间,这也提升了我断点调试代码的能力。