将陆续上传本人写的新书《自己动手写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)——简单算术操作指令实现过程的更多相关文章

  1. 自己动手写CPU之第八阶段(4)——转移指令实现过程2

    将陆续上传本人写的新书<自己动手写CPU>,今天是第36篇,我尽量每周四篇 开展晒书评送书活动,在亚马逊.京东.当当三大图书站点上,发表<自己动手写CPU>书评的前十名读者,均 ...

  2. 自己动手写CPU之第七阶段(7)——乘累加指令的实现

    将陆续上传本人写的新书<自己动手写CPU>.今天是第30篇.我尽量每周四篇 亚马逊的销售地址例如以下.欢迎大家围观呵! http://www.amazon.cn/dp/b00mqkrlg8 ...

  3. 自己动手写CPU之第四阶段(3)——MIPS编译环境的建立

    将陆续上传本人写的新书<自己动手写CPU>(尚未出版).今天是第13篇.我尽量每周四篇 4.4 MIPS编译环境的建立 OpenMIPS处理器在设计的时候就计划与MIPS32指令集架构兼容 ...

  4. 自己动手写CPU之第九阶段(8)——MIPS32中的LL、SC指令说明

    将陆续上传新书<自己动手写CPU>,今天是第47篇. 9.7 ll.sc指令实现思路 9.7.1 实现思路 这2条指令都涉及到訪问链接状态位LLbit,能够将LLbit当做寄存器处理,ll ...

  5. 自己动手写CPU之第五阶段(1)——流水线数据相关问题

    将陆续上传本人写的新书<自己动手写CPU>(尚未出版),今天是第15篇,我尽量每周四篇 上一章建立了原始的OpenMIPS五级流水线结构,可是仅仅实现了一条ori指令,从本章開始,将逐步完 ...

  6. 自己动手写CPU之第五阶段(3)——MIPS指令集中的逻辑、移位与空指令

    将陆续上传本人写的新书<自己动手写CPU>(尚未出版),今天是第17篇.我尽量每周四篇 5.4 逻辑.移位操作与空指令说明 MIPS32指令集架构中定义的逻辑操作指令有8条:and.and ...

  7. 自己动手写CPU之第六阶段(2)——移动操作指令实现思路

    将陆续上传本人写的新书<自己动手写CPU>(尚未出版),今天是第21篇,我尽量每周四篇 6.2 移动操作指令实现思路 6.2.1 实现思路 这6条移动操作指令能够分为两类:一类是不涉及特殊 ...

  8. 自己动手写CPU 笔记

    自己动手写CPU 跳转至: 导航. 搜索 文件夹 1 处理器与MIPS 2 可编程逻辑器件与Verilog HDL 3 教学版OpenMIPS处理器蓝图 4 第一条指令ori 5 逻辑.移位与nop ...

  9. 《自己动手写CPU》写书评获赠书活动结果

    <自己动手写CPU>写书评获赠图书的读者有: 京东:8***2.16号哨兵.magicyu.kk6803.jddickyd.杰出的胡兵 亚马逊:徐贺.马先童.jaychen.farmfar ...

随机推荐

  1. 最简单方法远程调试Python多进程子程序

    Python 2.6新增的multiprocessing,即多进程,给子进程代码调试有点困难,比如python自带的pdb如果直接在子进程代码里面启动会抛出一堆异常,原因是子进程的stdin/out/ ...

  2. 移动GIS技术在城市信息采集中的应用

    1 引言 随着移动平板电脑和手机(以下简称移动终端)在软硬件上的更新换代,和3G.4G通讯网络的升级,传统测绘和和数据服务方式正在发生巨大变化.以城市中的外业踏勘和信息采集为例,移动终端正成为主要的外 ...

  3. LeetCode OJ-- Add Binary

    https://oj.leetcode.com/problems/add-binary/ 对两个二进制字符串求和. 对于字符串 ans_str,求它的翻转. reverse(ans_str.begin ...

  4. python--网络爬虫一

    http://hankjin.blog.163.com/blog/static/3373193720105140583594/ http://blog.csdn.net/wklken/article/ ...

  5. Codeforces Round #450 (Div. 2) B. Position in Fraction【数论/循环节/给定分子m 分母n和一个数c,找出c在m/n的循环节第几个位置出现,没出现过输出-1】

    B. Position in Fraction time limit per test 1 second memory limit per test 256 megabytes input stand ...

  6. SecureCRT发送键盘按键对应表(转义字符)

    \r 发送回车(CR) \n 发送换行符(LF) \b 发送退格 \e 发送一个转义 \t 发送一个标签 \\ 发送一个反斜杠字符 \v 将剪贴板的内容粘贴到活动状态会话窗口 \p 暂停一秒钟

  7. ios界面笔记(一)

    基于一个简单视图的view解析

  8. 【spring boot】10.spring boot下的单元测试

    spring boot下的单元测试,思前想后还是需要单独用一章篇幅来看看. 然后在看了介绍和使用时候,我感觉并不想多去看了. 但是还是给后来人留下参考的路径: 官网说明:https://spring. ...

  9. 开源 免费 java CMS - FreeCMS2.1 会员我的留言

    项目地址:http://www.freeteam.cn/ 我的留言 从左側管理菜单点击我的留言进入.在这里能够查看当前登录会员的全部留言记录. 查看留言 点击留言标题能够查看留言具体内容. 删除留言 ...

  10. Iowait的成因、对系统影响及对策

    什么是iowait?顾名思义,就是系统因为io导致的进程wait.再深一点讲就是:这时候系统在做io,导致没有进程在干活,cpu在执行idle进程空转,所以说iowait的产生要满足两个条件,一是进程 ...