码迷,mamicode.com
首页 > 其他好文 > 详细

自己动手写处理器之第二阶段(5)——ModelSim电路仿真

时间:2014-07-22 14:03:04      阅读:444      评论:0      收藏:0      [点我收藏+]

标签:自己动手写处理器   软核   开源   mips   处理器   

将陆续上传本人写的新书《自己动手写处理器》(尚未出版),今天是第九篇,我尽量每周四篇


2.8 仿真

      上一节实现了一个简化的处理器取指电路,需要通过仿真以验证其功能是否正确,直观的仿真思路就是:给出一个时钟信号,上述电路会在每个时钟信号上升沿将取指地址加1,同时从指令存储器中取出一条指令,观察取指地址是否依次递增,同时观察取出的指令是否是存储器中取指地址对应的指令,如果都符合,那么上述取指电路就实现正确。此处涉及到两个问题。

      1、如何在指令存储器中存储指令,也就是指令存储器初始化问题。

      2、如何给出时钟信号?

      本节将分别解答上述问题,在此基础上,使用ModelSim进行仿真。

2.8.1 系统函数

      初始化存储器有两种方法,一种是对存储器中每个存储单元依次给出初值,如下。

rom[0] = 32'h00000000;   //存储器rom的第0个元素初始化为0x00000000
rom[1] = 32'h01010101;   //存储器rom的第1个元素初始化为0x01010101
rom[2] = 32'h02020202;   //存储器rom的第2个元素初始化为0x02020202
rom[3] = 32'h03030303;   //存储器rom的第3个元素初始化为0x03030303
......

      另一种方法是使用系统函数$readmemh,这样更加方便,但是后者只能用于仿真中。

      除了$readmemh外,在Verilog HDL中还定义了很多系统函数,比如显示当前仿真时间的函数$time、显示信号值的函数$display、暂停仿真过程的函数$stop、结束仿真过程的函数$finish等。本书主要用到了$stop、$readmemh这两个系统函数。

      1、$stop

      $stop用于对仿真过程进行控制,暂停仿真,其使用格式如下。

$stop();       // 使用格式一,不带参数
$stop(n);      // 使用格式二,带参数n,n可以等于0、1、2等值,含义如下:
               // 0:不输出任何信息;
               // 1:给出仿真时间和位置
               // 2:给出仿真时间和位置,还有其它一些运行统计数据

      当仿真程序执行到$stop语句时,将暂时停止仿真,此时设计者可以输入命令,对仿真器进行交互控制。

      2、$readmemh

      $readmemh函数用于读取文件,其作用是从外部文件中读取数据并放入存储器中。使用格式如下。

$readmemh("数据文件名", 存储对象);

      将第1个参数指定文件的数据读入第2个参数指定的存储器中。例如。

reg[31:0]  rom[63:0];

initial $readmemh ( "rom.data", rom );  // 读入文件rom.data的数据到rom中
      此处对数据文件的格式有一定要求,要求使用十六进制记录数据,且每一行记录一个地址的数据。例如:rom.data的内容如下,每一行是一个32位的数据。

00000000
01010101
02020202
03030303
......

      使用$readmemh ( "rom.data", rom )函数后,rom的内容就会初始化为如下。

rom[0]: 32'h00000000;   //存储器rom的第0个元素初始化为0x00000000
rom[1]: 32'h01010101;   //存储器rom的第1个元素初始化为0x01010101
rom[2]: 32'h02020202;   //存储器rom的第2个元素初始化为0x02020202
rom[3]: 32'h03030303;   //存储器rom的第3个元素初始化为0x03030303
......

      回到本节最开始提出的两个问题,现在可以回答第一个问题了,为了实现对指令存储器的初始化,只需要创建一个数据文件,其内容如上面的rom.data所示,然后在指令存储器rom.v中,增加代码$readmemh ("rom.data", rom )即可。完整代码可以参考本书光盘Code\Chapter2目录下的rom.v文件。

2.8.2 Test Bench

      现在回答本节最开始提出的第二个问题,通过创建Test Bench文件以给出时钟信号。

      Test Bench为测试或仿真一个Verilog HDL程序搭建了一个平台,我们给被测试的模块施加激励信号,通过观察被测试模块的输出响应,从而判断其逻辑功能实现的正确与否。如图2-17所示。

bubuko.com,布布扣

      Test Bench的结构如图2-18所示,与2.4节介绍的Verilog HDL模块的结构没有根本区别,但有自身的一些特点。

  •  Test Bench只有模块名,没有端口列表;激励信号(输入到待测试模块的信号)必须定义为reg类型,以保持信号值;从待测试模块输出的信号(用户观察的信号)必须定义为wire类型。
  •  在Test Bench中要调用被测试模块,也就是元件例化。
  •  Test Bench中一般会使用initial、always过程块来定义、描述激励信号。

