自己动手写CPU之第七阶段(2)——简单算术操作指令实现过程
将陆续上传本人写的新书《自己动手写CPU》。今天是第25篇。我尽量每周四篇
亚马逊的预售地址例如以下,欢迎大家围观呵!
http://www.amazon.cn/dp/b00mqkrlg8/ref=cm_sw_r_si_dp_5kq8tb1gyhja4
China-pub的预售地址例如以下:
http://product.china-pub.com/3804025
7.2 简单算术操作指令实现思路
尽管简单算术操作指令的数目比較多。有15条。但实现方式都是相似的,与前几章逻辑、移位操作指令的实现方式也非常类似,不须要添加新的模块、新的接口,仅仅须要改动流水线译码阶段的ID模块、运行阶段的EX模块就可以。
实现思路例如以下。
(1)改动流水线译码阶段的ID模块,加入对上述简单算术操作指令的译码。给出运算类型alusel_o、运算子类型aluop_o、要写入的目的寄存器地址wd_o等信息。同一时候依据须要读取地址为rs、rt的通用寄存器的值。
(2)改动流水线运行阶段的EX模块,根据传入的信息。进行运算。得到运算结果,确定终于要写目的寄存器的信息(包括:是否写、写入的目的寄存器地址、写入的值),并将这些信息传递到訪存阶段。
(3)上述信息会一直传递到回写阶段。最后改动目的寄存器。
7.3 改动OpenMIPS以实现简单算术操作指令
7.3.1 改动译码阶段的ID模块
在译码阶段要添加对简单算术操作指令的分析,分析的前提是能推断出指令种类,依据图7-1至7-4能够给出如图7-5所看到的的确定指令种类的过程。
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGVpc2hhbmd3ZW4=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">
当中涉及的宏定义例如以下。正是图7-5中各个指令的指令码或功能码。
在本书附带光盘Code\Chapter7_1文件夹下的defines.v文件里能够找到这些宏定义。
`define EXE_SLT 6'b101010
`define EXE_SLTU 6'b101011
`define EXE_SLTI 6'b001010
`define EXE_SLTIU 6'b001011
`define EXE_ADD 6'b100000
`define EXE_ADDU 6'b100001
`define EXE_SUB 6'b100010
`define EXE_SUBU 6'b100011
`define EXE_ADDI 6'b001000
`define EXE_ADDIU 6'b001001
`define EXE_CLZ 6'b100000
`define EXE_CLO 6'b100001 `define EXE_MULT 6'b011000
`define EXE_MULTU 6'b011001
`define EXE_MUL 6'b000010
......
`define EXE_SPECIAL_INST 6'b000000
`define EXE_REGIMM_INST 6'b000001
`define EXE_SPECIAL2_INST 6'b011100
改动ID模块的代码例如以下,完整代码位于本书附带光盘Code\Chapter7_1文件夹下的id.v文件。
module id(
......
);
......
always @ (*) begin
if (rst == `RstEnable) begin
......
end else begin
aluop_o <= `EXE_NOP_OP;
alusel_o <= `EXE_RES_NOP;
wd_o <= inst_i[15:11]; // 默认目的寄存器地址wd_o
wreg_o <= `WriteDisable;
instvalid <= `InstInvalid;
reg1_read_o <= 1'b0;
reg2_read_o <= 1'b0;
reg1_addr_o <= inst_i[25:21]; // 默认的reg1_addr_o
reg2_addr_o <= inst_i[20:16]; // 默认的reg2_addr_o
imm <= `ZeroWord;
case (op)
`EXE_SPECIAL_INST: begin // op等于SPECIAL
case (op2)
5'b00000: begin // op2等于5'b00000
case (op3)
......
`EXE_SLT: begin // slt指令
wreg_o <= `WriteEnable;
aluop_o <= `EXE_SLT_OP;
alusel_o <= `EXE_RES_ARITHMETIC;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_SLTU: begin // sltu指令
wreg_o <= `WriteEnable;
aluop_o <= `EXE_SLTU_OP;
alusel_o <= `EXE_RES_ARITHMETIC;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_ADD: begin // add指令
wreg_o <= `WriteEnable;
aluop_o <= `EXE_ADD_OP;
alusel_o <= `EXE_RES_ARITHMETIC;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_ADDU: begin // addu指令
wreg_o <= `WriteEnable;
aluop_o <= `EXE_ADDU_OP;
alusel_o <= `EXE_RES_ARITHMETIC;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_SUB: begin // sub指令
wreg_o <= `WriteEnable;
aluop_o <= `EXE_SUB_OP;
alusel_o <= `EXE_RES_ARITHMETIC;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_SUBU: begin // subu指令
wreg_o <= `WriteEnable;
aluop_o <= `EXE_SUBU_OP;
alusel_o <= `EXE_RES_ARITHMETIC;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_MULT: begin // mult指令
wreg_o <= `WriteDisable;
aluop_o <= `EXE_MULT_OP;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_MULTU: begin // multu指令
wreg_o <= `WriteDisable;
aluop_o <= `EXE_MULTU_OP;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
default: begin
end
endcase // end case op3
end
default: begin
end
endcase // end case op2
end
......
`EXE_SLTI: begin // slti指令
wreg_o <= `WriteEnable;
aluop_o <= `EXE_SLT_OP;
alusel_o <= `EXE_RES_ARITHMETIC;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b0;
imm <= {{16{inst_i[15]}}, inst_i[15:0]};
wd_o <= inst_i[20:16];
instvalid <= `InstValid;
end
`EXE_SLTIU: begin // sltiu指令
wreg_o <= `WriteEnable;
aluop_o <= `EXE_SLTU_OP;
alusel_o <= `EXE_RES_ARITHMETIC;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b0;
imm <= {{16{inst_i[15]}}, inst_i[15:0]};
wd_o <= inst_i[20:16];
instvalid <= `InstValid;
end
`EXE_ADDI: begin // addi指令
wreg_o <= `WriteEnable;
aluop_o <= `EXE_ADDI_OP;
alusel_o <= `EXE_RES_ARITHMETIC;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b0;
imm <= {{16{inst_i[15]}}, inst_i[15:0]};
wd_o <= inst_i[20:16];
instvalid <= `InstValid;
end
`EXE_ADDIU: begin // addiu指令
wreg_o <= `WriteEnable;
aluop_o <= `EXE_ADDIU_OP;
alusel_o <= `EXE_RES_ARITHMETIC;
reg1_read_o <= 1'b1; reg2_read_o <= 1'b0;
imm <= {{16{inst_i[15]}}, inst_i[15:0]};
wd_o <= inst_i[20:16];
instvalid <= `InstValid;
end
`EXE_SPECIAL2_INST: begin // op等于SPECIAL2
case ( op3 )
`EXE_CLZ: begin // clz指令
wreg_o <= `WriteEnable;
aluop_o <= `EXE_CLZ_OP;
alusel_o <= `EXE_RES_ARITHMETIC;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b0;
instvalid <= `InstValid;
end
`EXE_CLO: begin // clo指令
wreg_o <= `WriteEnable;
aluop_o <= `EXE_CLO_OP;
alusel_o <= `EXE_RES_ARITHMETIC;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b0;
instvalid <= `InstValid;
end
`EXE_MUL: begin // mul指令
wreg_o <= `WriteEnable;
aluop_o <= `EXE_MUL_OP;
alusel_o <= `EXE_RES_MUL;
reg1_read_o <= 1'b1;
reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
default: begin
end
endcase //EXE_SPECIAL_INST2 case
end
default: begin
end
endcase //case op ...... endmodule
对任一条指令而言,译码工作的主要内容是:确定要读取的寄存器情况、要运行的运算、要写的目的寄存器等三个方面的信息。以下对当中几个典型指令的译码过程进行解释。
1、add指令的译码过程
add指令译码须要设置的三个方面内容例如以下。addu、sub、subu指令的译码过程能够參考add指令。
(1)要读取的寄存器情况:add指令须要读取rs、rt寄存器的值,所以设置reg1_read_o、reg2_read_o为1。默认通过Regfile模块读port1读取的寄存器地址reg1_addr_o的值是指令的21-25bit,正是add指令中的rs,默认通过Regfile模块读port2读取的寄存器地址reg2_addr_o的值是指令的16-20bit。正是add指令中的rt。所以终于译码阶段的输出reg1_o就是地址为rs的寄存器的值,reg2_o就是地址为rt的寄存器的值。
(2)要运行的运算:add指令是算术运算中的加法操作,所以此处将alusel_o赋值为EXE_RES_ARITHMETIC。aluop_o赋值为EXE_ADD_OP。
(3)要写入的目的寄存器:add指令须要将结果写入目的寄存器,所以设置wreg_o为WriteEnable。设置wd_o为要写入的目的寄存器地址,默认是指令字的11-15bit。正是add指令中的rd。
2、addi指令的译码过程
addi指令译码须要设置的三个方面内容例如以下。addiu、subi、subiu指令的译码过程能够參考addi指令。
(1)要读取的寄存器情况:addi指令仅仅须要读取rs寄存器的值。所以设置reg1_read_o为1、reg2_read_o为0。默认通过Regfile模块读port1读取的寄存器地址reg1_addr_o的值是指令的21-25bit,正是addi指令中的rs。
设置reg2_read_o为0,表示使用马上数作为參与运算的第二个操作数。imm就是指令中的马上数进行符号扩展后的值。
所以终于译码阶段的输出reg1_o就是地址为rs的寄存器的值,reg2_o就是imm的值。
(2)要运行的运算:addi指令是算术运算中的加法操作,所以此处将alusel_o赋值为EXE_RES_ARITHMETIC,aluop_o赋值为EXE_ADDI_OP。
(3)要写入的目的寄存器:addi指令须要将结果写入目的寄存器。所以设置wreg_o为WriteEnable,设置要写入的目的寄存器地址wd_o是指令中16-20bit的值,正是addi指令中的rt。
3、slt指令的译码过程
slt指令译码须要设置的三个方面内容例如以下,sltu指令的译码过程能够參考slt指令。
(1)要读取的寄存器情况:slt指令须要读取rs、rt寄存器的值,所以设置reg1_read_o、reg2_read_o为1。
默认通过Regfile模块读port1读取的寄存器地址reg1_addr_o的值是指令的21-25bit,正是slt指令中的rs。默认通过Regfile模块读port2读取的寄存器地址reg2_addr_o的值是指令的16-20bit,正是slt指令中的rt。所以终于译码阶段的输出reg1_o就是地址为rs的寄存器的值。reg2_o就是地址为rt的寄存器的值。
(2)要运行的运算:slt指令是算术运算中的比較操作,所以此处将alusel_o赋值为EXE_RES_ARITHMETIC,aluop_o赋值为EXE_SLT_OP。
(3)要写入的目的寄存器:slt指令须要将结果写入目的寄存器。所以设置wreg_o为WriteEnable,设置wd_o为要写入的目的寄存器地址,默认是指令11-15bit的值,正是slt指令中的rd。
4、slti指令的译码过程
slti指令译码须要设置的三个方面内容例如以下。sltiu指令的译码过程能够參考slti指令。
(1)要读取的寄存器情况:slti指令仅仅须要读取rs寄存器的值。所以设置reg1_read_o为1、reg2_read_o为0。默认通过Regfile模块读port1读取的寄存器地址reg1_addr_o的值是指令的21-25bit,正是slti指令中的rs。设置reg2_read_o为0,表示使用马上数作为运算的第二个操作数。imm就是指令中的马上数进行符号扩展后的值。所以终于译码阶段的输出reg1_o就是地址为rs的寄存器的值,reg2_o就是imm的值。
(2)要运行的运算:slti指令是算术运算中的比較操作,所以此处将alusel_o赋值为EXE_RES_ARITHMETIC。aluop_o赋值为EXE_SLT_OP。
(3)要写入的目的寄存器:slti指令须要将结果写入目的寄存器,所以设置wreg_o为WriteEnable,设置要写入的目的寄存器地址wd_o是指令中16-20bit的值,正是slti指令中的rt。
5、mult指令的译码过程
mult指令译码须要设置的三个方面内容例如以下,multu指令的译码过程能够參考mult指令。
(1)要读取的寄存器情况:mult指令须要读取rs、rt寄存器的值。所以设置reg1_read_o、reg2_read_o为1。默认通过Regfile模块读port1读取的寄存器地址reg1_addr_o的值是指令的21-25bit。正是mult指令中的rs。默认通过Regfile模块读port2读取的寄存器地址reg2_addr_o的值是指令的16-20bit,正是mult指令中的rt。所以终于译码阶段的输出reg1_o就是地址为rs的寄存器的值。reg2_o就是地址为rt的寄存器的值。
(2)要运行的运算:mult指令是乘法操作,而且乘法结果不须要写入通用寄存器。而是写入HI、LO寄存器,所以此处将alusel_o保持为默认值EXE_RES_NOP。aluop_o赋值为EXE_MULT_OP。
(3)要写入的目的寄存器:mult指令不须要写通用寄存器。所以设置wreg_o为WriteDisable。
6、mul指令的译码过程
mul指令译码须要设置的三个方面内容例如以下。
(1)要读取的寄存器情况:mul指令须要读取rs、rt寄存器的值,所以设置reg1_read_o、reg2_read_o为1。
默认通过Regfile模块读port1读取的寄存器地址reg1_addr_o的值是指令的21-25bit,正是mul指令中的rs,默认通过Regfile模块读port2读取的寄存器地址reg2_addr_o的值是指令的16-20bit,正是mul指令中的rt。
所以终于译码阶段的输出reg1_o就是地址为rs的寄存器的值。reg2_o就是地址为rt的寄存器的值。
(2)要运行的运算:mul指令是乘法操作,而且乘法结果是写入通用寄存器,所以此处将alusel_o赋值为EXE_RES_MUL。aluop_o赋值为EXE_MUL_OP。
(3)要写入的目的寄存器:mul指令须要将结果写入目的寄存器,所以设置wreg_o为WriteEnable,设置wd_o为要写入的目的寄存器地址。默认是指令字的11-15bit,正是mul指令中的rd。
7、clo指令的译码过程
clo指令译码须要设置的三个方面内容例如以下。clz指令的译码过程能够參考clo指令。
(1)要读取的寄存器情况:clo指令仅仅须要读取rs寄存器的值,所以设置reg1_read_o为1、reg2_read_o为0。默认通过Regfile模块读port1读取的寄存器地址reg1_addr_o的值是指令的21-25bit,正是clo指令中的rs。所以终于译码阶段的输出reg1_o就是地址为rs的寄存器的值。
(2)要运行的运算:clo指令是算术运算中的计数操作,所以此处将alusel_o赋值为EXE_RES_ARITHMETIC,aluop_o赋值为EXE_CLO_OP。
(3)要写入的目的寄存器:clo指令须要将结果写入目的寄存器。所以设置wreg_o为WriteEnable,设置wd_o为要写入的目的寄存器地址。默认是指令字的11-15bit,正是clo指令中的rd。
为了实现简单算术指令,今天改动了译码阶段,下一次将改动运行阶段,敬请关注。
自己动手写CPU之第七阶段(2)——简单算术操作指令实现过程的更多相关文章
- 自己动手写CPU之第八阶段(4)——转移指令实现过程2
将陆续上传本人写的新书<自己动手写CPU>,今天是第36篇,我尽量每周四篇 开展晒书评送书活动,在亚马逊.京东.当当三大图书站点上,发表<自己动手写CPU>书评的前十名读者,均 ...
- 自己动手写CPU之第七阶段(7)——乘累加指令的实现
将陆续上传本人写的新书<自己动手写CPU>.今天是第30篇.我尽量每周四篇 亚马逊的销售地址例如以下.欢迎大家围观呵! http://www.amazon.cn/dp/b00mqkrlg8 ...
- 自己动手写CPU之第四阶段(3)——MIPS编译环境的建立
将陆续上传本人写的新书<自己动手写CPU>(尚未出版).今天是第13篇.我尽量每周四篇 4.4 MIPS编译环境的建立 OpenMIPS处理器在设计的时候就计划与MIPS32指令集架构兼容 ...
- 自己动手写CPU之第九阶段(8)——MIPS32中的LL、SC指令说明
将陆续上传新书<自己动手写CPU>,今天是第47篇. 9.7 ll.sc指令实现思路 9.7.1 实现思路 这2条指令都涉及到訪问链接状态位LLbit,能够将LLbit当做寄存器处理,ll ...
- 自己动手写CPU之第五阶段(1)——流水线数据相关问题
将陆续上传本人写的新书<自己动手写CPU>(尚未出版),今天是第15篇,我尽量每周四篇 上一章建立了原始的OpenMIPS五级流水线结构,可是仅仅实现了一条ori指令,从本章開始,将逐步完 ...
- 自己动手写CPU之第五阶段(3)——MIPS指令集中的逻辑、移位与空指令
将陆续上传本人写的新书<自己动手写CPU>(尚未出版),今天是第17篇.我尽量每周四篇 5.4 逻辑.移位操作与空指令说明 MIPS32指令集架构中定义的逻辑操作指令有8条:and.and ...
- 自己动手写CPU之第六阶段(2)——移动操作指令实现思路
将陆续上传本人写的新书<自己动手写CPU>(尚未出版),今天是第21篇,我尽量每周四篇 6.2 移动操作指令实现思路 6.2.1 实现思路 这6条移动操作指令能够分为两类:一类是不涉及特殊 ...
- 自己动手写CPU 笔记
自己动手写CPU 跳转至: 导航. 搜索 文件夹 1 处理器与MIPS 2 可编程逻辑器件与Verilog HDL 3 教学版OpenMIPS处理器蓝图 4 第一条指令ori 5 逻辑.移位与nop ...
- 《自己动手写CPU》写书评获赠书活动结果
<自己动手写CPU>写书评获赠图书的读者有: 京东:8***2.16号哨兵.magicyu.kk6803.jddickyd.杰出的胡兵 亚马逊:徐贺.马先童.jaychen.farmfar ...
随机推荐
- Bitmap类
一.Bitmap类 Bitmap对象封装了GDI+中的一个位图,此位图由图形图像及其属性的像素数据组成.因此Bitmap是用于处理由像素数据定义的图像的对象.该类的主要方法和属性如下: 1. GetP ...
- Android与H5互调
前言 微信,微博,微商,QQ空间,大量的软件使用内嵌了H5,这个时候就需要了解Android如何更H5交互的了:有些外包公司,为了节约成本,采用Android内嵌H5模式开发,便于在IOS上直接复用页 ...
- Codeforces 746G(构造)
G. ...
- 网站防火墙探测工具Wafw00f
网站防火墙探测工具Wafw00f 现在网站为了加强自身安全,通常都会安装各类防火墙.这些防火墙往往会拦截各种扫描请求,使得测试人员无法正确判断网站相关信息.Kali Linux提供了一款网站防火墙探 ...
- php的session与免登陆问题
Session 与 Session的GC 由于PHP的工作机制,它并没有一个daemon线程来定期的扫描Session 信息并判断其是否失效,当一个有效的请求发生时,PHP 会根据全局变量 sessi ...
- Maven在[INFO] Generating project in Interactive mode卡住的问题解决
我的环境: Apache Maven 3.3.9 (bb52d8502b132ec0a5a3f4c09453c07478323dc5; 2015-11-11T00:41:47+08:00) Maven ...
- Difference between a Hard Link and Soft (Symbolic) Link
Within the Unix/Linux file system, linking lets you create file shortcuts to link one or more files. ...
- HDU1565方格取数
典型的状态压缩DP问题.第i行的取法只受到第i-1行的影响.首先每一行的取法要相容(不能有两个相邻),然后相邻行之间也要相容.将每一个格子看做两种状态,1表示取,0表示不取.这样每一行就是一个01串, ...
- 2016.6.21 将Eclipse中项目部署到tomcat下
新建的web项目,各种都配置好,选择run on server之后,发现运行失败,并不能访问需要的网址.而脱离eclipse,将生成的war文件直接放到tomcat的webapp下时,可以正常访问.所 ...
- 【SharePoint】SharePoint 2013 使用PreSaveAction自定义客户端验证
使用PreSaveAction函数实现客户端自定义验证. 例:[项目编号]为空时,必须填写[责任者]项.(其中[项目编号]为单行文本框,[责任者]为用户/组选择框.) function PreSave ...