计算机原理
课程设计
课程名称:
计算机原理
指导教师:
姓 名:
班 级:
学 号:
日 期:
信 息 工 程 学 院
一、设计内容
简单 CPU 模拟器的设计与实现
二、设计要求
计算机组成原理这门课程主要是告诉我们在硬件上计算机是如何工作的,如何实现我们
的操作的,即让我们了解计算机的基本组成结构以及数据和命令在计算机的物理层面上如何
运行的。在学习完这门课程后,我们应该能够运用该课程的基本原理和基本方法,对有关计
算机硬件系统中的理论和实际问题进行计算和分析,并能对一些基本部件进行简单设计。因
此在本次计算机原理课程设计中,我运用了所学的知识,对计算机 CPU 运行的过程进行了一
次模拟。
1.模拟 CPU 基本组成
本次模拟的 CPU 由指令寄存器 IR、数据寄存器、PC 寄存器、程序状态寄存器 SR、16
个通用寄存器组成。指令寄存器地址总线和数据总线宽度为 16 位,数据总线的地址宽度为
16 位,数据总线的宽度为 8 位。指令寄存器 IR、PC 寄存器宽度为 16 位,16 个通用寄存器
组 R0-R15, 对应的宽度为 8 位,对应的地址为 0—15。通用寄存器、程序状态寄存器和数据
存储器统一编址,通用寄存器既可以用寄存器号访问,也可以用地址空间的地址访问。
程序状态寄存器的位位置、位名称、读写属性、复位时的值见下图:
所对应的含义如下:
图 1 程序状态寄存器介绍
I:全局中断允许位:为 1 时,允许中断,否则,禁止中断,CPU 响应中断时,硬件将
此位清 0,从中断返回时,将此位置 1
T:位复制存储位:BLD 指令用此位的值与 16 个通用寄存器中的某位交换值
H:半进位标志:即低 4 位是否向高 4 位进位或借位,如果有则为 1,否则,为 0
S:符号标志位:本位是位 N 和位 V 的异或值
V:有符号数溢出标志位
C:无符号数溢出标志位
N:负数标志位:若运算结果是负数,则为 1;否则,为 0
Z:0 标志位:若运算结果是 0,则为 1;否则,为 0
2.本课程设计 CPU 模拟的内容
2.1 本次模拟 CPU 内容
在本次实验中,模拟 CPU 的主要内容为对输入的指令进行模拟,pc+1,IR 寄存器显示当
前所执行的指令的二进制码,同时若本次操作对寄存器有影响,也将对相应的寄存器有所影
响。本次实验主要展示的指令如下:
加法指令;格式为(Add Rd , Rr),其中 Rd 为目的操作数寄存器,Rr 为原操作数寄存器,
其功能是:Rd <- Rd+Rr,机器码(二进制表示)0000 1100 dddd rrrr,其中,rrrr 为源
操作数的寄存器号,dddd 为目的操作数的寄存器号,所影响的标志位 Z,C,N,V,H,S。
减法指令:格式为(Sub Rd , Rr), 其中 Rd 为目的操作数寄存器,Rr 为原操作数寄
存器,其功能是:Rd <- Rd-Rr,机器码(二进制表示)0000 1000 dddd rrrr,其中,rrrr
为源操作数的寄存器号,dddd 为目的操作数的寄存器号,所影响的标志位 Z,C,N,V,H,S。
无符号乘法指令:格式为(Mul Rd, Rr),其中 Rd 为目的操作数寄存器,Rr 为原操作
数寄存器,其功能是:R1:R0 <- Rd*Rr,机器码(二进制表示)1001 1100 dddd rrrr,其
中,rrrr 为源操作数的寄存器号,dddd 为目的操作数的寄存器号,所影响的标志位 Z,C。
无条件相对跳转指令:格式为(RJMP K),其功能:PC<-PC+K+1,机器码(二进制表示),
1100 kkkk kkkk kkkk,其中, kkkk kkkk kkkk 为相对地址,所影响的标志:无
有条件相对跳转指令:格式为(BRMI K),其功能:if (N == 1) PC
<- PC + k + 1,
机器码(二进制表示),1111 0001 kkkk kkkk ,其中, kkkk kkkk 为相对地址,所影响的
标志位:无
数据传送指令:格式为(mov Rd, Rr),其功能是:Rd <-Rr,机器码(二进制表示), 0010
1100 dddd rrrr,其中,rrrrr 为源操作数的寄存器号,ddddd 为目的操作数的寄存器号,
所影响的标志位:无
载入立即数指令: 格式为(ldi Rd, K),其功能是:Rd <-K,机器码(二进制表示) 1110
KKKK dddd KKKK,其中,dddd 为目的操作数的寄存器号,目的寄存器只能是 r8~r15; KKKK KKKK
是立即数。所影响的标志位:无
装载指令:格式为(ld Rd, X),其功能:Rd <-(X),机器码(二进制表示),001 0000
dddd 1100
其中,dddd 为目的操作数的寄存器号,影响的标志位:无,其 X 为 R14 寄存器。
存储指令:格式为(st X, Rr),其功能 (X) <-Rr,器码(二进制表示),001 0010 rrrr
1100,中,rrrr 源操作数的寄存器号, X 为 R14:寄存器,所影响的标志位:无
空操作指令:格式为(nop),其功能 :不做任何操作,只消耗 CPU 时间,器码(二进
制表示)0000 0000 0000 0000,影响的标志位 :无
三、设计过程
本次我的课程设计主要是模拟计算机 CPU 工作过程,我的设计思路也是跟着 CPU 工作过
程来做的,因此本次课程设计也将以 CPU 工作过程为线索展开。
1.取指令
CPU 的控制器从内存读取一条指令并放入指令寄存器。指令一般包括操作码和操作数地
址。在程序中我先将指令读出来,存放在 instruction 字符串型数组中,即模拟了取指令过
程。
2、指令译码:
指令寄存器中的指令经过译码,决定该指令应进行何种操作。我们可以这么理解指令译
码阶段,就是告诉我们做什么操作(就是指令里的操作码)、操作数在哪里(操作数的地址)。
为了实现这个过程,我写了如下方法,形参为指令,方法功能及说明如下:
(1)getIrString(string str): 空格指令分割函数,返回的是指令码的字符串
(2)static string getAdrString(string str):空指令分割函数,返回的是
址码部分,包括寄存器和操作数两部分,即 register+resgiter/number
但由于老师给的测试文件中 Ld 指令,操作码与操作数地址分割是里两个空格,所以另外
封装针对 Ld 指令的方法如下:
(1)static string getLdString(string str):返回的是寄存器地址
(2)static string getLdAdrString(string str):空指令分割函数,返回的是
址码部分,包括寄存器和操作数两部分。
译码主要方法及功能如下:
static string getBinaryString(string str):形参是一个 16 进制数字符串,
返回一个二进制字符串
指令译码的部分只介绍主要方法,底层方法不一一赘述。
在取得指令后,将用 if 判断取得的指令是什么,并判断应该执行什么指令,到此,指令译
码完美模拟。
3、 执行指令
执行分两个阶段“取操作数”和“进行运算”。我们先来看有操作数的指令。我的做法
是先确定是什么操作(这个在上一条已经实现),本步的主要内容是根据执行操作。以 add
指令为例,首先,我们在上一步确定了这是一个加法指令,那么我们现在先根据地址码,获
得寄存器地址,再用 string getRegisterText()方法获得寄存器存的数,通过定义的 add
()方法进行运算,运算完毕,通过 setRegister()方法,将结果送入指定的寄存器。
取操作数的方法及及说明如下:
(1)string getRegisterText(string registerName) :得指定寄存器的文本内容,返
回的是一个二进制字符串。
运算方法及说明如下:
(1)static string add(string str1, string str2):加法指令运算,形参为两个二
进制字符串,传出的是相加后的结果字符串
(2)static string sub(string str1, string str2):减法指令运算,形参为两个二
进制字符串,传出的是相减后的结果字符串
(3)static string[] mul(string str1, string str2):乘法指令运算,形参为两个
二进制字符串,传出的是相减后的结果字符串
将操作数送入寄存器方法及说明如下:
(1)public void setRegister(string registerName, string
registerText):将文本送入指定寄存器
4、 修改指令计数器
即为 PC 加一,决定下一条指令的地址。本次让 stepCount 加一,即为 pc 加一,指向了
下一条指令的地址
通过以上的模拟,我最终的模拟运行截图结果如下:
四、设计中遇到的问题和解决方案
本次设计中我遇到的问题如下:
(1)如何确定地址码,操作码
通过计算机原理这门课程的学习,我知道指令的格式为:操作码+地址码,在老师给的
文件中,操作码和地址码采用之间空格进行分割,两个地址码之间采用“,”,进行分割,因
此我选择了 c#字符串方法中的 split 和 subString 方法进行分割,避免了多余的代码。
(2)如何向指定寄存器赋值
在我的设计过程中由于经常要对寄存器的内容进行改变,如果一个个的判断赋值,就会
向别的同学那样,写上万行的代码,这样就太浪费时间了,通过查找资料,我选择了 c#中
Control 类和借助 foreach 来实现,节约了时间和精力。
(3)二进制字符串长度不够
由于通用寄存器长度为八位,但有时数据译成二进制字符串后,长度往往会出现不
够的情况,因此,我自己动手写了几个 newStr()函数,当字符串长度不够时,补零。
五、设计感触
经过不断的努力,终于将这个程序做好了!但是这次设计的结果我并不是特别满意,因
无条件相对跳转指令我的实现效果并不好,有条件的相对跳转指令我没有实现。可是我还是
收获了特别多的东西,从一开始的毫无思路,到跟着 CPU 工作过程一步步实现,从无到有,
能力得到了很大的提升,也对 CPU 的工作过程有了更深的认识和理解。
而且我充分体验到了编程中的苦与乐,也充分认识到自己还有很多的东西要学习,并且
产生了巨大的动力去提升自己充实自己。通过这次实验设计使我更加的体会到 CPU 如何去工
作的,也意识到了解计算机的工作原理是在这个领域好好是走下去的不可缺少的基础。我还
明白了许多道理:
1、学习在于积累:学习的成果不可能一天两天就能得到的,只有长期的积累才可能将
量变达到质变。
2、做开发,就像喝咖啡,过程中我们品尝其中的苦涩,结果里我们回味它的香气。
3、软件服务于人类,软件是在解决一些生活中的问题和错误,问题决定解决方案。
学无止境,这次的实验设计只是学习生涯的一部分,对于一个在校生来说,学习知识是
最重要的,为了自己以后的路,好好学习,对自己负责!