时间:2024-08-02 来源:网络搜集 关于我们 0
3)瓜熟蒂落之5: Verilog实现控制器IP
昨天把系统的概要和各个模块细说了一遍,今天就要开始具体的实现设计了。实际上就是要在FPGA上把符合自己需要的功能的电路设计出来。今天的这个部分还是属于硬件部分,自己也要设计电路了,感觉是不是很高大上?不过怎样下手来描述这个过程呢,有点懵,照例让我泡杯铁观音,清醒一下头脑。
都已经是2020年了,电路设计(尤其是数字电路设计)是不是已经没有以前的电路图输入模式了?直接就用高级语言Verilog,它是一种硬件描述语言,通过它来描述电路,再经过软件的分析/综合/布局布线,最终在FPGA上形成具体的电路。这里推荐Verilog,而不是HDL,因为Verilog和C很类似,容易上手。有个英文网站,自己从上面学到很多,建议参考一下,地址为 https://www.fpga4fun.com/,名字也很贴切,FPGA就是有趣的。网站上有很多项目的讲解,提供了很多关于FPGA和Verilog语言的参考资料,真的值得看一看。
对于Verilog语言,这里补充说明自己的心得,那就是要有个好的编程习惯,要需要好FSM(有限状态机)的使用,虽然代码长一点,还是使用3段式状态机,而且固定用一种类型的状态机。有限状态机状态机分为Mealy状态机(状态机的输出由当前状态和输入决定)和Moore状态机(状态机的输出只由当前状态决定)两类。它们之间是有差别的,很相似但又不同,深入理解它们之间的细微差别是控制器设计的关键。有机会整理研究一下。我还是喜欢用Moore状态机,因为状态机的输出只由当前状态决定,在写代码的时候考虑的因素少一点,比较直接。
好了,如下的设计细节,再现了上一节的系统框图和设计架构,确实是模块化的喔。
Design of IP
这么些个模块,挨个描述过来,这文章可要写到复工了(2019年不平凡,2020年开年也不平凡啊),时间不允许,就拿ALPG模块为例子,描述一下设计方法吧。毕竟,模块间很类似的,只是各自完成不同的功能而已。
首先,模块的端口声明:
Module PORT, ALPG-1
Module PORT, ALPG-2
如上面2个图上中文标注的一样,模块的端口声明包含了6大组信号。因为ALPG在这个系统里和3个模块产生了交互,分别是testflow(TF)、datacenter(DC)和实际闪存(ONFI),有输入也有输出,因此在信号的命名上有规律,谁发起的就写在前面。这是我的个人偏好,也许其他同学有更好的方案,欢迎指教,共同进步。其中的第1类可定制参数,可以用来定制一些产品相关的参数,方便IP使用,特别是其中的 parameter PAGE_SIZE = 16d4352, 需要根据对应的闪存产品做相应的设定。比如之前提到的那个产品,参考Feature 页的说明,应该在系统设定时选用 PAGE_SIZE = 16d4320。
Feature of NAND
接下来就是所谓的3段式状态机来实现各个端口(基本上就是输出端口了,输入端口主要用于状态机的状态跳转。为什么呢?因为我偏好的就是前面提到的Moore型状态机啊)的功能了!以WE信号为例子,稍微详细解说一下吧。
写状态机时,首先会定义一些状态机的状态了,如下图(部分):
Parameter of FSM
其中的current_st 就代表当前状态, next_st就代表下个状态了。然后一系列的localparam 就来定义各种状态,这里没有采用所谓的One-Hot Code, 就让综合器自己去优化了,毕竟状态数目不少,所以用了8位来表示。
3段式之一:时序电路,描述状态的跳转。如下,这是常规写法,照着写就可以了。可以看出,这是一个异步复位时序电路,复位时是下降沿有效,而通常状态的跳转发生在时钟的上升沿。
1st of three FSM
3段式之二:组合电路,描述具体各个状态的跳转方式。这个电路有点长,因为它取决于电路的功能和用到的状态。
No 1 of Stage 2, FSM
No2 of Stage 2, FSM
稍微解释一下上面代码的功能。
行264:当当前状态current_st在初始S_INIT时,如果复位信号为低,下个状态next_st还是当前状态,否则(就是为高,复位无效)下个状态next_st就转入S_CHECK_CMD,目的就是检查有否命令信号进来。
行267:在当前状态current_st为S_CHECK_CMD时,如果TF_ALPG_request 和 TF_ALPG_cmdValid2个 信号都有效, 下个状态next_st就转为 S_LOAD, 也就是将命令信号锁存。否则如果TF_ALPG_request 和 TF_ALPG_cmdValid2个 信号中有一个无效, 下个状态next_st就转为 current_st,其实就是维持在当前状态。这样就实现了命令的检测了。
行271:在当前状态current_st为S_LOAD时,如果TF_ALPG_request信号为低, 下个状态next_st就转为 S_DECODE,去完成解码动作。否则, 下个状态next_st就转为 current_st,也就是维持在当前的S_LOAD状态。这样的设定,就完成了 ALPG和TF之间的握手协议。TF对ALPG有个请求 (TF_ALPG_request && TF_ALPG_cmdValid 都有效,也就是拉高),ALPG在合适的状态,也就是当前状态current_st为S_CHECK_CMD就应答,切换状态从S_CHECK_CMD转入S_LOAD,通知TF(怎么通知呢?也就是S_LOAD状态时状态机的输出,这在第3段会给出。),然后等待TF拉低TF_ALPG_request,表示TF收到了通知,TF可以继续去做别的事情,直到合适的时候再来确认ALPG的状态。
行274: 对锁存的命令解码
行276:根据解码结果,分配任务,跳转到不同的状态。因为不同的状态会有不同的相应的输出,这就实现了信号的输出管理。
行296:以接受到的指令为命令作为例子,这里是个准备动作。比如,有些命令需要闪存的状态为RDY才接收。
行298:具体的命令输出状态。当寄存器data_toggled_cnt的计数等于命令给出的 值(reg_TF_ALPG_validByteCnt)时,表示命令完成,下个状态next_st就转入S_POST_NAND_CMD,进行收尾工作,比如确认闪存是否完成命令进入RDY状态。否则继续维持在当前状态,完成相应的命令。
行302: 命令完成,进入命令完成状态S_DONE,这是就可以输出响应,告诉TF命令完成了。
好,接下来进入最后一段,也就是
3段式之三:时序电路,描述具体各个状态的输出。因为采用的是Moore型状态机,每个状态的输出很容易确定,只和当前状态有关。因此,对于WE信号,就有了如下的第3段描述(摘要):
Part1, FSM Stage3
Part2, FSM Stage 3
可以看到,行1791:在当前状态S_PRE_NAND_CMD时, WE (由寄存器变量 reg_ALPG_ONFI_WEb值定义)为 reg_ALPG_ONFI_WEb <= 1b1, 也就是电平为高。当前状态S_OP_NAND_CMD时,行1796开始就由 clk_index_in_onecmdseq寄存器的值来顺序反转。这就实现了WE的下降沿和上升沿。当然不能永远反转下去啊,前面第2段里规定好了,当寄存器data_toggled_cnt的计数等于命令给出的 值(reg_TF_ALPG_validByteCnt)时,表示命令完成,下个状态next_st就转入S_POST_NAND_CMD啦。
如此,3段式状态机的描述,虽然代码行数多,但逻辑清晰明了,不容易写错。当然,还有一句话别忘了,非常重要,就是下面这条连续赋值语句,不可缺少喔:
assign ALPG_ONFI_WEb=reg_ALPG_ONFI_WEb;
它就把 reg_ALPG_ONFI_WEb的值赋给真正的信号 ALPG_ONFI_WEb了。
好了,如法炮制,各个输出信号都可以实现完成了。
然后是分析(RTL ANALYSIS)和仿真(SIMULATION),确认功能是否符合要求。这里的仿真就要写个测试模块,test bench, 忘了该如何翻译了(羞)! 实际上,写测试模块和写实际的模块很类似,一样需要功力,但有些场合还更加烧脑细胞。时间不够,这里就不展开了。在这方面自己也还需要努力多学习呢。如果发现功能有不符合的,还得再修改代码,继续分析/仿真,来几个反复。 然后下一步时综合(SYNTHESIS), 输入约束,进行时序仿真(后仿),同样可能需要几个来回,直到满意为止。接下来一步,离胜利就可近了,可以进行实现(IMPLEMENTATION), 生成BIT流(Generate Bitstream),下载到开发板上做下一步验证。当然还有个在线逻辑分析仪。在Vivado 中,在线逻辑分析仪的功能被称为“集成逻辑分析器(Integrated Logic Analyzer,ILA)”,它以IP 核的形式来加入到用户设计中。Vivado 提供了三种具有不同集成层次的插入ILA 方法,以满足不同Vivado 用户群的不同需求。详细的可以参考相应的文档。真的好强大,不需要昂贵的示波器了!
上面谈到的这一些,都可以有大篇幅来描写,今天就割爱了。就上个功能仿真的图吧:
testbench ALPG
可以看到,途中的 1,2,3,4 处分别完成了 80h(Command),0x0123(Address),0x001905(Address)和 10h(Command) 的波形。
所有这些无误地完成后,就可以把它封装成IP,供下一步硬件系统的使用了。请看Chunhui的下回分解了。