bubuko.com,布布扣

      为简单取指令电路设计的Test Bench如下,完整代码位于本书光盘Code\Chapter2目录下的inst_fetch_tb.v文件。

module inst_fetch_tb;          // Test Bench名为inst_fetch_tb

/****************************************************************
***********              第一段:数据类型说明             *********
*****************************************************************/

  reg           CLOCK;         // 激励信号CLOCK,这是时钟信号
  reg           rst;           // 激励信号rst,这是复位信号
  wire[31:0]    inst;          // 显示信号inst,取出的指令

/****************************************************************
***********              第二段:激励向量定义             *********
*****************************************************************/

  // 定义CLOCK信号,每隔10个时间单位,CLOCK的值翻转,由此得到一个周期信号。
  // 在仿真的时候,一个时间单位默认是1ns,所以CLOCK的值每10ns翻转一次,对应
  // 就是50MHz的时钟
  initial begin
    CLOCK = 1'b0;
    forever #10 CLOCK = ~CLOCK;
  end
  
  // 定义rst信号,最开始为1,表示复位信号有效,过了195个时间单位,即195ns,
  // 设置rst信号的值为0,复位信号无效,复位结束,再运行1000ns,暂停仿真
  initial begin
    rst = 1'b1;
    #195 rst= 1'b0;
    #1000 $stop;
  end

/****************************************************************
***********             第三段:待测试模块例化            *********
*****************************************************************/

  inst_fetch inst_fetch0(
		.clk(CLOCK),
		.rst(rst),
		.inst_o(inst)	
	);

endmodule

2.8.3 ModelSim仿真

      指令存储器初始化问题解决了、时钟信号也给出了,现在可以使用ModelSim进行仿真了。

      1、建立ModelSim工程

      打开ModelSim,选择File->New->Project,出现新建工程对话框,其中填写工程名,选择保存目录,注意保存目录中不要有中文,如图2-19所示。

bubuko.com,布布扣

      点击OK后,会出现图2-20所示的界面,这里点击Add Existing File,也就是添加已有文件,出现图2-21所示的添加文件对话框。

bubuko.com,布布扣

      点击Browse按钮,出现选择文件对话框,找到本书光盘的Code\Chapter2目录,添加其中所有的.v文件,如图2-22所示。

bubuko.com,布布扣

      选择要添加的文件后,点击“打开”按钮,即完成添加,此时显示图2-23所示界面,在其中选中copy to project directory,这样就会将刚才选中的文件复制到新的工程目录下。

bubuko.com,布布扣

      文件添加完成后,会在ModelSim的主界面中显示所有文件的状态,其中问号表示对应文件没有编译。任意选中一个文件,鼠标右键单击,在弹出菜单中选择Compile->Compile All,即开始编译所有文件,如图2-24所示。稍等几秒钟就编译结束了。编译结束后,所有的文件状态都应该是一个绿色的“√”。

bubuko.com,布布扣

      2、开始仿真

      切换到Library这个Tab,然后展开work目录,在inst_fetch_tb文件上点击右键,在弹出菜单中选择Simulate,如图2-25所示。

bubuko.com,布布扣

      此时会增加一个Tab,名称为sim,展开其中的inst_fetch_tb节点,选择inst_fetch0,会在Objects窗口中显示inst_fetch模块的所有信号,如图2-26所示,如果没有出现Objects窗口,可以通过菜单View->Objects调出该窗口。

bubuko.com,布布扣

      选择Objects窗口中的所有信号,然后点击右键,在弹出菜单中选择Add to->Wave->Selected Signals,如图2-27所示,将所有信号都添加到Wave窗口中。这些都是要观察的信号。如图2-28所示。

bubuko.com,布布扣

      点击工具栏中的Run-All按钮,就可开始仿真,如图2-29所示,仿真结果如图2-30所示。从仿真结果可知,处理器取指令电路实现正确。

bubuko.com,布布扣

bubuko.com,布布扣

2.9 小结

      本章花了比较大的篇幅介绍了可编程逻辑器件的基本知识,以及基于可编程逻辑器件的数字系统设计流程,包括设计输入、综合、布局布线、下载、仿真等几步,这与传统的数字系统设计流程还是有很大不同的。然后介绍了Verilog HDL这样一种硬件编程语言,这也是将要用来实现OpenMIPS处理器的语言。在此基础上,设计实现了一个简化的处理器取指令电路,并使用ModelSim仿真验证该电路实现的正确性。在后期教学版OpenMIPS的设计实现过程中,也主要是使用ModelSim仿真验证,步骤都是一样的。

      从下一次开始,就正式进入OpenMIPS处理器的设计实现阶段了。未完待续!

自己动手写处理器之第二阶段(5)——ModelSim电路仿真

标签:自己动手写处理器   软核   开源   mips   处理器   

原文地址:http://blog.csdn.net/leishangwen/article/details/38040203

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!