写在前面的话
本节呢,梦翼师兄重点和大家谈一下层次化设计方法,我们所谓的层次化设计,实际上就是对一个很大的系统设计进行拆分,直到拆分成很容易实现的最小模块为止。我们都知道,如果我们想要盖一栋大楼,那么首先一定是先设计好工程图纸,然后建筑工人才可以根据设计图纸施工。那么电子系统设计呢?其实也是这样的,在进行具体代码设计之前,我们首先应该认真分析整个的项目需求,在确定项目需求理解无误的情况下,按照电路功能不同,我们可以将整个系统划分成若干个比较大的子模块,然后根据各子模块的功能,进行进一步的细分,直至无法分解。好的层次划分可以有效降低系统开发难度,同时也有利于团队作战,团队中的每个人只需要负责完成自己的那部分模块,最后由顶层设计者进行组装拼接即可完成整体项目的设计。
层次化设计框图示例
如上图所示就是一个简易的层次化设计模型,系统顶层模块只是负责连线,将各功能单元正确的组合起来。而各功能单元又由各自对应的若干子模块组成,同一单元的子模块之间有着相应的级联关系。
层次化设计实例
大家还记得梦翼师兄给大家分享的流水灯实验吗?在这里,我们回顾一下,我们首先用状态机实现了流水灯的时序,然后由于LED灯切换时间过快,我们无法看到流水的现象,因此我们又采用了两种方式来限制LED切换,第一种:在状态机中嵌入延时计数器 第二种:创建一个时钟分频模块,然后用慢时钟驱动状态机。我们利用以上两种方式最终都实现了流水灯的结果,而且所有的代码修改都是在同一个文件下。那么今天梦翼师兄和大家一起来学一下层次化设计的实现方式。
系统顶层架构图
模块功能介绍
模块名 |
功能描述 |
Freq |
时钟分频模块,用来分频产生慢时钟 |
LED_Driver |
LED驱动,控制LED灯切换 |
Led_flow |
系统顶层模块,负责子模块级联 |
顶层模块端口介绍
端口名 |
端口说明 |
Clk_sys |
系统50MHz时钟输入 |
Rst_n |
系统复位 |
Pio_led |
LED驱动端口 |
4.1.3.4 系统内部连线介绍
连线名 |
连线说明 |
Clk_slow |
分频得到的慢时钟信号 |
4.1.3.5 代码解释
LED_Driver 模块代码
/**************************************************** * Engineer : 梦翼师兄 * QQ : 761664056 * The module function:流水灯驱动模块 *****************************************************/ 01 module led_learn( 02 clk, //系统时钟输入 03 rst_n, //系统复位 04 pio_led//LED驱动输出 05 ); 06 //系统输入 07 input clk; //系统时钟输入 08 input rst_n; //系统复位 09 //系统输出 10 output reg [3:0]pio_led;//LED驱动输出 11 //中间寄存器定义 12 reg [1:0]state;//状态寄存器定义 13 14 //LED驱动逻辑 15 always@(posedge clk or negedge rst_n) 16 begin 17 if(!rst_n) 18 begin 19 pio_led<=4'b1111;//LED全部熄灭 20 state<=0;//寄存器赋初值 21 end 22 else begin 23 case(state) 24 0:begin 25 pio_led<=4'b0111;//第一个灯点亮 26 state<=1;//状态跳转 27 end 28 1:begin 29 pio_led<=4'b1011;//第二个灯点亮 30 state<=2;//状态跳转 31 end 32 2:begin 33 pio_led<=4'b1101;//第三个灯点亮 34 state<=3;//状态跳转 35 end 36 3:begin 37 pio_led<=4'b1110;//第四个灯点亮 38 state<=0;//状态跳转 39 end 40 default:state<=0; 41 endcase 42 end 43 end 44 endmodule |
本模块代码就是我们之前做过的做基本状态机驱动模块,每来一个驱动时钟上升沿,状态发生一次跳转,LED值随之发生改变。
Freq 模块代码
/**************************************************** * Engineer : 梦翼师兄 * QQ : 761664056 * The module function:时钟分频模块 *****************************************************/ 01 module freq(clk,rst_n,clk_slow); 02 input clk;//系统50MHz时钟输入 03 input rst_n;//系统复位 04 05 output reg clk_slow;//慢时钟定义 06 07 reg [40:0]counter;//计数器定义 08 09 //时钟分频电路 10 always@(posedge clk or negedge rst_n) 11 begin 12 if(!rst_n) 13 begin 14 counter<=0;//计数器赋初值 15 clk_slow<=0;//慢时钟赋初值 16 end 17 else 18 begin 19 if(counter<12) 20 counter<=counter+1; 21 else 22 begin 23 counter<=0; 24 clk_slow<=~clk_slow; 25 end 26 end 27 end 28 endmodule |
该模块的作用就是利用计数器实现分频:统计一定的快时钟个数,然后驱动慢时钟寄存器值发生翻转,输出慢时钟。
Led_flow模块代码
/**************************************************** * Engineer : 梦翼师兄 * QQ : 761664056 * The module function:流水灯顶层模块 *****************************************************/ 01 module Led_flow(clk,rst_n,pio_led); 02 input clk;//系统50MHz时钟输入 03 input rst_n;//系统复位 04 05 output [3:0]pio_led;//LED驱动输出 06 07 wire clk_slow;//慢时钟定义 08 09 freq freq( 10 .clk(clk), //系统时钟输入 11 .rst_n(rst_n),//系统复位 12 .clk_slow(clk_slow)//慢时钟输出 13 ); 14 15 led_learn led_learn( 16 .clk(clk_slow), //驱动时钟输入 17 .rst_n(rst_n), //系统复位 18 .pio_led(pio_led)//LED驱动输出 19 ); 20 21 endmodule |
该模块为系统顶层模块,负责将分频模块和LED驱动模块进行组装级联。梦翼师兄强烈建议在顶层模块只做模块级联,绝对不要编写任何逻辑。
仿真代码
/**************************************************** * Engineer : 梦翼师兄 * QQ : 761664056 * The module function:流水灯测试模块 *****************************************************/ 01 `timescale 1ns/1ps //时间单位和精度定义 02 module tb; 03 04 //系统输入 05 reg clk; //系统时钟输入 06 reg rst_n; //系统复位 07 //系统输出 08 wire [3:0]pio_led;//LED驱动输出 09 10 initial 11 begin 12 clk=0; 13 rst_n=0; 14 #1000.1 rst_n=1; 15 end 16 17 always #10 clk=~clk;//50MHz时钟 18 19 Led_flow Led_flow( 20 .clk(clk), //系统时钟输入 21 .rst_n(rst_n), //系统复位 22 .pio_led(pio_led)//LED驱动输出 23 ); 24 endmodule |
查看仿真波形如下
如何查看波形呢?既然逻辑是分模块的,那么我们查看波形是否正确也应该是分模块来看的,首先我们查看 freq模块,freq模块的功能就是快时钟产生慢时钟,通过波形我们可以看到clk_slow慢时钟确实产生了,说明该模块功能正确。
接下来,我们的目标是将慢时钟作为LED驱动模块的时钟源,也就是说LED驱动模块的时钟端口“clk”频率应该和clk_slow一致,查看波形可知,条件符合,说明顶层级联关系正确。
最后查看流水灯切换,应该发生在每一个驱动时钟上升沿,由波形图可知,逻辑全部正确,设计结束。
对于层次化设计,我们可以查看RTL级视图(软件操作请查看梦翼师兄视频)
可以看到,电路生成的RTL级视图和我们所设计的架构图一致,说明系统顶层连接正确。因此通常情况下,如果是进行层次化设计,设计结束以后我们应该首先查看RTL级视图是否正确,只有确保顶层连接正确的情况下我们才进行电路仿真,查看代码时序逻辑是否正确。