EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
+ c: b" M2 C3 E. k2 n7 q+ b
- `& Q; v6 u) o) T5 d) d) W! \学习FPGA,最关键的是学什么?有读者学了大半年时间的FPGA,学了串口就只懂串口的设计,学了spi就只懂SPI接口的设计。每个接口、每个功能,都只是学一个懂一个。换个功能需求,或者对接口做一个小小的改动,就无从下手了。 设计代码,从来都只是模仿,或者不断地调试修改,凑代码。设计出的代码也没有任何规律,相同的功能,今天设计和明天设计都不一样。这就如学功夫,今天学下少林,明天学下武当,后天又学下华山,在这样的情况下,能成长为高手,那就奇怪了。 在明德扬看来,FPGA设计应该有一套通用的设计方法。该方法能够应付所有的功能设计,无论功能怎么变,都可以用该方法来套用。明德扬发明的这套方法就是至简设计法。 至简设计法从宏观上,适应所有的功能设计需求。例如,无论是什么功能,我们都先将其转化成需求波形。然后在此基础上设计模块架构;在模块架构基础上设计信号。这步骤都是通用的、是固化的。 至简设计法在微观上,则制定得实用的规范。详细到,要不要添加信号;怎么添加信号;添加信号的名字规范等,我们都做了详细的规定。 下面我们用4个经典例子,讲述了至简设计法的使用技巧。其他复杂功能,无论怎么变,都是这4个经典案例的变种。读者只需要强化、巩固技巧,多训练,多应用,逐步成长为高手。 至简设计法经典案例1 案例1. 当收到en=1后,dout产生一个宽度为10个时钟周期的高电平脉冲。 : v' G8 r; m5 S4 u! M( N; R
需要说明,根据看波形规则,在第3个时钟上沿的时候,看到en==1,根据功能要求,上升沿之后dout就会变为1。10个时钟周期后,dout将变为0。 从功能要求中,看到数字10,我们就知道要计数,并且是dout==1的次数为10个。所以我们计算的是dout==1的时钟次数,并且是10次。为此,补充一个计数器信号cnt,更新后的波形如下图。 计数器cnt要遵守如下原则。 初值一定为0。 除了最后一个,在时钟上升沿,看到dout==1,就将cnt值加1 在时钟上升沿时看到dout==1,并且是最后一个时,cnt值不加1,直接清零。 从功能要求和波形图,我们确认,计数器cnt是对dout==1进行计数,并且一共数10个。为此,在GVIM编辑器中输入“Jsq”并回车,将出现如下代码。 在第13行,输入dout==1,在第14行代码中,输入10-1,这样就完成了计数器设计。 代码解释:第1至第11行,是一个时序always的代码。该代码要描述的功能是: 在时钟clk上升沿或者复位rst_n的下降沿的时候,always就对cnt判断条件并变化一次。具体变化过程如下: 如果是rst_n==0,则将cnt变为0。 否则(即rst_n==1),如果add_cnt有效,也就是为1的时候。继续判断条件并执行。 如果end_cnt有效,即end_cnt==1,则将cnt变为0。 否则(即end_cnt==0),cnt就自加1。 否则(即rst_n==1且add_cnt==0的时钟),cnt保持不变。 上面代码中add_cnt表示计数器加1条件,end_cnt表示计数器数到最后一个。 上面代码描述过于复杂,其实概括起来,功能就是:时钟上升沿时,如果计数器加1条件有效,并且是数到最后一个,则计数器清零;如果计数器加1条件有效,但不是最后一个,则计数器就加1;其他时候,计数器就保持不变。 那么加1条件,即add_cnt是什么呢?在第13行进行了定义。该行代码表示,dout==1就是计数器的加1条件。 那么结束条件,即end_cnt是什么呢?在第14行进行了定义。该行代码表示,数到10个就结束。其中我们关注的是那个数字10,而-1是固定的格式。 add_cnt && cnt==10-1,含义是表示“数到第10个的时候”,add_cnt &&cnt==x-1表示“数到第x个的时候”。记住这个规则。end_cnt==1也表示数完了。 设计好计数器cnt后,我们就可以设计输出信号dout了。仔细分析dout,该信号有两个变化点:变1和变0。我们分析原因,dout变1是由于收到en==1;dout变0,则是数到了10个或者是数完了。所以综上所述,dout的代码是: 至此,我们完成了主体程序的设计,接下来补充module的其他部分。 将module的名称定义为my_ex1。并且我们已经知道该模块有4个信号:clk、rst_n、en和dout。为此,代码如下: 其中clk、rst_n和en是输入信号,dout是输出信号,并且4个信号都是1比特的,根据这些信息,我们补充输入输出端口定义。代码如下: 接下来定义信号类型。 cnt是用always产生的信号,因此类型为reg。cnt计数的最大值为9,需要用4根线表示,即位宽是4位。add_cnt和end_cnt都是用assign方式设计的,因此类型为wire。并且其值是0或者1,1个线表示即可。因此代码如下: dout是用always方式设计的,因此类型为reg。并且其值是0或者1,1根线表示即可。因此代码如下: 至此,整个代码的设计工作已经完成。整体代码如下: 1 $ m' ~* M" L4 o ~, @! d
2 & j7 S* `/ P2 `" ]4 R2 M0 d" y! e3 D( l
3
& K2 ^- [# u1 I/ z- F9 C# D2 \4 4 n( F! F- N% } v' i; @) c# S! E
5 0 W# ^6 x& p+ ~0 f' q% H
6
( L7 H8 V3 W X7 % o6 ~: }, m$ {) X% i }7 }' ]
8
+ _! S/ [+ }' g2 s5 R6 D8 S k9
% k4 }* o* s6 c10
, p& { ]+ o7 \1 {7 F* b3 E11 , K4 E: J; \: ^9 X/ d) Y
12 ; b, n# b. w6 I8 @- f3 t" B6 @
13
; n# n* t/ v$ e3 c14 , _7 H1 M7 }# p* h- J1 x
15 ; g) j) u6 q( R. s$ C: D
16
) o5 Q7 g" [7 `& U3 C17 ; G, ?, E, o% g/ [ C
18 C" |' ~4 X( P* ?" s# ~
19
0 @( W0 u" u# l* {( ^# M20 9 ?0 L Q: _* Y( {
21
1 _. c3 N0 z; C1 \' e1 Y22
2 x M0 Y/ E1 T23
$ b* z2 p; h j2 c24 2 P, C( k: i" E5 t+ D0 e t
25
2 {, o* D, [0 {. M' K" z* y26 9 F/ ?% r4 M u, {# t
27 + c0 a! V5 a) X$ U% C( s
28 | module my_ex1(
- \* q0 h. o7 G, T; j0 l clk , 4 [3 D0 x( g! C& V3 p E# n" w
rst_n ,
( h* ^# V' K0 o" e3 O8 M en ,
0 l. g8 [0 R$ A/ ?1 [+ A, Q$ F dout
, {! M+ C6 {8 r7 R6 Z);
, |- J8 W( ], j5 l" B5 _input clk ;
3 \5 b* m' e* i6 h5 ~ ?input rst_n ;
" I9 T, _" H) s8 Minput en ; ]0 `0 X+ {; x. A
output dout ;
2 U6 y/ ]; ~& F2 w# breg [ 3:0] cnt ;
" w' q! s$ L Fwire add_cnt ; % ~! R9 d! S* V+ M# `, m
wire end_cnt ; 4 J# K/ m4 L8 h4 W* f" F
reg dout ; " X, K/ ~; k! ]4 [* p- B
always @(posEDGE clk or negedge rst_n)begin 4 _1 @( D/ ^; A$ R; U3 O1 V4 K" l
if(!rst_n)begin
- `7 J! k8 h& @' f1 Q* \) u7 R cnt <= 0;
9 A! D' ? q+ }2 z; z end " I* C9 Q0 l3 D1 G1 F1 ?: h
else if(add_cnt)begin
, C$ m( s$ R& N3 j7 u if(end_cnt) $ j2 `" |( |7 ?
cnt <= 0;
' k. ]& E7 K( _6 C1 x else 9 Q+ ?% E! j& G! H8 p5 [2 h
cnt <= cnt + 1;
: o9 R- g9 ~0 Z3 u end ; U! c/ o* \; H. f' C# c' @
end
8 Y' e. u2 ~; C8 S9 yassign add_cnt = (dout==1); 1 m% I( l: ]: J
assign end_cnt = add_cnt && cnt==10 -1 ; ( I1 A9 Z5 a: ?$ e( N/ {, ?1 u, E
always @(posedge clk or negedge rst_n)begin
. N" _' r4 W/ v if(rst_n==1'b0)begin
5 w+ V! o, X o3 A7 q+ q* K# N! D/ k dout <= 0;
5 }* h" `$ O4 Q end + d8 e+ I% m" j% Z8 |
else if(en==1)begin
; ?0 V$ S% c! U! K% V2 o dout <= 1; - o9 c$ d5 ]+ j1 y& }1 Y' G
end ; N6 T: c& S: Z# S, A
else if(add_cnt && cnt==10-1)begin
; ]( L( e+ x: I0 `' q7 n# |# q dout <= 0; ' |# |1 V7 a; l/ {
end 6 F. v' j$ `) W% W o) C
end
! G/ o( V: S! v- g. |& P' b; Uendmodule |
+ t1 J+ R9 s0 c/ z t: Z& i6 z8 d4 K4 n4 |0 x% k9 ]7 {' x* E
4 _7 \$ r8 r. i, N/ R, T7 W, c, [; ]% a' P% T: U4 Z6 Z
|