计算机原理:简单CPU模拟器的设计与实现

/*

计算机课程设计实验报告

跳转指令用栈实现

*/

一、设计内容

简单CPU模拟器的设计与实现

 

二、设计要求

计算机组成原理这门课程主要是告诉我们在硬件上计算机是如何工作的,如何实现我们的操作的,即让我们了解计算机的基本组成结构以及数据和命令在计算机的物理层面上如何运行的。在学习完这门课程后,我们应该能够运用该课程的基本原理和基本方法,对有关计算机硬件系统中的理论和实际问题进行计算和分析,并能对一些基本部件进行简单设计。因此在本次计算机原理课程设计中,我运用了所学的知识,对计算机CPU运行的过程进行了一次模拟。

1.模拟CPU基本组成

本次模拟的CPU由指令寄存器IR、数据寄存器、PC寄存器、程序状态寄存器SR、16个通用寄存器组成。指令寄存器地址总线和数据总线宽度为16位,数据总线的地址宽度为16位,数据总线的宽度为8位。指令寄存器IR、PC寄存器宽度为16位,16个通用寄存器组R0-R15, 对应的宽度为8位,对应的地址为0—15。通用寄存器、程序状态寄存器和数据存储器统一编址,通用寄存器既可以用寄存器号访问,也可以用地址空间的地址访问。

程序状态寄存器的位位置、位名称、读写属性、复位时的值见下图:

计算机原理:简单CPU模拟器的设计与实现_第1张图片

图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的工作过程有了更深的认识和理解。

 

你可能感兴趣的:(计算机原理课程设计)