自己写CPU第四阶段(2)——验证该第一指令ori实现效果
我们会继续上传新书《自己写CPU》(未公布),今天是12片,四篇
书名又之前的《自己动手写处理器》改为《自己动手写CPU》
4.3 验证OpenMIPS实现效果
4.3.1指令存储器ROM的实现
本节将验证我们的OpenMIPS是否实现正确,包括:流水线是否正确、ori指令是否实现正确。在验证之前,须要首先实现指令存储器,以便OpenMIPS从中读取指令。
指令存储器模块是仅仅读的。其接口如图4-7所看到的,还是採用左边是输入接口,右边是输出接口的方式绘制。这样便于理解。
接口含义如表4-12所看到的。
指令存储器ROM模块在文件inst_rom.v中实现,代码例如以下,能够在本书附带光盘的Code\Chapter4\文件夹下找到源文件。
module inst_rom( input wire ce,
input wire[`InstAddrBus] addr,
output reg[`InstBus] inst );
// 定义一个数组,大小是InstMemNum,元素宽度是InstBus
reg[`InstBus] inst_mem[0:`InstMemNum-1]; // 使用文件inst_rom.data初始化指令存储器
initial $readmemh ( "inst_rom.data", inst_mem ); // 当复位信号无效时,根据输入的地址。给出指令存储器ROM中相应的元素
always @ (*) begin
if (ce == `ChipDisable) begin
inst <= `ZeroWord;
end else begin
inst <= inst_mem[addr[`InstMemNumLog2+1:2]];
end
end endmodule
代码非常好理解,有下面几点说明。
(1)在初始化指令存储器时,使用了initial过程语句。
initial过程语句仅仅运行一次,通经常使用于仿真模块中对激励向量的描写叙述,或用于给变量赋初值,是面向模拟仿真的过程语句。通常不能被综合工具支持。所以假设要将本章实现的OpenMIPS处理器使用综合工具进行综合,那么须要改动这里初始化指令存储器的方法。
(2)在初始化指令存储器时,使用了系统函数$readmemh,表示从inst_rom.data文件里读取数据以初始化inst_mem,而inst_mem正是之前定义的数组。inst_rom.data是一个文本文件。里面存储的是指令。其每行存储一条32位宽度的指令(使用十六进制表示),系统函数$readmemh会将inst_rom.data中的数据依次填写到inst_mem数组中。
(3)OpenMIPS是依照字节寻址的。而此处定义的指令存储器的每一个地址是一个32bit的字,所以要将OpenMIPS给出的指令地址除以4再使用。比方:要读取地址0xC处的指令,那么实际就是相应ROM的inst_mem[3],如图4-8所看到的。
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGVpc2hhbmd3ZW4=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">
除以4也就是将指令地址右移2位。所以在读取的时候给出的地址是addr[`InstMemNumLog2+1:2]。当中InstMemNumLog2是指令存储器的实际地址宽度,比方:假设inst_mem有1024个元素,那么InstMemNum等于1024。InstMemNumLog2等于10。表示实际地址宽度为10。
4.3.2 最小SOPC的实现
为了验证。须要建立一个SOPC,当中仅包括OpenMIPS、指令存储器ROM,所以是一个最小SOPC。OpenMIPS从指令存储器中读取指令,指令进入OpenMIPS開始运行。
最小SOPC的结构如图4-9所看到的。
最小SOPC相应的模块是openmips_min_sopc。位于文件openmips_min_sopc.v中,读者能够在本书附带光盘的Code\Chapter4\文件夹下找到该文件。主要内容例如以下。
在当中例化了处理器OpenMIPS、指令存储器ROM,并将两者依照图4-9的方式连接。
module openmips_min_sopc( input wire clk,
input wire rst ); // 连接指令存储器
wire[`InstAddrBus] inst_addr;
wire[`InstBus] inst;
wire rom_ce; // 例化处理器OpenMIPS
openmips openmips0(
.clk(clk), .rst(rst),
.rom_addr_o(inst_addr), .rom_data_i(inst),
.rom_ce(rom_ce)
); // 例化指令存储器ROM
inst_rom inst_rom0(
.ce(rom_ce),
.addr(inst_addr), .inst(inst)
); endmodule
4.3.3 编写測试程序
我们须要写一段測试程序,并将其存储到指令存储器ROM,这样当上一节建立的最小SOPC開始执行的时候,就会从ROM中取出我们的程序,送入OpenMIPS处理器执行。因为眼下的OpenMIPS仅仅实现了一条ori指令。所以測试程序非常easy,例如以下,相应本书附带光盘Code\Chapter4\TestAsm文件夹下的inst_rom.S文件。
ori $1,$0,0x1100 # $1 = $0 | 0x1100 = 0x1100
ori $2,$0,0x0020 # $2 = $0 | 0x0020 = 0x0020
ori $3,$0,0xff00 # $3 = $0 | 0xff00 = 0xff00
ori $4,$0,0xffff # $4 = $0 | 0xffff = 0xffff
共同拥有4条指令。都是ori指令。
第1条指令将0x1100进行零扩展后与寄存器$0进行逻辑“或”运算。结果保存在寄存器$1中。
第2条指令将0x0020进行零扩展后与寄存器$0进行逻辑“或”运算,结果保存在寄存器$2中。
第3条指令将0xff00进行零扩展后与寄存器$0进行逻辑“或”运算,结果保存在寄存器$3中。
第4条指令将0xffff进行零扩展后与寄存器$0进行逻辑“或”运算,结果保存在寄存器$4中。
指令的凝视说明了指令的运行结果。接下来,依照正常的顺序应该是使用编译器编译我们的測试程序。但因为GCC编译器的安装、使用、Makefile文件的制作等内容还须要不少篇幅解说,而想必各位读者和笔者一样。急切地想知道OpenMIPS是否实现正确,所以本节採用手工编译的方式编译測试程序,4.4节将专题介绍GCC编译器的使用。
手工编译仅仅需依照指令内容填充进图4-1所看到的的ori指令格式中,就可以得到相应的二进制字,比方:对于指令ori $1,$0,0x1100。相应的二进制字如图4-10所看到的。
转化为十六进制即0x34011100,其余3条指令依照相同的方式能够得到相应的二进制字,依照$readmemh函数的要求。一行放一条指令。得到測试程序相应的isnt_rom.data文件例如以下,可在本书附带光盘的Code\Chapter4\TestAsm文件夹下找到同名文件。
34011100
34020020
3403ff00
3404ffff
4.3.4 建立Test Bench文件
本小节将建立Test Bench文件,当中给出最小SOPC执行所需的时钟信号、复位信号。代码例如以下,相应本书附带光盘Code\Chapter4\文件夹下的openmips_min_sopc_tb.v文件。
// 时间单位是1ns,精度是1ps
`timescale 1ns/1ps module openmips_min_sopc_tb(); reg CLOCK_50;
reg rst; // 每隔10ns。CLOCK_50信号翻转一次。所以一个周期是20ns。相应50MHz
initial begin
CLOCK_50 = 1'b0;
forever #10 CLOCK_50 = ~CLOCK_50;
end // 最初时刻。复位信号有效,在第195ns,复位信号无效,最小SOPC開始执行
// 执行1000ns后,暂停仿真
initial begin
rst = `RstEnable;
#195 rst= `RstDisable;
#1000 $stop;
end // 例化最小SOPC
openmips_min_sopc openmips_min_sopc0(
.clk(CLOCK_50),
.rst(rst)
); endmodule
4.3.5使用ModelSim检验OpenMIPS实现效果
万事俱备,仅仅欠东风了,本节是验证前的最后一步——建立ModelSimproject,进行仿真。參考第2章的介绍,新建一个ModelSimproject,project名能够为openmips_min_sopc。将上文创建的OpenMIPS全部源文件、Test Bench文件、指令存储器的源文件等(也就是本书附带光盘Code\Chapter4文件夹下全部.v文件)加入到project中。然后编译。
注意:还须要将上一小克制作的inst_rom.data文件拷贝到project文件夹下。
编译通过后。将workspace切换到Library选项卡,打开work这个library,选中openmips_min_sopc_tb,右键点击。选择Simulate,如图4-11所看到的。
在出现的波形显示界面中,加入要观察的信号,就可以開始仿真。此处我们选择寄存器$1-$4作为观察对象,如图4-12所看到的。通过观察寄存器$1-$4的终于值,可知OpenMIPS正确运行了測试程序,也就是正确实现了ori指令。
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGVpc2hhbmd3ZW4=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">
加入很多其他要观察的信号,能够了解流水线运行情况。如图4-13所看到的。
为了使流水线情况显示的更加直观。此处以第一条指令在流水线中的运行过程为例。而且图中去掉了其他指令运行时引起的信号变化。
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGVpc2hhbmd3ZW4=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">
(1)在复位结束后的第一个时钟周期上升沿,rom_ce_o变为ChipEnable。表示指令存储器使能。開始取指。进入取指阶段,从指令存储器中取出第一条指令0x34011100。赋给IF/ID模块的输入portif_inst。下一个时钟周期,第一条指令进入译码阶段。
(2)观察译码阶段。
- 此时译码阶段的指令id_inst正是第一条指令0x34011100
- 指令地址id_pc是0x00000000
- 在ID模块对指令进行译码。得到指令运算类型alusel_o是3'b001。查询defines.h文件里的宏定义可知。相应宏EXE_RES_LOGIC,表示是逻辑运算
- 得到运算子类型aluop_o是8'b00100101,查询defines.h文件里的宏定义可知,相应宏EXE_OR_OP。表示逻辑“或”运算
- 译码得到參与运算的源操作数1是0x00000000。正是$0寄存器的值
- 译码得到參与运算的源操作数2是0x00001100。正是指令中马上数零扩展后的值
- 译码得到wreg_o的值为1,表示要写目的寄存器
- 译码得到要写入的目的寄存器wd_o是5'b00001。正是$1寄存器
(3)观察运行阶段。
- 进行指定的运算。得到wdata_o为0x00001100,就是要写到目的寄存器的数据
- 传递译码阶段wreg_o的值,为1,表示要写目的寄存器
- 传递译码阶段wd_o的值。为5'b00001。表示要写入的目的寄存器是$1寄存器
(4)观察訪存阶段
- 传递运行阶段wdata_o的值,为0x00001100,表示要写到目的寄存器的数据
- 传递运行阶段wreg_o的值。为1,表示要写目的寄存器
- 传递运行阶段wd_o的值。为5'b00001,表示要写入的目的寄存器是$1寄存器
(5)观察回写阶段
- 得到訪存阶段wdata_o的值,为0x00001100,表示要写到目的寄存器的数据
- 得到訪存阶段wreg_o的值,为1。表示要写目的寄存器
- 得到訪存阶段wd_o的值,为5'b00001。表示要写入的目的寄存器是$1寄存器
在回写阶段的最后,将依照要求写目的寄存器$1,使得$1的值为0x00001100。
通过上面的观察。可知原始的OpenMIPS五级流水线实现正确。接下来。我们就能够以此为基础,不断充实,加入实现很多其它的MIPS指令,只是,在此之前,我们要先学习使用GNU工具链。本节的样例仅仅有4条指令,能够手工编译,以后会遇到比較复杂。拥有较多指令的程序。届时,手工编译就显得效率低下了,所以要使用GNU工具链。
待续!
版权声明:本文博客原创文章。博客,未经同意,不得转载。
自己写CPU第四阶段(2)——验证该第一指令ori实现效果的更多相关文章
- 自己动手写CPU之第九阶段(8)——MIPS32中的LL、SC指令说明
将陆续上传新书<自己动手写CPU>,今天是第47篇. 9.7 ll.sc指令实现思路 9.7.1 实现思路 这2条指令都涉及到訪问链接状态位LLbit,能够将LLbit当做寄存器处理,ll ...
- 自己动手写处理器之第四阶段(1)——第一条指令ori的实现
将陆续上传本人写的新书<自己动手写处理器>(尚未出版),今天是第11篇,我尽量每周四篇 第4章 第一条指令ori的实现 前面几章介绍了非常多预备知识,也描绘了即将要实现的OpenMIPS处 ...
- 自己动手写CPU之第九阶段(4)——载入存储指令实现思路
将陆续上传新书<自己动手写CPU>,今天是第40篇,我尽量每周四篇,可是近期已经非常久没有实现这个目标了,一直都有事,不好意思哈. 开展晒书评送书活动,在q=%E4%BA%9A%E9%A9 ...
- 自己动手写CPU之第九阶段(2)——载入存储指令说明2(lwl、lwr)
将陆续上传新书<自己动手写CPU>.今天是第38篇,我尽量每周四篇,可是近期已经非常久没有实现这个目标了.一直都有事,不好意思哈. 开展晒书评送书活动,在q=%E4%BA%9A%E9%A9 ...
- 自己动手写CPU之第九阶段(7)——MIPS32中的LL、SC指令说明
将陆续上传新书<自己动手写CPU>,今天是第46篇. 在MIPS32指令集中有两条特殊的存储载入指令:链接载入指令LL.条件存储指令SC,本次将介绍这两条指令.在兴许将实现这两条指令. 9 ...
- 自己动手写CPU之第四阶段(3)——MIPS编译环境的建立
将陆续上传本人写的新书<自己动手写CPU>(尚未出版).今天是第13篇.我尽量每周四篇 4.4 MIPS编译环境的建立 OpenMIPS处理器在设计的时候就计划与MIPS32指令集架构兼容 ...
- 自己动手写CPU之第五阶段(1)——流水线数据相关问题
将陆续上传本人写的新书<自己动手写CPU>(尚未出版),今天是第15篇,我尽量每周四篇 上一章建立了原始的OpenMIPS五级流水线结构,可是仅仅实现了一条ori指令,从本章開始,将逐步完 ...
- 自己动手写CPU之第七阶段(7)——乘累加指令的实现
将陆续上传本人写的新书<自己动手写CPU>.今天是第30篇.我尽量每周四篇 亚马逊的销售地址例如以下.欢迎大家围观呵! http://www.amazon.cn/dp/b00mqkrlg8 ...
- 自己动手写CPU之第六阶段(2)——移动操作指令实现思路
将陆续上传本人写的新书<自己动手写CPU>(尚未出版),今天是第21篇,我尽量每周四篇 6.2 移动操作指令实现思路 6.2.1 实现思路 这6条移动操作指令能够分为两类:一类是不涉及特殊 ...
随机推荐
- Unity3d之MiniJson与LitJson之间的较量
由于项目不得不用到json来解析服务器端传来的数据,于是不得不选择一种在unity3d上面可用的json.开始根据网上推荐LitJson,于是下载下来源码,导入项目: 经过测试可以用:但是移植到ipa ...
- PHP上传文件超过了最大文件大小限制导致无法上传成功
最近的研究<HeadFirst PHP & MySQL>第一本书5章"使用存储在文件中的数据",难道当一个文件上传应用程序,发生了错误.即,文件不能成功上传.这 ...
- 采用DWR、maven保存数据到数据库
一.原理: Ajax是时下比较流行的一种web界面设计新思路,其核心思想是从浏览器获取XMLHttp对象与服务器端进行交互. DWR(Direct Web Remoting)就是实现了这种Ajax技术 ...
- [背景分离] 识别移动物体基于高斯混合 MOG
使用很easy, frame 就是当前帧, foreground 是取得的, binary 型背景, 0.03是学习速率能够依据实际调整. cv::BackgroundSubtractorMOG ...
- CodeBlocks暴力恢复默认设置
昨天,我不知道怎么去CodeBlocks干净的界面使自己都不知道怎么走.然后找到默认设置恢复方法,找不到.然后,我用了一个恢复方法暴力,卸载重装,有一点须要注意.卸载后CodeBlocks的配置文件还 ...
- Unity入门
Unity入门 用unity做一个最简单的交互.(相当于Hello World)仅仅要最后能执行就算入门了. 第一步,要先用三维制作软件制作出我们须要的场景. 这儿使用的是Max2012(软件大小3. ...
- 【hadoop之翊】——基于CentOS的hadoop2.4.0伪分布安装配置
今天总算是把hadoop2.4的整个开发环境弄好了,包括 windows7上eclipse连接hadoop,eclipse的配置和測试弄得烦躁的一逗比了~ 先上一张成功的图片,hadoop的伪分布式安 ...
- 协同编辑多人word一个小技巧文件
协同编辑多人word窍门 近期在工作中编写标书时因为不同内容分给了各个部门去制作.可是在汇总后遇到再次改动的问题.对方把改动后的部分文档发给我粘贴到标书中后,所有的格式所有都乱了.又一次整理格式.标题 ...
- Hibernate4.3.9Final常见问题汇总
hibernate4下一个可用的hibernate.properties: jdbc.driverClassName=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql ...
- Android KitKat 4.4 Wifi移植AP模式和网络共享的调试日志
Tethering技术在移动平台上已经运用的越来越广泛了.它能够把移动设备当做一个接入点,其它的设备能够通过Wi-Fi.USB或是Bluetooth等方式连接到此移动设备.在Android中能够将Wi ...