实验报告 |
实验名称: | CPU 与简单模型机实验 | 日期: | ----.--.-- |
班级: | ----------- | 学号: | ------------ | 姓名: | ---------- |
一、实验目的: | |
1、 | 掌握一个简单CPU 的组成原理; |
2、 | 在掌握部件单元电路的基础上,进一步将其构造一台基本模型计算机; |
3、 | 为其定义五条机器指令,编写相应的微程序,并上机调试建立和掌握整机概念。 |
二、实验内容: | |
1、 | 在SRAM中构建一段机器程序代码来实现简单应用功能,利用原有的微程序序列,执行该段机器程序代码,将结果显示在输出设备上。 |
三、项目要求及分析: |
1)利用原有的微指令以及机器代码实现简单应用
在实验指导书中所给出了IN(输入)、ADD(二进制加法)、OUT(输出)、JMP(无条件转移),HLT(停机)共五条微指令,微指令存储在控制存储器中,每一个指令经过译码之后就会产生相应的控制信号,控制计算机系统进行工作。
存储程序思想是把程序以及数据一起存入内存,只需要启动程序,程序就可以自动执行,而不需要人工干预。在这一个任务中,把机器指令按照顺序存入存储器,然后让CPU自动取指并执行。
要实现这一功能,需要把指导书提供的微程序和机器指令分别存放在控制存储器和存储器中,然后程序即可执行。
2)思考题:试修改现有的指令系统中的加法指令,并增加存数,取数,减法操作。
对于原来的加法微指令,是把R0寄存器中的值送入ALU_A和ALU_B,然后执行加法操作,结果写回R0。修改之后的指令是针对R0以及内存中的值进行相加,所以需要更改控制存储器中地址为30的[R0->A]指令,更改其操作内容,并修改next字段,完成对加法逻辑的修改。
由于需要新增三条指令,首先对机器码(60、70、80),通过图1,得到经过P<1>测试之后会跳转的位置,即某一条机器指令对应微指令的起始地址,然后在控制存储器中选择还没有使用的存储单元,作为存储微指令的地址,并通过next域把微指令连接,构成微程序。
图1
对于减法指令(SUB),规定其为双字节指令,第一个字节为操作码,第二个字节为内存地址ADDR,指令功能为使用R0的值减去内存中地址为ADDR的数字的值,结果写回R0中。
对于存数指令(STA),规定其为双字节指令,第一个字节为操作码,第二个字节为内存地址ADDR,指令功能为把R0的值存入内存中地址为ADDR的位置。
对于取数指令(LAD),规定其为双字节指令,第一个字节为操作码,第二个字节为内存地址ADDR,指令功能为把内存地址为ADDR的值存入R0。
然后可以根据我所明确的指令的格式,设计流程图,并确定控制信号,把其转化为二进制代码表,然后得出对应的微程序,通过计算机写入到实验箱中的控制存储器中。
之后,可以按照定义的机器指令格式,编写机器指令程序,使用计算机写入到实验箱的存储器中,然后按下复位键,不断给出时钟脉冲,程序就可以执行。
四、具体实现: |
应包含以下内容:画出增加机器指令的微程序流程图、编制二进制代码表、编写微程序、编写机器指令验证程序。
1)利用原有的微指令以及机器代码实现简单应用
实验指导书中已经给出。
2)思考题:试修改现有的指令系统中的加法指令,并增加存数,取数,减法操作。
微程序流程图:(图2)
图2
编制二进制代码表:
机器指令 | 说明 | 地址 | 23-22 | 21(WR) | RD(20) | 19(IOM) | S3-S0 | A | B | C | MA5-MA0 | 二进制编码 |
ADD | PC->AR,PC++ | 30 | 00 | 0 | 0 | 0 | 0000 | 110 | 110 | 101 | 0E | 006D4E |
MEM->AR | 0E | 00 | 0 | 1 | 0 | 0000 | 110 | 000 | 000 | 0F | 10600F | |
MEM->B | 0F | 00 | 0 | 1 | 0 | 0000 | 010 | 000 | 000 | 10 | 102010 | |
R0->A | 10 | 00 | 0 | 0 | 0 | 0000 | 001 | 010 | 000 | 05 | 001405 | |
A+B->R0 | 05 | 00 | 0 | 0 | 0 | 1001 | 011 | 001 | 000 | 01 | 04B201 | |
SUB | PC->AR,PC++ | 38 | 00 | 0 | 0 | 0 | 0000 | 110 | 110 | 101 | 08 | 006D48 |
MEM->AR | 08 | 00 | 0 | 1 | 0 | 0000 | 110 | 000 | 000 | 09 | 106009 | |
MEM->B | 09 | 00 | 0 | 1 | 0 | 0000 | 010 | 000 | 000 | 0A | 10200A | |
R0->A | 0A | 00 | 0 | 0 | 0 | 0000 | 001 | 010 | 000 | 0B | 00140B | |
A-B->R0 | 0B | 00 | 0 | 0 | 0 | 1011 | 011 | 001 | 000 | 01 | 05B201 | |
STA | PC->AR,PC++ | 36 | 00 | 0 | 0 | 0 | 0000 | 110 | 110 | 101 | 06 | 006D46 |
MEM->AR | 06 | 00 | 0 | 1 | 0 | 0000 | 110 | 000 | 000 | 07 | 106007 | |
R0->MEM | 07 | 00 | 1 | 0 | 0 | 0000 | 000 | 010 | 000 | 01 | 200401 | |
LAD | PC->AR,PC++ | 37 | 00 | 0 | 0 | 0 | 0000 | 110 | 110 | 101 | 0C | 006D4C |
MEM->AR | 0C | 00 | 0 | 1 | 0 | 0000 | 110 | 000 | 000 | 0D | 10600D | |
MEM->R0 | 0D | 00 | 0 | 1 | 0 | 0000 | 011 | 000 | 000 | 01 | 103001 |
编写微程序:
; //** Start Of MicroController Data **// $M 00 000001 ; NOP $M 01 006D43 ; PC->AR,PC加1 $M 03 107070 ; MEM->IR, P<1> $M 1D 105141 ; MEM->PC $M 32 183001 ; IN->R0 $M 33 280401 ; R0->OUT $M 35 000035 ; NOP $M 3C 006D5D ; PC->AR,PC加1 ;以上为原来的指令 $M 30 006D4E ; ADD指令 PC->AR,PC++ $M 0E 10600F ; MEM->AR $M 0F 102010 ; MEM->B $M 10 001405 ; R0->A $M 05 04B201 ; ADD指令结束 A+B->R0 $M 38 006D48 ; SUB指令 PC->AR,PC++ $M 08 106009 ; MEM->AR $M 09 10200A ; MEM->B $M 0A 00140B ; R0->A $M 0B 05B201 ; SUB指令结束 A-B->R0 $M 36 006D46 ; STA指令 PC->AR,PC++ $M 06 106007 ; MEM->AR $M 07 200401 ; STA指令结束 R0->MEM $M 37 006D4C ; LAD指令 PC->AR,PC++ $M 0C 10600D ; MEM->AR $M 0D 103001 ; LAD指令结束 MEM->R0 ; //** End Of MicroController Data **// |
编写机器指令验证:
(a)加法功能验证:
; //***** Start Of Main Memory Data *****// $P 00 20 ; IN 把in输入到R0 $P 01 60 ; STA 把R0存入MEM[51] $P 02 51 ; STA地址 $P 03 20 ; IN把in输入到R0 $P 04 00 ; ADD R0=R0+MEM[51]. $P 05 51 ; 加数在内存中的地址 $P 06 30 ; OUT 输出R0 $P 07 E0 ; JMP $P 08 00 ; 跳转到程序开始(方便重复实验) ; //***** End Of Main Memory Data *****// |
代码功能:先从in读入一个数字放到MEM[51],然后再读入一个数,放到R0,计算:R0=R0+MEM[51].
(b)减法功能验证:
; //***** Start Of Main Memory Data *****// $P 00 20 ; IN 把in输入到R0 $P 01 60 ; STA 把R0存入MEM[51] $P 02 51 ; STA地址 $P 03 20 ; IN 把in输入到R0 $P 04 80 ; SUB R0=R0-MEM[51]. $P 05 51 ; 减数在内存中的地址 $P 06 30 ; OUT输出R0 $P 07 E0 ; JMP $P 08 00 ; 跳转到程序开始(方便重复实验) ; //***** End Of Main Memory Data *****// |
代码功能:先从in读入一个数字放到MEM[51],然后再读入一个数,放到R0,计算:R0=R0-MEM[51].
(c)取数功能验证
; //***** Start Of Main Memory Data *****// $P 00 20 ; IN 把in输入到R0 $P 01 60 ; STA 把R0存入MEM[53] $P 02 53 ; STA地址 $P 03 70 ; LAD R0=MEM[53] $P 04 53 ; LAD地址 $P 05 30 ; OUT输出R0 $P 06 E0 ; JMP $P 07 00 ; 跳转到程序开始(方便重复实验) ; //***** End Of Main Memory Data *****// |
代码功能:把一个数字从in单元读入,然后存放在MEM[53]中,然后再取出该数字,然后输出。
五、调试运行结果: |
1)利用原有的微指令以及机器代码实现简单应用
图3 按照实验指导书连线
在这一次测试时,微程序以及机器指令均对应实验指导书上给定的内容。
预期效果:通过in单元向模型机输入一个数字,然后模型机把这一个数字作为加数和被加数相加,然后输出运算结果。
调用IN指令,存入数据
图4 从in单元向R0存入0x01
然后使用未修改的ADD指令,完成R0 = R0 + R0的运算。
图5 把R0的值放入A和B,然后执行ADD操作,把结果写回R0
执行OUT指令,显示R0的值。
图6 显示R0的值
观察实验箱,输出结果为0x02,是0x01 + 0x01的结果,该次实验结果正确。
图7 实验箱out单元
2)思考题:试修改现有的指令系统中的加法指令,并增加存数,取数,减法操作。
在这一个项目中,所使用的微指令见具体实现-编写微程序模块
(a)首先进行减法功能验证:
通过IN指令读入减数。
图8 把数字从0x08从in单元写入R0
通过STA指令存储R0中的数据到MEM[0x51].
图9 把R0存入内存地址为0x51的存储单元
通过IN指令读取被减数
图10 利用in单元把0x10读入到R0中
在SUB指令中,微程序加载MEM[0x51]的数据,存放在ALU_B中,充当减数。
图11 从地址为0x51的内存中取出之前存入的数字0x08
在SUB指令中,执行相减,并写回R0中。
图12 做减法运算
OUT指令,把R0的值发送给OUT单元
图13 把最终结果发送到OUT单元
图14 观察实验箱数据
(b)加法指令验证:
在STA指令执行前,已经执行了IN指令,并把in单元数据写到了R0中。
然后执行STA,把R0中的值写入到MEM[0x51]
图15 把R0中的值写入到地址为0x51的内存中
ADD指令中的加载存储器内数据的执行过程,把MEM[0x51]的值读入到ALU_B中,在这一次操作之后,再读取R0的值到ALU_A中。
图16 从内存中读出事先存好的01
ADD指令进行求和并写回R0中
图17 进行相加操作
在执行OUT操作之后,观察实验箱,发现输出结果确实为 0x04 = 0x03 + 0x01,这一次实验正确。
图18 观察out单元
(c)进行输入输出指令测试:
在该条指令之前,已经通过in指令在R0中写入了0x03
这时调用STA指令,给定内存地址0x53,存入数据
图19 把0x03写入到地址为0x53的内存中
调用LAD指令,给定内存地址0x53,读取数据
图20 在地址为0x53的内存处读出数据
在执行完OUT指令之后,观察实验箱。发现读取出来的数据就是存入的数据,本此实验成功。
图21 out单元
在上述调试中,先测试了实验指导书中给出的例子程序,并使用计算机软件对控制箱内部具体的实现流程进行了观察。
然后按照具体实现中的编程文件,通过PC机进行下载,并选用三个机器码片段进行测试。在下载完程序后,按下脉冲信号发生按钮,程序按照预期流程执行,并且正常输出结果。
六、所遇问题及解决方法: |
遇到的问题一:
按照我的理解输入二进制编码对应的16进制,执行后没有达到预料结果。
解决方法:
再一次检查自己的代码,没有找到问题。观察实验指导书中所给出的标准的微指令,按照我的理解把其转化为16进制,然后与计算机上提供的微指令进行对比,发现我在转化16进制的时候出现了问题,错误地把最后6位(MA5-MA0)当做了8位进行转化,导致进制转化错误。
重新转化,编程,得到了正确的结果。
遇到的问题二:
如果直接手动进行转化,耗时耗力,还容易出错。
解决方法:
Python程序中的数字可以使用_进行分隔,可视性强,并且可以进行进制转化。
编写如下的python代码。
a = 0b00_000_0000_110_110_101_001110 #a的值根据每一条微指令的控制信号进行更改 print(hex(a)) |
输出结果为
0x6d4e |
这样就可以正确的生成二进制对应的十六进制了。
遇到的问题三:我在最初设计指令的时候,未按照定义进行,而是把SUB的机器码为61,STA机器码为14,LAD机器码为72.
解决方法:
在这一章具有许多保留内容,在下一次实验中会使用这些保留内容(低字节另有用处),所以应该为后面的设计留下空间。
再针对要求的机器码重新进行译码,得到对应的微指令起始地址,然后改写微指令,即可修复。
反思:在设计中,要严格遵守规范,并且要提前做好规划。
七、实验总结: | |
1. | 在基本运算器实验中,我首次见到了计算机的模型机,通过连线与操作实验箱,我对其有了初步的了解。在这一次实验中,我通过把算术逻辑单元(ALU)与控制模块进行连接,通过开关控制数据通路的输入,控制通路的输入,并且把算术逻辑单元的输出通过数据总线上的指示灯以及发两个标志位对应的指示灯进行展示,对其结果进行观察。 在这一次实验中,我发现一旦改变ALU的输入,其很快就可以把值算出来,但是只有按下时钟脉冲之后,数值才会被传输处理。这使得我初次对数据通路以及控制通路有了了解。数据通路仅仅负责运算,由于各级门的延迟,导致运算并不是瞬间完成的,所以又需要控制器每隔固定的一段时间,向各个模块发送信息,并等计算完成之后,执行下一个操作。 我在这一次实验中通过拨动开关,对数据通路以及控制通路有了比较直观地理解,这一次实验激起了我的学习兴趣。 在静态随机存储器实验中,我首先拨动开关,在地址寄存器上写入要访问内存的地址,然后在数据总线上传输所需要的数据,控制存储器进行读写。 在这一次实验中,我首次在实验中体会到了总线的意义。总线把计算机中的相应部件连接成一个总体,在每一时刻,只能有一组数据在总线上传输。通过总线,可以轻易地把数据在CPU内部进行传送,避免了过于复杂的连线。 同时,我也了解了内存的读写方法。必须要事先在地址寄存器上规定需要访问的地址,然后才可以对内存进行访问。 通过第一节课的两次实验,我对于模型机的部件有了基本的了解,学会了在实验箱上进行连线,并掌握了通过开关控制各个模块的功能。 |
2. | 在微程序控制器实验中,通过实验指导书,我发现模型机上的控制存储器也可以像内存一样进行读写,这样就可以把实现得到的二进制微指令写入控制存储器中。当然,更改控制存储器的值还可以通过PC机与其相连进行。 在这一次实验中,我了解到,机器指令在CPU内部并不是直接执行的,而是要把机器指令翻译为微指令,然后对每一条微指令进行译码,产生控制信号,作用于各个模块进行控制,最终完成所需要的功能。 我发现微程序是通过类似于链表的结构进行连接,当执行某一条微指令的时候,可以通过在本条微指令中的next域获取下一条微指令的地址,在对应的微程序执行完成之后,又会跳到指令译码状态,继续执行。 对于机器指令,在P<1>测试环节对其进行译码,改变微地址寄存器的地址,从而实现分支功能。 在这一次的实验中,打破了我固有的想法,机器指令之下还有抽象层次,通过微指令的运作,机器指令才可以被翻译成控制信号,进行一步步操作。 |
3. | 在这一次实验中,摒弃了之前几次实验中的开关,完全采用存储程序的思想,事先把程序以及数据存放在内存中,只需要给定初始的PC值,然后启动计算机,就可以自动执行,完成所需要的任务。 我首先把例子程序下载到实验箱中进行测试,初步了解了存储程序的执行过程,然后按照所给定的要求,修改原有的ADD指令,并增加STA,LAD,SUB指令。 在设计过程中,我了解了设计微指令的一般步骤。 首先按照要求,画出微程序的流程图,确定给定机器指令通过P<1>测试之后所跳转的地址,并给每一个微指令分配在控制存储器中的地址,明确每一条微指令的下一条微指令以及含义。 然后根据微指令的功能,选择控制信号,使数据的值从一个地方传送到另一个地方,然后写出微指令的16进制代码。 然后使用语言描述所涉及的微指令地址以及内容。 最后设计相应的机器码,对微指令的功能进行测试。 在本次测试中,我通过动手操作,完成了一个存储程序计算机模型的设计,然后对其进行了测试。 同时,我也在与之前手动拨动开关对计算机控制进行了对比。如果是手动拨动开关,那么计算机的执行速度就会受限于人的操作速度,相反,如果把指令事先存入内存,那么对于一些循环的部分,计算机就可以自己取指,执行,而不需要人去干预,这极大地提升了计算机的运行速度,同时也使得计算机可以更加通用。 |