sky 发表于 2020-9-18 07:56:14

从零开始写RISC-V处理器【2】浅谈Verilog

本帖最后由 sky 于 2020-9-18 09:11 编辑


从零开始写RISC-V处理器【1】前言
从零开始写RISC-V处理器【2】浅谈Verilog
从零开始写RISC-V处理器【3】硬件篇(1)
从零开始写RISC-V处理器【4】硬件篇(2)
从零开始写RISC-V处理器【5】硬件篇(3-完)

项目地址:https://gitee.com/liangkangnan/tinyriscv
verilog,确切来说应该是verilog HDL(Hardware Description Language ),从它的名字就可以知道这是一种硬件描述语言。首先它是一种语言,和C语言、C++语言一样是一种编程语言,那么verilog描述的是什么硬件呢?描述电阻?描述电容?描述运算放大器?都不是,它描述的是数字电路里的硬件,比如与、非门、触发器、锁存器等等。
既然是编程语言,那一定会有它的语法,学过C语言的同学再来看verilog得代码,会发现有很多地方是相似的。
verilog的语法并不难,难的是什么时候该用wire类型,什么时候该用reg类型,什么时候该用assign来描述电路,什么时候该用always来描述电路。assign能描述组合逻辑电路,always也能描述组合逻辑电路,两者有什么区别呢?
3.1 用always描述组合逻辑电路
我们知道数字电路里有两大类型的电路,一种是组合逻辑电路,另外一种是时序逻辑电路。组合逻辑:输出只是当前输入逻辑电平的函数(有延时),与电路的原始状态无关。当前电路输入信号任何一个发生改变,输出都将发生改变。时序逻辑:输出不仅是当前输入电平的函数,还与目前电路的状态有关。
在verilog中,assign能描述组合逻辑电路,always也能描述组合逻辑电路。对于简单的组合逻辑电路的话两者描述起来都比较好懂、容易理解,但是一旦到了复杂的组合逻辑电路,如果用assign描述的话要么是一大串要么是要用好多个assign,不容易弄明白。但是用always描述起来却是非常容易理解的。
既然这样,那全部组合逻辑电路都用always来描述好了,呵呵,既然assign存在就有它的合理性。用always描述组合逻辑电路时要注意避免产生锁存器,if和case的分支情况要写全。
在tinyriscv中用了大量的always来描述组合逻辑电路,特别是在译码和执行阶段。
3.2 数字电路设计中的时序问题
要分析数字电路中的时序问题,就一定要提到以下这个模型。



其中对时序影响最大的是上图中的组合逻辑电路。所以要避免时序问题,最简单的方法减小组合逻辑电路的延时。组合逻辑电路里的串联级数越多延时就越大,实在没办法减小串联级数时,可以采用流水线的方式将这些级数用触发器隔开。
3.3 流水线设计
要设计处理器的话,流水线是绕不开的。当然你也可以抬杠说:”用状态机也可以实现处理器啊,不一定要用流水线。”
采用流水线设计方式,不但可以提高处理器的工作频率,还可以提高处理器的效率。但是流水线并不是越长越好,流水线越长要使用的资源就越多、面积就越大。
在设计一款处理器之前,首先要确定好所设计的处理器要达到什么样的性能(或者说主频最高是多少),所使用的资源的上限是多少,功耗范围是多少。如果一味地追求性能而不考虑资源和功耗的话,那么所设计出来的处理器估计就只能用来玩玩,或者做做学术研究。
tinyriscv采用的是三级流水线,即取指、译码和执行,设计的目标就是要对标ARM的Cortex-M3系列处理器。
3.4 代码风格代码风格其实并没有一种标准,但是并不代表代码风格不重要。好的代码风格可以让别人看你的代码时有一种赏心悦目的感觉。哪怕代码只是写给自己看,也一定要养成好的代码风格的习惯。tinyriscv的代码风格在很大程度上沿用了写C语言代码所采用的风格。
下面介绍tinyriscv的一些主要的代码风格。
(1)缩进
统一使用4个空格。
(2)if语句
不管if语句下面有多少行语句,if下面的语句都由begin…end包起来,并且begin在if的最后,如下所示:

(3)case语句
对于每一个分支情况,不管有多少行语句,都由begin…end包起来,如下所示:

(4)always语句
always语句后跟begin,如下所示:

(5)其他
=、==、<=、>=、+、-、*、/、@等符号左右各有一个空格。
,和:符号后面有一个空格。
对于模块的输入信号,不省略wire关键字。
每个文件的最后留一行空行。
if、case、always后面都有一个空格。


页: [1]
查看完整版本: 从零开始写RISC-V处理器【2】浅谈Verilog