层次化设计
炼狱传奇-层次化设计之战本节我们通过驱动流水灯的不同方式来体现 Fpga 中的一个重要思想—层次
化设计。
首先介绍一下我所使用开发板的硬件资源,50MHZ 时钟输入、4 个低电平点
亮的流水灯。 然后通过两种不同驱动方式的对比使读者更加深层次的了解层次化
设计
下图提供了一段流水灯代码,请问能够实现流水现象吗?
与上述代码所对应的波形图如下
FPGA 的时钟是 50M,周期 20ns,上述代码每隔 20ns,流水灯的状态发生改
变,即每个灯亮的状态是 20ns,时间非常短,人的肉眼观察不到灯亮的状态。
由于周期特别短导致无法观察到灯亮,因此只要通过计数器将周期延长一定
的时间,就可以看到“流水”现象。以下代码通过设计一个计数器 count 将周期
延长到两秒,代码如下
代码经过编译以后得到 RTL 图如下
下面提供相对应的仿真代码, 通过参数传递的方式将 led_fsm1 中的 NUM 赋
值为 50,代替 NUM=28'd100000000,提高仿真效率
具体解释如下,在 led_fsm1 中 NUM 达到 28'd100000000-1(NUM-1)时,才会
产生时钟的跳转,但是在波形仿真中仿真时间长,效率低,通过参数传递将 50
传给 NUM,这样在仿真中,NUM-1=49 时,时钟发生翻转,提高仿真效率,参数传
递时,将参数定义为 parameter 类型,并且在文件中凡是能够用到参数的地方,
尽量要用参数表示,比如用到 28'd100000000-1,可以用 NUM-1 代替,否则会导
致参数传递失败。具体参考给出的波形文件
仿真结果如下
从 上 面 的 波 形 看 出 当 count==50-1 , led_out 发 生 改 变 , 而 不 是
count==28'd100000000-1 ,由此可知参数传递成功
那么,请问一下,在一个模块里面既要写 count 分频模块,又要写 led_out
的输出,有没有简单的思路呢?
下面我们介绍一种更简单的思考方式,层次化设计
所谓层次设计就是将一个整体项目划分成多个模块, 就像电脑由键盘、 鼠标、
显示器构成一样。分好模块以后,我们就必须要一个顶层文件,将多个模块连接
起来。
下面依然用一个 50MHz 的晶振点亮一个流水灯进行层次化设计为例进行讲
解。
首先考虑流水灯由哪几个模块构成。如果用 50MHz 驱动流水灯的话,50MHz
频率过快,会导致点亮流水灯的效果看不到,所以我们需要一个分频模块,将时
钟频率降低。为了实现流水灯则需要一个逻辑控制模块,最后将这两个模块在顶
层中进行连接
系统框图如下:
接下来,设计具体电路描述代码,实现各模块功能,首先,新建工程如下
然后建立起顶层文件
建立时钟分频模块 led_freq 在这里不建议调用锁相环(PLL) ,锁相环分频
是有限制的,我试了一下如果用锁相环来点灯的话,时钟太快还是看不到流水的
现象,所以需要独立编写一个 led_freq 模块
在写完分频模块以后,就要写如何让流水灯实现,以下是流水灯控制模块的代码,在控
制模块 (led_ctrl) 中 注意信号 clk, 此时钟不是 50M 时钟, 是经过分频模块分频以后的时钟,
这点是如何实现的呢?可以看后面提供的 RTL 图,看模块的连接关系,和顶层模块讲解
下面先提供一个 led_ctrl 控制的仿真代码,用来测试单独的流水灯控制模
块,具体代码如下
led_ctrl 模块仿真波形如下
有以上波形可以看出,复位结束以后,流水灯的驱动端口 led_out 和状态机
的状态寄存器 state 在时钟上升沿的驱动下有效配合,实现了数据的滚动赋值,
可以正确实现流水灯设计。
下面编辑顶层模块, 顶层模块的主要功能是将分频模块和流水灯控制模块连
接起来,我们要求在顶层中只做端口连线,不做任何逻辑。顶层具体代码如下:
进行全编译,结果如下:
编译通过,我们可以首先查看一下 RTL 级视图,点击 Tools->Netlist Viewers->RTL Viewer
查看结果如下
由上图可以说明,最终综合出来的电路和我们所设想的是完全一致的。
通过对比以上两种方法, 可以很明显的发现层次化设计的 RTL 视图能够清晰的反映出模
块之间的连接关系,在设计中可以独立的对每个模块进行设计,降低设计的复杂度,尤其是
大规模的设计,也便于代码的调试,将一个复杂的系统转换为对每个独立模块的调试,所以
层次化设计是一项非常重要的设计技巧
页:
[1]