【计算机系统1】3 LC-3汇编语言求成绩等级

目录

目的与要求

内容与方法

步骤与过程

程序总体设计

核心数据结构——冒泡排序

调试过程

成绩数据文件data编写和程序数据初始

成绩复制

冒泡排序

A B计数保存

核心代码

结论或体会


目的与要求

分析和理解实验指定的问题

利用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 成绩复制代码编译运行

  • 结果正确,x3200x4000存放的数据一样(图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个寄存器。需要合理循环利用寄存器。

猜你喜欢

转载自blog.csdn.net/weixin_51695846/article/details/125357151