【0.2基础的条件准备两周之后的数字IC前端设计校招面试】0.2进化到0.3——模块思维实现功能

it2022-05-05  129

前言

书接上文:https://blog.csdn.net/moon9999/article/details/96614319

目前我们已经进化到0.2形态了,简单来说verilog代码层面已经没有我们不会的了(哈哈( ̄▽ ̄)"),如果还有不会的那就是自己的问题哈。那么接下来我们需要建立模块思维。

简单来讲,一个芯片是由若干多层级大大小小的模块构成,每个模块根据输入给出信号输出完成自己的功能,模块间通过互连和调用进行配合最终实现整体的功能。说句实在话,模块划分是个技术活,我觉得只有到架构师层次还能拍下来,划分不好不仅会影响芯片功能实现,还可能会严重拖延项目进度,还有可能几个设计人员打起来。。。

当然作为刚入门的渣渣,我们不用考虑这么多,假设别人就是把一个功能点以模块的形式给了我们,接下来我们开工。

模块化思维

任务描述

给芯片做个万年历记录下芯片工作了多少年了,责任重大,以后查询一款芯片什么时候开始工作的就靠你这个功能了!

输出四个信号分别是是秒分时日,当输入使能信号有效是进行计时,否则包持原有时间计数,当脉冲信号clr有效时,清空所有计数,当清空信号和使能信号同时为1时,清空计数重新计数。

接口定义

信号

类型

位宽

描述

clk

input

1

时钟,经过外部分频处理为1s一拍即时钟频率为1Hz

rst_n

input

1

复位信号,低电平有效,要求异步复位

en

input

1

使能信号,信号为高电平时万年历工作,否则各项计数包持原值不变,同步维持信号

clr

input

1

清零信号,信号拉高时清零所有计数,同步单拍脉冲信号

sec

output

8

输出万年历 秒

min

output

8

输出万年历 分

hour

output

8

输出万年历 时

day

output

8

输出万年历 日

 需求分析

简单看下我们的输入。输入信号很简单,时钟复位和使能信号,使能有效时万年历工作,使能无效时万年历包持原值,当脉冲信号clr有效时,清空所有计数,当清空信号和使能信号同时为1时,重新计数;由于没有异步信号,代码中无需涉及异步处理。

输出信号分别是万年历的秒分时日,看起来这个芯片使用周期很难超过256天啊;sec显然应该时是0-59循环计数,min是0-59循环计数,hour是0-23,day就一直计满再翻转了。

底层模块

有些人的思维是自定而下型,先由功能搭出大概的框架,一步步向下划分模块;有些人的思维是自下而上型,先写一个个基础功能模块,再把这个模块通过互连和调用组合在一起

完成顶层功能。我也不知道这两种思路哪一种是更好的思路,如果我选我选择看心情。

对于这个需求呢,我们不妨就先来写一个小模块,名字就叫计数到某一固定值就自动反转的模块。

经过一番努力,这是我最后完成的小模块。实现的思路很简单,模块实现计数器功能,传参为计满翻转值,en信号有效时进行计数功能,clr信号有效清空计数值,clr信号优先级更高。代码非常简单,甚至不需要做成模块。

module u_count #( parameter CNT_MAX = 256 ) ( input clk , input rst_n , input en , input clr , output reg [7:0] cnt ); always @(posedge clk or negedge rst_n)begin if(!rst_n)begin cnt <= 8'b0; end else if(clr)begin cnt <= 8'b0; end else if(en)begin if(cnt == CNT_MAX -1)begin cnt <= 8'b0; end else begin cnt <= cnt + 8'b1; end end else begin cnt <= cnt; end end endmodule

代码里有几点说明一下:

a.信号位宽不定义,那么就取默认值位宽为1,不是自动适配的(差点被气心肌梗);

b.输入输出可以像我这样定义,可以采用如下两种形式,不过我认为一定性定义好是最简单有效的;

c.parameter可以定义在传参列表中,也可以在代码中定义,之后的传参形式是没有区别的;

d.位宽定义由大往小写;

e.为什么传参CNT_MAX默认值为256呢,因为256-1是8bit计数器能够达到的最大值,也就是说在不传参的场景下,该技术器模块实现的就是计满翻转的普适性功能;

ps.另外的两种输入输出定义方式:

module u_count #( parameter CNT_MAX = 256 ) ( input clk , input rst_n , input en , input clr , output cnt ); //parameter CNT_MAX = 256; reg [7:0] cnt; endmodule module u_count #( parameter CNT_MAX = 256 ) ( clk , rst_n , en , clr , cnt ); input clk ; input rst_n ; input en ; input clr ; output cnt ; //parameter CNT_MAX = 256; reg [7:0] cnt ; endmodule

模块调用与互连

有了底层模块,我们就可以搭建更大的功能更上层的模块了。显然底层模块是不满足当前定义的输入输出接口需求的,不过没关系,我们先做个顶层把刚刚的count模块例化进去。

module time_top( input clk , input rst_n , input en , input clr , output reg [7:0] sec , output reg [7:0] min , output reg [7:0] hour , output reg [7:0] day ); u_count #( .CNT_MAX(60) ) U_SEC( .clk (clk ) , .rst_n (rst_n ) , .en (en) , .clr (clr) , .cnt (sec) ); endmodule

好的例化模块完成,现在我们的顶层模块已经可以实现sec信号的输出了,那么我们来考虑下如何实现min信号输出。

min信号的实现原理比较简单,只要在sec计数到59的时候自己加1就可以了,跟我们表的时针是一毛一样的。那么我们可以选择在u_count里面加一段always块,当然也可以选择在顶层互连完成。

如何互连呢?其实就可以理解为min的使能条件改变了,sec的使能条件是en信号,en有效时候就一直加一直加,而min的是能条件呢显然变成当en有效且sec==59。遵循这个思路,我们直接在顶层例化一份min模块就可以了。

module time_top( input clk , input rst_n , input en , input clr , output reg [7:0] sec , output reg [7:0] min , output reg [7:0] hour , output reg [7:0] day ); wire min_en; assign min_en = en & (sec==8'd59); u_count #( .CNT_MAX(60) ) U_SEC( .clk (clk ) , .rst_n (rst_n ) , .en (en) , .clr (clr) , .cnt (sec) ); u_count #( .CNT_MAX(60) ) U_MIN( .clk (clk ) , .rst_n (rst_n ) , .en (min_en) , .clr (clr) , .cnt (min) ); endmodule

完成所有代码

遵循这这个思路,我们就可以把hour和day信号都做出来了,同样的操作再例化两份就ok了,那么下面时我最后完成的代码,不过我把parameter单独在外面定义了一份,这是为了便于之后的修改与调整可以集中在一处,不必总是到下面例化处去修改。

module time_top( input clk , input rst_n , input en , input clr , output reg [7:0] sec , output reg [7:0] min , output reg [7:0] hour , output reg [7:0] day ); parameter SEC_MAX = 60; parameter MIN_MAX = 60; parameter HOU_MAX = 24; wire min_en; wire hou_en; wire day_en; assign min_en = en & (sec ==SEC_MAX-1); assign hou_en = en & (min ==MIN_MAX-1); assign day_en = en & (hour==HOU_MAX-1); u_count #( .CNT_MAX(SEC_MAX) ) U_SEC( .clk (clk ) , .rst_n (rst_n ) , .en (en) , .clr (clr) , .cnt (sec) ); u_count #( .CNT_MAX(MIN_MAX) ) U_MIN( .clk (clk ) , .rst_n (rst_n ) , .en (min_en) , .clr (clr) , .cnt (min) ); u_count #( .CNT_MAX(HOU_MAX) ) U_HOUR( .clk (clk ) , .rst_n (rst_n ) , .en (hou_en) , .clr (clr) , .cnt (hour) ); u_count U_DAY( .clk (clk ) , .rst_n (rst_n ) , .en (day_en) , .clr (clr) , .cnt (day) ); endmodule

ps.这段代码没有经过综合和仿真,如果哪里有些语法问题标点问题也是很有可能的,真的写出错了请告知( ̄▽ ̄)"


最新回复(0)