二、RISC-V SoC内核注解——译码 代码讲解
tinyriscv这个SoC工程的内核cpu部分,采用经典的三级流水线结构进行设计,即大家所熟知的:取值—>译码—>执行三级流水线。
另外,在最后一个章节中会上传额外添加详细注释的工程代码,完全开源,如有需要可自行下载。
上一篇博文中注释了取值模块,现在来介绍译码模块:
目录
0 RISC-V SoC注解系列文章目录
1. 译码模块的整体介绍
2. RISCV指令RV32I、RV32M介绍
3. 译码模块的注解
3.1 id.v(组合逻辑电路)
3.2 id_ex.v(时序逻辑电路)
0 RISC-V SoC注解系列文章目录
零、RISC-V SoC软核笔记详解——前言
一、RISC-V SoC内核注解——取指
二、RISC-V SoC内核注解——译码
三、RISC-V SoC内核注解——执行
四、RISC-V SoC内核注解——除法(试商法)
五、RISC-V SoC内核注解——中断
六、RISC-V SoC内核注解——通用寄存器
七、RISC-V SoC内核注解——总线
八、RISC-V SoC外设注解——GPIO
九、RISC-V SoC外设注解——SPI接口
十、RISC-V SoC外设注解——timer定时器
十一、RISC-V SoC外设注解——UART模块(终篇)
1. 译码模块的整体介绍
RISC-V内核的译码部分:涉及到id.v、id_ex.v、ctrl.v、clint.v、csr_reg.v等模块,其中clint.v、csr_reg.v两个模块是关于中断处理的模块,在中断章节会详细注解。ctrl.v模块是指令跳转和流水线暂停的控制信号,在后续的章节中会单独介绍。
译码部分详细结构图:
2. RISCV指令RV32I、RV32M介绍
这个RISCV软核,实现了RISCV基础指令集RV32I和扩展指令集RV32M(乘除法拓展指令)。关于这两个指令,在下文会一一标注出来。那具体是怎么实现指令的解析的呢?我们需要对照《RISC-V指令集手册》来进行注解。
《RISC-V指令集手册》的中文翻译版放在下边链接中了,需要的小伙伴可自行下载:
提取码:63bz
《RISC-V指令集手册》https://pan.baidu.com/s/1086s0N-BdVxUoZfYF5byRA首先对RV32I指令集进行简单的介绍,如果想了解更详细的内容请查看上述链接中的RISC-V指令集的中文参考手册《RISC-V-Reader-Chinese-v2p1》,第23页,第二章“RV32I:RISC-V基础整数指令集”:
RV32I是RISC-V基础整数指令集,它有六种基本指令格式,分别是:
- 用于寄存器-寄存器操作的 R 类型指令;
- 用于短立即数和访存 load 操作的 I 型指令;
- 用于访存 store 操作的 S 型指令;
- 用于条件跳转操作的 B 类型指令;
- 用于长立即数的 U 型指令;
- 用于无条件跳转的 J 型指令。
这六种指令的基本格式如下:
RV32I所有指令的具体的指令布局,操作码,格式类型和名称的操作码映射如下图所示:
这个RISC-V SoC工程完全实现了RV32I指令,因此上述表中的所有指令都会在译码模块中找到相应的代码。下文中会根据代码一一对应上述的指令。
接下来对扩展指令集RV32M(乘除法拓展指令)进行简单的介绍(详细介绍在中文参考手册《RISC-V-Reader-Chinese-v2p1》第51页)。
扩展指令集RV32M是32位整数的乘除法拓展指令:
乘法(指令的详细格式在中文参考手册152页):
1.mul指令将操作数寄存器rsl与rs2中的32位整数相乘,其64位结果的低32位写回寄存器rd中。两个32位整数操作数相乘的结果等于64位,而两个32位操作数当作有符号数相乘所得的低32位和当作无符号数相乘所得的低32位是相同的,因此RISC-V架构仅定义了一条mul指令作为取低32位结果的乘法指令。
2.mulh指令将操作数寄存器rsl与rs2中的32位整数当作有符号数相乘,结果的高32位写回寄存器rd中。
3.mulhu指令将操作数寄存器rsl与rs2中的32位整数当作无符号数相乘,结果的高32位写回寄存器rd中。
4.mulhsu指令将操作数寄存器rsl与rs2中的32位整数相乘,其中rsl当作有符号数和rs2当作无符号数,将结果的高32位写回寄存器rd中。
3. 译码模块的注解
3.1 id.v(组合逻辑电路)
主要功能为:1.根据指令内容,解析出当前具体是哪一条指令(比如add指令);2.根据具体的指令,确定当前指令涉及的寄存器。比如读寄存器是一个还是两个,是否需要写寄存器以及写哪一个寄存器;3.访存:访问通用寄存器,得到要读的寄存器的值(地址)[1]。
输入信号:
// from if_idinput wire[`InstBus] inst_i, // 指令内容 32位input wire[`InstAddrBus] inst_addr_i, // 指令地址 32位// from regsinput wire[`RegBus] reg1_rdata_i, // 通用寄存器1输入数据input wire[`RegBus] reg2_rdata_i, // 通用寄存器2输入数据// from csr reginput wire[`RegBus] csr_rdata_i, // CSR寄存器输入数据// from exinput wire ex_jump_flag_i, // 跳转标志//----------------------------以上输入----------以下输出---------------------------------
输出信号:// to regsoutput reg[`RegAddrBus ] reg1_raddr_o, // 读通用寄存器1地址output reg[`RegAddrBus ] reg2_raddr_o, // 读通用寄存器2地址// to csroutput reg[`MemAddrBus ] csr_raddr_o , // reg读CSR寄存器地址// to exoutput reg[`MemAddrBus ] op1_o , //从指令中解析出来的操作数1 output reg[`MemAddrBus ] op2_o , //从指令中解析出来的操作数2output reg[`MemAddrBus ] op1_jump_o , //从指令中解析出来的跳转地址1output reg[`MemAddrBus ] op2_jump_o , //从指令中解析出来的跳转地址2output reg[`InstBus ] inst_o, // 指令内容 与输入时内容相同output reg[`InstAddrBus] inst_addr_o , // 指令地址 与输入时内容相同output reg[`RegBus ] reg1_rdata_o, // 通用寄存器1数据 与输入时内容相同output reg[`RegBus ] reg2_rdata_o, // 通用寄存器2数据 与输入时内容相同output reg reg_we_o, // 写通用寄存器标志 output reg[`RegAddrBus ] reg_waddr_o, // 写通用寄存器地址 output reg csr_we_o, // 写CSR寄存器标志 output reg[`RegBus ] csr_rdata_o, // CSR寄存器数据 与输入时内容相同output reg[`MemAddrBus ] csr_waddr_o // 写CSR寄存器地址
首先将32位的指令码解析为6个部分,如下所示:
//将一条32位的指令分为6个部分,顺序如下
//funct7、rs2、rs1、funct3、rd、opcodewire[6:0] funct7 = inst_i[31:25]; //功能2,由funct7和funct3共同确定一条具体的指令wire[4:0] rs2 = inst_i[24:20]; //源寄存器2、立即数wire[4:0] rs1 = inst_i[19:15]; //源寄存器1、立即数wire[2:0] funct3 = inst_i[14:12]; //功能1,由funct7和funct3共同确定一条具体的指令wire[4:0] rd = inst_i[11:7 ]; //目标寄存器、立即数wire[6:0] opcode = inst_i[6 :0 ]; //操作码,指出该指令需要完成操作的类型或性质;
接下来是组合逻辑实现译码操作,我们截取其中一部分内容进行注解,其余部分类似。
case (opcode)//先判断操作码 `INST_TYPE_I: begin //短立即数和访存load操作 立即数类型 I type case (funct3) //当多个条件选项下需要执行相同的语句时,多个条件选项可以用逗号分开,放在同一个语句块的候选项中。 `INST_ADDI, `INST_SLTI, `INST_SLTIU, `INST_XORI, `INST_ORI, `INST_ANDI, `INST_SLLI, `INST_SRI: begin//寄存器的值和立即数的值进行各种逻辑运算 reg_we_o = `WriteEnable; // 写通用寄存器标志 reg_waddr_o = rd; //目标寄存器(写通用寄存器地址) reg1_raddr_o = rs1; //源寄存器1的地址,去通用寄存器模块中取reg1_rdata_i数据。 reg2_raddr_o = `ZeroReg; op1_o = reg1_rdata_i; //rs1地址从reg中取回的数据。 op2_o = {{20{inst_i[31]}}, inst_i[31:20]}; //指令中的立即数 end default: begin reg_we_o = `WriteDisable; reg_waddr_o = `ZeroReg; reg1_raddr_o = `ZeroReg; reg2_raddr_o = `ZeroReg; end endcase
end
代码解析如下:
由define.v文件可以查找到,宏定义INST_TYPE_I(opcode)的值是7'b0010011,INST_ADDI(func3)的值是3'b000,如下代码所示:
// I type inst
`define INST_TYPE_I 7'b0010011
`define INST_ADDI 3'b000 //立即数+寄存器
`define INST_SLTI 3'b010 //寄存器<立即数->则为1
`define INST_SLTIU 3'b011 //寄存器比较立即数,比较时视为无符号数,如果小则写入1
`define INST_XORI 3'b100 //寄存器与立即数按位异或
`define INST_ORI 3'b110 //立即数|寄存器
`define INST_ANDI 3'b111 //立即数&寄存器
`define INST_SLLI 3'b001 //寄存器<<立即数
`define INST_SRI 3'b101 //寄存器>>立即数
而操作码opcode,对应指令码的低7位[6:0],funct3对应指令码的[14:12]位:
wire[2:0] funct3 = inst_i[14:12]; //功能1
wire[6:0] opcode = inst_i[6 :0 ]; //操作码
即,inst_i[6 :0 ] = 7'b0010011,inst_i[14:12] = 3'b000,对应查找上文图2.3,可以找到唯一对应的指令如下所示:
其余指令虽然格式可能会有多不同,按相同的方法都能找到相对应的指令描述。
3.2 id_ex.v(时序逻辑电路)
主要功能:译码模块(id.v)的输出会送到id_ex模块的输入端,id_ex模块是一个时序电路,作用是将输入的信号打一拍后再输出到执行模块(ex.v)。通过例化gen_pipe_dff模块,如果该模块没有接收到复位或者暂停流水线信号hold_flag_in(来自Ctrl模块),则将输入的信号打一拍,输出至下一级。
输入信号:来自id模块
输出信号:输出到ex模块
input wire clk,input wire rst,input wire[`InstBus] inst_i, // 指令内容input wire[`InstAddrBus] inst_addr_i, // 指令地址input wire reg_we_i, // 写通用寄存器标志input wire[`RegAddrBus] reg_waddr_i, // 写通用寄存器地址input wire[`RegBus] reg1_rdata_i, // 通用寄存器1读数据input wire[`RegBus] reg2_rdata_i, // 通用寄存器2读数据input wire csr_we_i, // 写CSR寄存器标志input wire[`MemAddrBus] csr_waddr_i, // 写CSR寄存器地址input wire[`RegBus] csr_rdata_i, // CSR寄存器读数据input wire[`MemAddrBus] op1_i,input wire[`MemAddrBus] op2_i,input wire[`MemAddrBus] op1_jump_i,input wire[`MemAddrBus] op2_jump_i,input wire[`Hold_Flag_Bus] hold_flag_i, // 流水线暂停标志output wire[`MemAddrBus] op1_o,output wire[`MemAddrBus] op2_o,output wire[`MemAddrBus] op1_jump_o,output wire[`MemAddrBus] op2_jump_o,output wire[`InstBus] inst_o, // 指令内容output wire[`InstAddrBus] inst_addr_o, // 指令地址output wire reg_we_o, // 写通用寄存器标志output wire[`RegAddrBus] reg_waddr_o, // 写通用寄存器地址output wire[`RegBus] reg1_rdata_o, // 通用寄存器1读数据output wire[`RegBus] reg2_rdata_o, // 通用寄存器2读数据output wire csr_we_o, // 写CSR寄存器标志output wire[`MemAddrBus] csr_waddr_o, // 写CSR寄存器地址output wire[`RegBus] csr_rdata_o // CSR寄存器读数据
二、RISC-V SoC内核注解——译码 代码讲解相关推荐
- 十、RISC-V SoC外设——timer定时器 代码讲解
上一篇博文中注释了SPI外设模块,现在来介绍timer定时器模块. 另外,在最后一个章节中会上传额外添加详细注释的工程代码,完全开源,如有需要可自行下载. 目录 0 RISC-V SoC注解系列文章目 ...
- 五、RISC-V SoC内核——中断 代码讲解
tinyriscv这个SoC工程的内核cpu部分,采用经典的三级流水线结构进行设计,即大家所熟知的:取值->译码->执行三级流水线. 另外,在最后一个章节中会上传额外添加详细注释的工程代码 ...
- 一、RISC-V SoC内核——取指 代码讲解
在开篇中我们对RISC-V及其SoC软核工程进行了简单介绍,现在来介绍取指模块: tinyriscv这个SoC工程的内核cpu部分,采用经典的三级流水线结构进行设计,即大家所熟知的:取值->译码 ...
- 七、RISC-V SoC内核——总线 代码讲解
上一篇博文中注释了通用寄存器reg.v模块,现在来介绍总线模块rib.v: 另外,在最后一个章节中会上传额外添加详细注释的工程代码,完全开源,如有需要可自行下载. (这个RIB总线协议为工程原作者自定 ...
- linux内核中链表代码分析---list.h头文件分析(二)【转】
转自:http://blog.chinaunix.net/uid-30254565-id-5637598.html linux内核中链表代码分析---list.h头文件分析(二) 16年2月28日16 ...
- tx2 fpga pcie无法读写_Cyclone V SOC(ARM+FPGA)开发文档_之开发流程详解
双击可查看大图(手动狗头) 目录 Altera Cyclone V soc开发文档 之软硬件开发 1 Cyclone V开发流程介绍 5 专业术语 5 Cyclone V软件开发介绍 6 U-BOOT ...
- ubuntu arm qt_Cyclone V SOC(ARM+FPGA)开发文档_之开发流程详解
双击可查看大图(手动狗头) 目录 Altera Cyclone V soc开发文档 之软硬件开发 1 Cyclone V开发流程介绍 5 专业术语 5 Cyclone V软件开发介绍 6 U-BOOT ...
- Cyclone V SoC FPGA学习之路第一章:综述
Cyclone V SoC FPGA学习之路第一章:总体了解 关键词: adaptive logic modules – ALM 自适应逻辑模块 logic array block --LAB 逻辑阵 ...
- Cyclone V SoC FPGA学习之路第二章:硬件篇
Cyclone V SoC FPGA学习之路第二章:硬件篇(内部资源) 前言 上一章了解了<cycloneV device datasheet>,其中数据手册里重点介绍了电源要求,时序参数 ...
最新文章
- FAQ - DucleBox | A Game Engine for OpenGL Programming
- leetcode算法题--掷骰子模拟★★
- Day 17: 使用 JBoss Forge 和 OpenShift 构建部署 JAVA EE 6 应用
- git的简单操作命令
- 最大化平均值 (二分搜索法)
- 苹果计算机咋出记录,怎么查看Mac电脑的开机记录?
- esxi服务器3d性能,ESXi主机性能问题(示例代码)
- Ajax请求数据与删除数据后刷新页面
- linux有k歌软件吗,在Linux下可用Wine安装和运行暴风影音16、全民K歌
- 【论文复现】Hierarchical Attention Networks for Document Classification
- List中对象model的排序问题
- 虚拟机中的linux系统联网,虚拟机上Linux系统上网设置
- mysql 判断当前星期_MySQL数据库如何获取一个日期所对应的星期数呢?
- 《一个操作系统的实现》 ubuntu系统环境配置
- Sipeed M1W内部esp8285固件烧录教程
- 基于PID控制的车辆LKA算法
- python爬虫之一:爬取网页小说(魂破九天)
- css类命名_标题CSS:CSS类命名的简单方法
- 连接 蓝牙HC - 05 模块 读写操作
- html仿微信评论输入框,简单仿微信朋友圈评论功能
热门文章
- pandas库读取多个excel文件数据并进行筛选合并处理后导入到新表格中
- 坦克大战 —— 韩顺平
- Android程序员想进大厂?算法很重要(1),面经解析
- vue中使用Luckysheet实现Excel的导入、在线编辑、导出等功能
- OpenCV实战(2)——OpenCV核心数据结构
- 无法启动计算机打印机服务程序,安装驱动程序时电脑弹出错误窗口“无法启动Windows打印后台程序服务” (适用于Windows OS)...
- 涉密计算机与涉密网络管理制度,长沙理工大学网络涉密保密管理制度
- 20.JavaScript6
- MapReduce 的核心知识点,你都 get 到了吗 ?(干货文章,建议收藏!)
- 迷宫问题寻找最短路径(BFS)