写在最前
这本书讲的是如何用verilog,以riscv为指令集,设计一款CPU。也就是书中说的蜂鸟E200。之前没有看过类似的书,对CPU的工作流程也不熟悉。这本书以verilog为载体,介绍了CPU的基本原理,对于第一次接触CPU内部眼里的菜鸟来说,简直不要太神奇。而且本书开源代码,只要有一块fpga,你也能够自己做出一块CPU来。
第一章~第四章
这是本书的第一部分,主要是一些介绍。诸如RISCV之前的一些架构,以及RV指令集的特性。第三章介绍不同的RV版本,第四章介绍本书的E200的特性。
第五章 E200设计总览
讲了一些很有用的基础知识
- 架构指的是指令集架构,微架构是根据架构设计的硬件布局
- 处理器或者CPU往往是一个完整的SOC,和处理器核或者core是处理器的运算核心。
E200的设计哲学
- 模块化和可重用性
- 面积最小化
- 结构简单化
- 性能不追求极端,够用即可
E200的代码风格
- 使用标准DFF模块例化生成寄存器
- 使用assign语句代替ifelse和case
- 代码即注释
- 禁止使用CLOCK和RESET
第六章 流水线
五级流水线:取指,译码,执行,访存,写回
流水线也不是必须的,有的处理器用的是状态机。并且流水线的深度不同的处理器也有不同的设置。
流水线的冲突
- 数据冲突
这是三种数据依赖性,其中WAW,WAR可以通过寄存器重命名的方式去除依赖,而RAW是真数据相关,就是它必须要读已经写了的这个数据。如果发生这种情况,就要等待写完才可以。有一些解决方法, 比如找个东西记录这种相关性。
E200的流水线
- IFU取指
- EXU用来译码和执行
- LSU用来访存
- WB用来写回
第七章 取指
概述
- 对于非分支跳转指令,就连续不断地进行取指即可,就算是不是对齐的32位指令,最好也能够每个周期都能够读一条指令
- 对于分支跳转指令,能够快速判断是否需要跳转。如果需要跳转,就从新的PC取出指令。
- 从ITCM或者ICACHE中取指令,E200用的是ITCM,很快。
- 非对齐的指令,对于顺序执行的,只需要缓存下来,等下次取指拼接到一起就可以了,不耽误时间。但是对于跳转的那种,就用多bank,并行一次取俩,也可以在一个周期内完成。
分支
- 无条件直接跳转,比如jal x5,offset。这种,立即数就能跳
- 无条件简洁跳转,不是立即数了,需要从寄存器读跳转的地址
- 带条件直接跳
- 带条件间接跳,这个RV里没有
为了提升性能,就要进行分支预测。首先要预测方向,也就是到底跳不跳,还有就是预测地址。
预测方向就有各种方法,比如静态预测和动态预测。
预测地址是除了直接跳转,间接跳转是需要读寄存器的,很耗费时间。就用比如保存之前的分支语句,如果匹配,就直接跳到那个地址之类的方法。
RV对于取指的简化
- 规整的编码指令格式
- 指令长度指示码放于低位
- 简单的分支跳转指令
- 没有分支延迟槽指令。分支延迟槽是在分支后面放一些不受分支影响的指令,默认现在的分支预测精度已经很高,为了减少硬件成本。
- 提供明确的静态分支预测依据
- 提供明确的RAS依据,这个是预测跳转地址的一个方法
IFU的实现
- 首先从ITCM取指,然后放到IR和PC里,IR是指令寄存器。同时用minidecode进行初步地译码来判断当前指令是普通指令还是分支跳转,然后生成用BPU来做分支预测,生成下一个PC
- 如果取指令的地址不在ITCM里,就会通过BIU访问外部存储。
第八章 执行
- 根据IR中的指令,译码和派遣
- 读寄存器,RD-Regfile
- 维护数据的相关性,OITF
- 给各种运算单元执行,ALU,长指令,LSU,EAI等
- 交付指令
- 写回寄存器,WB-Regfile
- 系统中有一些特殊的寄存器,叫CSR寄存器,为了存储系统的一些状态。
- 实际的派遣是ALU进行的
流水线冲突,长指令和OITF
- 资源冲突:就是运算单元的冲突,就等待
- 数据冲突:正在派遣的指令和尚未执行完成的长指令存在RAW和WAW依赖。
为了检测出这种数据依赖,E200实现了一个OITF模块。其中存储的是已经派遣但是还未写回的长指令信息。然后每次在进行指令派遣的时候,就把本指令的操作数和长指令的向比较,如果有相同的,就说明有相关性,就等待。
ALU+浮点单元
做各种计算
第九章 交付
我理解的交付就是这条指令能够执行,而不是执行完成。
首先ALU会计算是否需要跳转,计算出来之后就发给交付模块。如果交付模块发现结果和预测结果一样,就不会冲刷流水线,否则就冲刷流水线。
第十章 写回
两个仲裁
- 最终写回仲裁:长指令比单指令有更高优先级。如果没有长指令写回,单指令可以比更早位置的长指令写回。
- 长指令写回仲裁:根据OITF判断长指令的先后关系,严格控制长指令的写回顺序
第十一章 存储器架构
AGU address generation unit
是ALU的一部分,用于产生访存地址。
LSU ITCM DTCM
A字扩展指令
这里是用于多核操作的原子指令,包括互斥操作等的实现。
第十二章 BIU Bus Interface Unit
E200提出了自己的总线协议ICB
实现了一从多主和多主一从以及多主多从的总线连接方式。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-spFHBnCB-1591688314612)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200609151117973.png)]
第十三章 中断和异常
广义上的异常包含了狭义的中断和异常。异常主要包括
- 同步异常:由于执行程序指令或者试图执行程序指令而造成的异常。这个原因能够被精确定位到某一个指令,而且无论运行多少次,都能够被精确地复现
- 异步异常:最常见的异步异常就是外部中断,称之为精确异步异常。还有非精确异步异常。
异常处理机制
- 停止执行当前指令,转而从CSR寄存器mtvec定义的PC地址开始执行
- 更新其他几个寄存器:异常原因,异常PC,异常值,状态
- 退出异常
- 从mepc定义的pc开始执行
- 更新CSR寄存器mstatus
RV架构中断定义
- 外部中断:来自处理器核外部的中断,还有一个中断控制器PLIC,用来仲裁外部中断
- 计时器中断:mtime,mtimecmp
- 软件中断:软件自己往msip寄存器里写1触发中断
- 调试中断
一般外部中断优先级最高,软件中断次之,计时器中断再次。
其他章
第十四章是讲如何调试,十五章讲低功耗的各方面优化,十六章讲RV能够进行协处理器扩展。第三部分主要讲如何在实际平台上实现E200。附录讲了RV的指令集等其他RV基础知识。在此不多赘述。