实验目的
熟悉和理解LC-3的汇编指令格式。
进一步掌握在LC-3仿真平台下汇编指令的设计输入和调试过程。
掌握利用汇编指令解决问题的思路,加深对汇编指令的理解。
实验内容
分析和理解试验指定的需解决问题。
利用LC-3的汇编语言代码设计实现相关程序。
通过LC-3仿真器调试和运行相关程序并得到正确的结果
实验要求
熟悉和理解LC-3的汇编语言指令格式。
掌握在LC-3仿真平台下汇编语言代码的设计输入和调试过程。
掌握利用汇编语言解决问题的思路,加深对底层硬件的理解。
实验问题
程序起始地址x3000
在x3200处开始存放16个学生成绩,成绩为0-100的正整数
编写程序对16个学生的成绩进行排序,从高至低存放在起始地址x4000处。
计算学生获得成绩等级为A的数量存放在x4100,获得B等级的数量存放在x4101处。(成绩等级计算方法:如果一个学生的成绩在85分以上同时排名前25%则获得A,如果一个学生不能获得A,他的成绩在75分以上同时排名前50%,则可获得B。其它成绩则获得C)
实验报告要写清楚排序算法的实现过程以及等级的计算方法
实验步骤
题目分析
本题中主要需要实现转移数据位置、并统计在给定分数区间和给定分数名次以内的学生个数这三个功能,下面逐一进行分析:
①转移数据位置:
可以通过类似于C++语言中指针的方式,分别将R1和R2(此处仅作为说明用,并不是真正意义上的R1和R2,实际操作可以换成如R3、R5或R7等其他寄存器)指向数据源单元首地址(x3200)和目标存储单元首地址(x4000),每次复制一个学生的成绩数据,每次复制完成后,将R1和R2所指地址加一(指针加一)使其指向下一个单元并用另一寄存器进行计数,待计数器数满十六次后,数据转移功能完成,并进入下一功能的代码块中。
②对数据进行降序排列:
常用排序方法有冒泡法选择法等,本实验中选择了选择排序法对学生成绩进行排序,此处需要注意的是因为汇编语言中没有比较数值大小的指令,因此在进行大小比较时,应比较两数做差之后的值是否大于一,需要将一个数值转换为对应的负值(取反加一),而在进行判断之后不能忘记将对应的负值转换为相应的原数值(非负数),否则会造成出现错误的数据。
排序过程中有两层循环,大循环(外层循环)用于遍历所有的学生成绩数据,小循环(内层循环)用于找到单次循环的最大值,并进行位置的调换。直至大循环循环完毕,所有排序操作结束,并进入下一功能的代码块中。
③统计学生个数:
依照本题的要求需要统计A、B两个等级的学生,由于对各个等级的学生要求存在对排名的要求故从头部往后逐一遍历,遇到符合要求的成绩相应的计数器就加一,等遍历到中间位置(50%)就可结束,并将计数器的个数存在相应的内存中。
代码实现
设置程序起始位置:
初始化寄存器
进行数据复制
将成绩进行排序
统计A、B等级学生人数:
前面已经介绍,需要分两步进行统计:
①统计获得A和前25%中获得B的学生人数:
②统计25%-50%中B的学生人数:
符号表
进行测试
测试数据为:97,83,72,69,50,93,80,71,68,51,87,74,70,67,62,86
预期排序结果为:97,93,86,87,83,80,74,72,71,70,69,68,67,62,51,50共有4个A等级成绩,2个B等级成绩。
在simulator中运行并设置测试数据如下:
排序结果如下图
对A、B等级学生的成绩计数结果如下:
可以看到A等级学生有4人,B等级学生有2人。
完美符合预期,故实验编程正确。
实验结论
通过这次的实验,我对汇编语言有了更深的认识。在实验过程中遇到不少困难,最终都成功解决。如判断时条件错误,忘记将因用于比较而变成负数的值转回原值等。最后在一次次debug和测试中都得到解决。在对汇编语言进行编程时,如果代码较长,理解起各个指令的含义变得困难,此时就需要借助注释来进行提示,注释的作用在本实验中得到了很大体现。
此外,我也学会了将高级语言中排序算法应用到汇编语言的能力,这大大降低了在汇编语言中实现相应操作的难度。
完整源码(仅供参考)
.ORIG x3000 ;程序起始位于x3000 ;初始化寄存器 LD R0,SCORE ;将R0初始化为x3200,使R0指向第一个成绩 AND R1,R1,#0 ;R1清零 ADD R1,R1,#15 ; ADD R1,R1,#1 ;通过两次赋值将R1初始化为16 LD R3,AStart ;将R3初始化为x4000指向目标地址 AND R5,R5,#0 ;R5清零 ADD R5,R5,#15 ; ADD R5,R5,#1 ;通过两次赋值将R5初始化为16 ;将输入到以x3200起始的成绩复制到x4000起始的内存单元 copy BRz sort ;当计数器为0的时候就进行排序 LDR R4,R0,#0 ;将x3200存储的数据复制给R4 STR R4,R3,#0 ;将R4存储在x4000中 ADD R0,R0,#1 ;数据源指针地址加1 ADD R3,R3,#1 ;目标指针地址加1 ADD R5,R5,#-1 ;计数器减1 BRnzp copy ;跳转到copy,继续复制数据 ;成绩排序 sort LD R3,AStart ;初始化R3指针为x4000 ADD R1,R1,#0 ;设条件码 F BRz C ;外层循环计数器跳转指令 ADD R2,R1,#-1 ;R2为内层循环的计数器,R1为外层循环的计数器 LDR R4,R3,#0 ;用R4来存储最大的数 ADD R6,R3,#0 ;对最大数的地址进行修改 ADD R7,R3,#0 ;存储最大的数的地址 NOT R4,R4 ; ADD R4,R4,#1 ;准备比较大小 E ADD R6,R6,#1 ;R6是内层循环的指针 LDR R5,R6,#0 ; ADD R5,R4,R5 ; BRnz D ;若R5>R4,那么交换最大的与被比较的位置 LDR R4,R6,#0 ;若R5<R4,把R6所存的地址的内容给R4 NOT R4,R4 ; ADD R4,R4,#1 ;将R4变回原数据 ADD R7,R6,#0 ;将当前所存最大数的地址给R7 D ADD R2,R2,#-1 ;内层循环计数器的值减1 BRp E ;跳回选择排序的小循环,继续进行排序 LDR R0,R3,#0 ;把R3所存地址(x4000)的数据赋给R0 STR R0,R7,#0 ;把R0数据赋给R7所存的地址的内存单元 NOT R4,R4 ; ADD R4,R4,#1 ;把R4原数据 STR R4,R3,#0 ;将最大的数存储到被比较的数所在的地址 ADD R3,R3,#1 ;外层循环指针加1 ADD R1,R1,#-1 ;外层循环计数器减1 BRnzp F ;跳回到外循环,继续进行排序 ;统计获得A和前25%中获得B的学生人数 C LD R0,AStart ;将R0指向AStart的x4000 AND R1,R1,#0 ;R1作为计数器 AND R2,R2,#0 ; AND R3,R3,#0 ; AND R4,R4,#0 ; AND R5,R5,#0 ; AND R6,R6,#0 ;寄存器R1到R6清零 ADD R1,R1,#4 ;将4赋给R1即排名前4(25%) G BRz StoreA ; ADD R1,R1,#-1 ;计数器R1减1 LDR R2,R0,#0 ;将成绩传给R2 LD R7,Ne85 ;将-85赋给R7 ADD R3,R2,R7 ;比较R2与85 BRn G1 ;R2<85,跳过R4的计数到G1 ADD R4,R4,#1 ;R4存A的人数 BRnzp Dyh ; G1 ADD R7,R7,#10 ;将-75赋给R7 ADD R5,R2,R7 ;比较R2与75 ADD R5,R5,#0 ;设置条件码 BRn Dyh ;R2<75,跳过R6的计数到Dyh ADD R6,R6,#1 ;R6存B的人数 Dyh ADD R0,R0,#1 ;指针加1 ADD R1,R1,#0 ;设置条件码 BRp G ;跳回判断G StoreA STI R4,SaveA ;将R4中的内容(等级为A的学生人数)存储在地址x4100中 ;统计25%-50%中B的学生人数 LD R0,BStart ;将R0x4004 AND R1,R1,#0 ;R1作为计数器 AND R2,R2,#0 ; AND R3,R3,#0 ;寄存器R1到R3清零 ADD R1,R1,#4 ;将4赋给R1即4到8(25%到50%) I ADD R1,R1,#0 ;设置条件码 BRz StoreB ; ADD R1,R1,#-1 ;计数器减1 LDR R2,R0,#0 ;通过循环,将排名为5到8名的学生成绩赋给R2 LD R5,Ne75 ;将-75赋给R5 ADD R3,R2,R5 ;将成绩R2与75进行比较 ADD R3,R3,#0 ;设置条件码 BRn H ;n表示R2不足75,跳过R6的计数到H ADD R6,R6,#1 ;R6存B的人数 H ADD R0,R0,#1 ;指针加1 BRnzp I ;跳回判断I StoreB STI R6,SaveB ;将R6存在地址x4101 ;程序结束 HALT ; Ne85 .FILL #-85 Ne75 .FILL #-75 SCORE .FILL x3200 AStart .FILL x4000 BStart .FILL x4004 SaveA .FILL x4100 SaveB .FILL x4101 .END