计算机系统 实验1
实验目的:
1. 掌握处理仿真工具LC-3软件的安装和使用方法。
2. 学会在LC-3仿真环境下编辑程序和转换为可执行目标程序的方法。
3. 学会在LC-3仿真环境下运行和调试程序的方法。
实验内容与实验要求:
1. 安装LC-3仿真器
2. 利用LC3EDIT输入机器代码程序(0/1模式)并创建可执行目标程序。
3. 利用LC3EDIT输入机器代码程序(hex模式)并创建可执行目标程序。
4. 利用LC3EDIT输入汇编代码程序并创建可执行目标程序。
5. 利用LC-3 Simulator仿真器运用对应目标程序。
6. 学习和掌握断点,单步执行等调试方法和手段。
实验步骤
- 安装LC-3仿真器
运行”仿真器” 目录下的LC301.exe文件,其实质是个winzip压缩包,选择目录,点击“Unzip”即可。
运行安装目录下的LC3edit.exe文件。
2.用二进制机器码的输入和编译,并创建可执行目标程序
在代码输入区,输入代码。
选择File->Save,命名EX1.bin文件。(二进制机器代码程序的后缀必需为.bin)编译,选择Translate->Convert Base
信息区域提示Convert Complete-0 error(s).的成功信息在EX1.bin对应的文件夹中会产生EX1.obj文件,可在LC-3 Simulator 中执行。
3.用16进制机器码的输入和编译,并创建可执行目标程序
新建文件,File->new在代码输入区,输入代码。
选择File->Save,命名EX2.hex文件。(二进制机器代码程序的后缀必需为.hex)编译,选择Translate->Convert Base 16。
信息区域提示Convert Complete-0 error(s).的成功信息在EX2.hex对应的文件夹中会产生EX2.obj文件,可在LC-3 Simulator 中执行。
4.汇编语言程序的输入和编译,并创建可执行目标程序
新建文件,File->new在代码输入区,输入右侧代码。
选择File->Save,命名EX3.ASM文件。(二进制机器代码程序的后缀必需为.asm)编译,选择Translate->Convert assemble。
观察信息区域提示的成功信息。如果出错,请检查代码在EX3.asm对应的文件夹中会产生EX3.obj文件,可在LC-3 Simulator 中执行。
但是编译后,获得的不只是一个,但少量的文件:
EX3.obj,目标文件
EX3.bin,ASCII码0和1编写的程序
EX3.hex, ASCII码十六进制格式
EX3.sym,在汇编程序第一次通过的时候创建的符号表格
EX3.lst,程序的列表文件
5. LC-3 Simulator仿真器运用对应目标程序
打开模拟器,然后点击打开程序按钮。浏览且选择addnums.obj文件。注意到在模拟器中,你只能选择打开.obj这样的文件类型。
加载数据(十个数字)到内存的方法
有很多方法可以把你准备的数据加到LC-3仿真器的内存中。你想把他们放在x3100开始的位置。
第一个方法:点击工具条上“Jump to”框右边的输入框,输入十六进制数字x3100,当你按下回车后,在内存信息显示出来前,你会跳越x100个内存位置。所以x3100这个内存单元位置会第一个显示。在Value选项框中,填入16进制数X3107,然后选择OK。
你可以双击每一行并输入数据,如果你只想打开弹出窗口一次,即Location区域的值自动变化,在value 区域输入下一个值,然后单击apply按钮,做完单击操作后,单击OK。
第二种方式: 返回到LC3Edit.程序,输入下面16进制代码:
3100 ;数据在内存地址X3100处开始
3107 ;从此处开始,添加的10个数字
2819
0110
0310
0110
1110
11B1
0019
0007
0004
单击,将代码保存为 data.hex
通常第一行是我们想要添加数据的起始地址。后面若干行是我们想要导入内存的实际数据。
因为我们使用16进制编程,因此单击,此时,在你保存 “.hex”的位置将会产生一个名为data.obj的文件
现在返回模拟器,单击导入项目,选择 data.obj。注意,你可以导入多个.obj文件,他们可以同时存在于LC-3 simulator 内存中。
6.设置断点,运行程序
单步执行调试方法和手段
首先,你需要重将程序计数器重置为你的程序的第一个位置。即设置PC 为X3000.可以双击它,然后输入新的值。当然,你也可以使用快速方法,单击x3000哪一行,然后单击,这样就将PC 指向了这个位置,现在你就可以单步执行程序了
单击一步,第一次。,一些有趣的事情将会发生:
- R1 被清0,
- 2,蓝色箭头,以及PC的值 都指向了x3001的位置,这也是下一个将运行的指令
- IR的值设置为了x5260,看看x3000处16进制的值,这里也是x5260. IR 中存储了当前运行的指令。因为我们已经结束了第一个指令,并且还没有运行第二个指令,所以第一个指令依然是当前指令
单击一步,第二次。观察 PC 和 IR 中的新的值,第二次指令 将R4清零
单击一步,第三次。PC和IR的值再一次更新,现在R4拥有了值X0A,即10进制数10.即我们需要重复循环10次,这个指令仅仅执行添加x000A到x0000, 并且将结果放置在R4中
继续单步执行,观察每一个指令执行后的结果,确保结果是期望看到的
如果你想结束单步,直接运行。你可以单击按钮,这将直接执行程序到断点处
现在你知道一次就写出一个完美的程序,并成功运行是多么的美妙。但是,通常那是难以实现的。
Example1调试这个不适用乘法指令的乘法程序
编写乘法代码,命名为Example1.bin,用二进制编码编译,打开Lc3 Simulator,打开生成的Example1.obj文件, 在行x3204处设置断点(双击改行最前面的灰色方框), 点击,弹出Set Value 窗口,在Location字段中选择R4,在Value处输入“x5”, 点击Apply,然后选择R5,输入x3,点击OK,接下来运行程序。
点击,运行程序,稍后,会弹出如下窗口:
该窗口会弹出是因为在halt行处设置的断点,点击OK关闭窗口,查看R2,应该包含最后的结果,十进制3*5=15,但是R2中包含十进制20(十六进制x14),程序存在问题,下面寻找问题,调试乘法程序。
因为程序存在循环,所以利用断点调试循环,但是为确保每条指令正确执行,先逐步调试乘法程序,让程序循环执行一次。
在分支指令处设置断点来发现一个循环是否被过多执行,这样在每次循环迭代的结尾处都会暂停,此时有利于查看寄存器的状态,点击,尝试另一种设置断点的方法。
设置PC为x3203,然后点击Add、设置PC为x3200,R5为x3,然后点击,运行程序
点击OK,注意观察寄存器的值,蓝色箭头和PC均指向x3203,R4未变,R5则变为x2,R2变为x5,。状态码p为1,意味着继续执行程序时,分支会跳转。
点击,关闭弹出的窗口,如上次一样,观察寄存器,尤其是R2和R5,目前已经循环两次,R2内容为x1,R2为十进制10,状态码P=1,因此循环将继续执行一次。
点击,然后点击OK,此时R5为0,R2为十进制15,因为3*5=15,此时应该停止,但是状态码Z=1,分支指令将继续执行,多做一次,这里出现了问题。
通过修改分支指令使只有当P=1时,循环就会执行正确的次数,为验证其正确性,用LC3Edit修改分支指令如下:
0000 001 111111101 ;跳转到 location x3201 如果结果为正值
保存并转成.obj格式,装载程序到模拟器,如果不想修改源代码,可以在模拟器中直接修改,双击行x3203,在Set Value窗口中将其值从x0601改为x0201(此种方法仅对此次装载有效,下次装载时,该bug仍然存在,因此还要修改源代码)。
最后,重设PC为x3200,R5为x3,R4为x5,取消断点,点击,关闭断点弹窗后,可以看到十进制15出现在R2中,程序调试成功。
Example 2:调试程序使其输出输入并求和
在LC3Edit中输入“让用户输入两个数(0到9),然后求和,然后打印(同样介于0和9)在Console窗口中”的程序,并通过点击来编译这个程序
打开simulator,载入程序。然后双击x3008行前的小灰色方块来设置断点,点击运行你的程序,提示在console窗口输入字符:
输入4,然后再输入3,程序给了错误的结果。
调试程序,当在console窗口输入“4”时,R0中给出的值是x34.当输入的是“3”时,显示的是x33。我们把这些值相加,结果是x67。查看ASCII表,x67代表的是“g”。
所以需要添加5个指令:两个是载入两个mask,一个是将-x30加到第一个数中,一个是对另一个数做同样的操作,最后一个是在输出前将结果加上x30。
然后重复上述操作后,便可得出正确结果。
实验结论:
通过本次实验,我掌握了LC-3Edit和simulate的使用方法,对仿真环境的操作有了最基本的认识;学会了在LC-3Edit仿真环境下如果编写自己想要的程序,并实现程序运行的方法;学会了在LC-simulate对相应的机器代码进行调试调试的方法,并得到正确的结果。
在实验中虽然也遇到了一些困难,但是经过研讨、对程序的调试、对代码进行修改后,成功解决这些问题,最终程序得以顺利实现。