来源:liangkangnan的博客
更新于 2021-01-31
tinyriscv 一个从零开始写的极简易懂的RISC-V处理器核
从零开始写RISC-V处理器之一 前言
从零开始写RISC-V处理器之二 绪论
从零开始写RISC-V处理器之三 硬件篇
从零开始写RISC-V处理器之四 软件篇
从零开始写RISC-V处理器之五 实践篇
从零开始写RISC-V处理器之六 写在最后
前言
第一次听到RISC-V这个词大概是两年前,当时觉得它也就是和MIPS这些CPU架构没什么区别,因此也就不以为然了。直到去年,RISC-V这个词开始频繁地出现在微信和其他网站上,此时我再也不能无动于衷了,于是开始在网上搜索有关它的资料,开始知道有SiFive这个网站,知道SiFive出了好几款RISC-V的开发板。可是最便宜的那一块开发板都要700多RMB,最后还是忍痛出手了一块。由于平时上班比较忙,所以玩这块板子的时间并不多,也就是晚上下班后和周末玩玩,自己照着芯片手册写了几个例程在板子上跑跑而已。
再后来发现网上已经有如何设计RISC-V处理器的书籍卖了,并且这个处理器是开源的,于是果断买了一本来阅读并浏览了它的开源代码,最后表示看不懂。从那之后一个“从零开始写RISC-V处理器”的想法开始不断地出现在我的脑海里。我心里是很想学习、深入研究RISC-V的,但是一直以来都没有verilog和FPGA的基础,可以说是CPU设计领域里的门外汉,再加上很少业余时间,为此一度犹豫不决。但是直觉告诉我已近不能再等了,我决定开始自学verilog和FPGA,用简单易懂的方式写一个RISC-V处理器并且把它开源出来,在提高自身的同时希望能帮助到那些想入门RISC-V的同学,于是tinyriscv终于在2019年12月诞生了。
tinyriscv是一个采用三级流水线设计,顺序、单发射、单核的32位RISC-V处理器,全部代码都是采用verilog HDL语言编写,核心设计思想是简单、易懂。
绪论
RISC-V是什么
RISC,即精简指令集处理器,是相对于X86这种CISC(复杂指令集处理器)来说的。RISC-V中的V是罗马数字,也即阿拉伯数字中的5,就是指第5代RISC。
RISC-V是一种指令集架构,和ARM、MIPS这些是属于同一类东西。RISC-V诞生于2010年,最大的特点是开源,任何人都可以设计RISC-V架构的处理器并且不会有任何版权问题。
既生ARM,何生RISC-V
ARM是一种很优秀的处理器,这一点是无可否认的,在RISC处理器中是处于绝对老大的地位。但是ARM是闭源的,要设计基于ARM的处理器是要交版权费的,或者说要购买ARM的授权,而且这授权费用是昂贵的。
RISC-V的诞生并不是偶然的,而是必然的,为什么?且由我从以下两大领域进行说明。
先看开源软件领域(或者说是操作系统领域),Windows是闭源的,Linux是开源的,Linux有多成功、对开源软件有多重要的意义,这个不用多说了吧。再看手机操作系统领域,iOS是闭源的,Android是开源的,Android有多成功,这个也不用多说了吧。对于RISC处理器领域,由于有了ARM的闭源,必然就会有另外一种开源的RISC处理器。RISC-V之于CPU的意义,就好比Linux之于开源软件的意义。
或者你会说现在也有好多开源的处理器架构啊,比如MIPS等等,为什么偏偏是RISC-V?这个在这里我就不细说了,我只想说一句:大部分人能看到的机遇不会是一个好的机遇,你懂的。
可以说未来十年乃至更长时间内不会有比RISC-V更优秀的开源处理器架构出现。错过RISC-V,你注定要错过一个时代。
浅谈Verilog
verilog,确切来说应该是verilog HDL(Hardware Description Language ),从它的名字就可以知道这是一种硬件描述语言。首先它是一种语言,和C语言、C++语言一样是一种编程语言,那么verilog描述的是什么硬件呢?描述电阻?描述电容?描述运算放大器?都不是,它描述的是数字电路里的硬件,比如与、非门、触发器、锁存器等等。
既然是编程语言,那一定会有它的语法,学过C语言的同学再来看verilog得代码,会发现有很多地方是相似的。
verilog的语法并不难,难的是什么时候该用wire类型,什么时候该用reg类型,什么时候该用assign来描述电路,什么时候该用always来描述电路。assign能描述组合逻辑电路,always也能描述组合逻辑电路,两者有什么区别呢?
用always描述组合逻辑电路
我们知道数字电路里有两大类型的电路,一种是组合逻辑电路,另外一种是时序逻辑电路。组合逻辑电路不需要时钟作为触发条件,因此输入会立即(不考虑延时)反映到输出。时序逻辑电路以时钟作为触发条件,时钟的上升沿到来时输入才会反映到输出。
在verilog中,assign能描述组合逻辑电路,always也能描述组合逻辑电路。对于简单的组合逻辑电路的话两者描述起来都比较好懂、容易理解,但是一旦到了复杂的组合逻辑电路,如果用assign描述的话要么是一大串要么是要用好多个assign,不容易弄明白。但是用always描述起来却是非常容易理解的。
既然这样,那全部组合逻辑电路都用always来描述好了,呵呵,既然assign存在就有它的合理性。
用always描述组合逻辑电路时要注意避免产生锁存器,if和case的分支情况要写全。
在tinyriscv中用了大量的always来描述组合逻辑电路,特别是在译码和执行阶段。
数字电路设计中的时序问题
要分析数字电路中的时序问题,就一定要提到以下这个模型。
其中对时序影响最大的是上图中的组合逻辑电路。所以要避免时序问题,最简单的方法减小组合逻辑电路的延时。组合逻辑电路里的串联级数越多延时就越大,实在没办法减小串联级数时,可以采用流水线的方式将这些级数用触发器隔开。
流水线设计
要设计处理器的话,流水线是绕不开的。当然你也可以抬杠说:”用状态机也可以实现处理器啊,不一定要用流水线。”
采用流水线设计方式,不但可以提高处理器的工作频率,还可以提高处理器的效率。但是流水线并不是越长越好,流水线越长要使用的资源就越多、面积就越大。
在设计一款处理器之前,首先要确定好所设计的处理器要达到什么样的性能(或者说主频最高是多少),所使用的资源的上限是多少,功耗范围是多少。如果一味地追求性能而不考虑资源和功耗的话,那么所设计出来的处理器估计就只能用来玩玩,或者做做学术研究。
tinyriscv采用的是三级流水线,即取指、译码和执行,设计的目标就是要对标ARM的Cortex-M3系列处理器。
代码风格
代码风格其实并没有一种标准,但是并不代表代码风格不重要。好的代码风格可以让别人看你的代码时有一种赏心悦目的感觉。哪怕代码只是写给自己看,也一定要养成好的代码风格的习惯。tinyriscv的代码风格在很大程度上沿用了写C语言代码所采用的风格。
下面介绍tinyriscv的一些主要的代码风格。
缩进
统一使用4个空格。
if语句
不管if语句下面有多少行语句,if下面的语句都由begin…end包起来,并且begin在if的最后,如下所示:
if (a == 1'b1) begin
c <= b;
end else begin
c <= d;
end
case语句
对于每一个分支情况,不管有多少行语句,都由begin…end包起来,如下所示:
case (a)
c: begin
e = g;
end
default: begin
b = t;
end
endcase
always语句
always语句后跟begin,如下所示:
always @ (posedge clk) begin
a <= b;
end
其他
=、==、<=、>=、+、-、*、/、@等符号左右各有一个空格。
,和:符号后面有一个空格。
对于模块的输入信号,不省略wire关键字。
每个文件的最后留一行空行。
if、case、always后面都有一个空格。
未完待续。