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基础整数指令集,它有六种基本指令格式,分别是:

  1. 用于寄存器-寄存器操作的 R 类型指令;
  2. 用于短立即数和访存 load 操作的 I 型指令;
  3. 用于访存 store 操作的 S 型指令;
  4. 用于条件跳转操作的 B 类型指令;
  5. 用于长立即数的 U 型指令;
  6. 用于无条件跳转的 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内核注解——译码 代码讲解相关推荐

  1. 十、RISC-V SoC外设——timer定时器 代码讲解

    上一篇博文中注释了SPI外设模块,现在来介绍timer定时器模块. 另外,在最后一个章节中会上传额外添加详细注释的工程代码,完全开源,如有需要可自行下载. 目录 0 RISC-V SoC注解系列文章目 ...

  2. 五、RISC-V SoC内核——中断 代码讲解

    tinyriscv这个SoC工程的内核cpu部分,采用经典的三级流水线结构进行设计,即大家所熟知的:取值->译码->执行三级流水线. 另外,在最后一个章节中会上传额外添加详细注释的工程代码 ...

  3. 一、RISC-V SoC内核——取指 代码讲解

    在开篇中我们对RISC-V及其SoC软核工程进行了简单介绍,现在来介绍取指模块: tinyriscv这个SoC工程的内核cpu部分,采用经典的三级流水线结构进行设计,即大家所熟知的:取值->译码 ...

  4. 七、RISC-V SoC内核——总线 代码讲解

    上一篇博文中注释了通用寄存器reg.v模块,现在来介绍总线模块rib.v: 另外,在最后一个章节中会上传额外添加详细注释的工程代码,完全开源,如有需要可自行下载. (这个RIB总线协议为工程原作者自定 ...

  5. linux内核中链表代码分析---list.h头文件分析(二)【转】

    转自:http://blog.chinaunix.net/uid-30254565-id-5637598.html linux内核中链表代码分析---list.h头文件分析(二) 16年2月28日16 ...

  6. tx2 fpga pcie无法读写_Cyclone V SOC(ARM+FPGA)开发文档_之开发流程详解

    双击可查看大图(手动狗头) 目录 Altera Cyclone V soc开发文档 之软硬件开发 1 Cyclone V开发流程介绍 5 专业术语 5 Cyclone V软件开发介绍 6 U-BOOT ...

  7. ubuntu arm qt_Cyclone V SOC(ARM+FPGA)开发文档_之开发流程详解

    双击可查看大图(手动狗头) 目录 Altera Cyclone V soc开发文档 之软硬件开发 1 Cyclone V开发流程介绍 5 专业术语 5 Cyclone V软件开发介绍 6 U-BOOT ...

  8. Cyclone V SoC FPGA学习之路第一章:综述

    Cyclone V SoC FPGA学习之路第一章:总体了解 关键词: adaptive logic modules – ALM 自适应逻辑模块 logic array block --LAB 逻辑阵 ...

  9. Cyclone V SoC FPGA学习之路第二章:硬件篇

    Cyclone V SoC FPGA学习之路第二章:硬件篇(内部资源) 前言 上一章了解了<cycloneV device datasheet>,其中数据手册里重点介绍了电源要求,时序参数 ...

最新文章

  1. FAQ - DucleBox | A Game Engine for OpenGL Programming
  2. leetcode算法题--掷骰子模拟★★
  3. Day 17: 使用 JBoss Forge 和 OpenShift 构建部署 JAVA EE 6 应用
  4. git的简单操作命令
  5. 最大化平均值 (二分搜索法)
  6. 苹果计算机咋出记录,怎么查看Mac电脑的开机记录?
  7. esxi服务器3d性能,ESXi主机性能问题(示例代码)
  8. Ajax请求数据与删除数据后刷新页面
  9. linux有k歌软件吗,在Linux下可用Wine安装和运行暴风影音16、全民K歌
  10. 【论文复现】Hierarchical Attention Networks for Document Classification
  11. List中对象model的排序问题
  12. 虚拟机中的linux系统联网,虚拟机上Linux系统上网设置
  13. mysql 判断当前星期_MySQL数据库如何获取一个日期所对应的星期数呢?
  14. 《一个操作系统的实现》 ubuntu系统环境配置
  15. Sipeed M1W内部esp8285固件烧录教程
  16. 基于PID控制的车辆LKA算法
  17. python爬虫之一:爬取网页小说(魂破九天)
  18. css类命名_标题CSS:CSS类命名的简单方法
  19. 连接 蓝牙HC - 05 模块 读写操作
  20. html仿微信评论输入框,简单仿微信朋友圈评论功能

热门文章

  1. pandas库读取多个excel文件数据并进行筛选合并处理后导入到新表格中
  2. 坦克大战 —— 韩顺平
  3. Android程序员想进大厂?算法很重要(1),面经解析
  4. vue中使用Luckysheet实现Excel的导入、在线编辑、导出等功能
  5. OpenCV实战(2)——OpenCV核心数据结构
  6. 无法启动计算机打印机服务程序,安装驱动程序时电脑弹出错误窗口“无法启动Windows打印后台程序服务” (适用于Windows OS)...
  7. 涉密计算机与涉密网络管理制度,长沙理工大学网络涉密保密管理制度
  8. 20.JavaScript6
  9. MapReduce 的核心知识点,你都 get 到了吗 ?(干货文章,建议收藏!)
  10. 迷宫问题寻找最短路径(BFS)