一乐电子

 找回密码
 请使用微信账号登录和注册会员

QQ登录

只需一步,快速开始

微信扫码登录

手机号码,快捷登录

手机号码,快捷登录

搜索
查看: 11889|回复: 14

Verilog HDL 建模技巧 :低级建模 仿顺序操作 · 思路篇

[复制链接]
发表于 2010-6-5 21:48 | 显示全部楼层 |阅读模式
好东西尽收其中 这个是转以下这个仁兄的  akuei2's Blog: P4 F$ ], ^: s4 i
[Verilog HDL 建模技巧 :低级建模 仿顺序操作 · 思路篇] 1 - 封面+书语
1 k* q  Q3 v+ {6 f% `$ ~+ z* E2 W- @
% ?! B  I4 g( r8 e
. t1 P1 _+ B7 l+ A1 n2 f& w/ @% b0 I8 r: a9 S7 c+ H
书语:

“低级建模”是针对入门或者新手提出的一种“设计思路”。我们知道FPGA执行的概念是“并行”,但是在入门众多的实验中,高达4成的实验都是“顺序操作”的执行概念。假设一个比较经典的例子“流水灯”实验。如果利用单片机设计流水灯的驱动程序,是非常简单,我们只要,建立延迟函数,移位函数,和一个大循环,就可以实验流水灯效果。


/ z  |8 W7 {. S5 m- u

但是换做另一个环境如(CPLD/FPGA)的平台上,实验复杂的流水灯效果。在“并行”概念上,设计这样一个驱动程式,会使得初学者上力不接下力。我们可以考虑这样一个问题:“用什么办法,不失CPLD/FPGA"并行性",而且还可以轻松实现"顺序操作" ?

在网上个多的论坛,时常可以看见很多新手求救关于这方面的问题,笔者也是如此,所以笔者才决定写这本笔记。

  Z- Q3 s; f5 U4 B- k

还有一种问题,就是编程风格的问题。Verilog HDL语言对初学者来说,编程风格是最一个大难题的。有这样冷笑话流传在新手之间流传:“ 如果一个新手写十个驱动程式,会超过10个不同的编程风格 ”。这也难怪的,要建立一个编程风格真的不简单,即使是写了多年经验,也不见得会有编程风格。然而“低级建模”有固定的模板格式,可以很好的帮助新手们。


6 G) M+ O3 G# H! h9 G

除此之外,“低级建模”对“仿顺序操作”是简洁的,不同于一般的编程,滥用了“状态机”来达到效果。“状态机”在仿顺序操作上,虽然有很大的效果,但是“状态机”对资源的消耗,和“代码的臃肿”都是可见的。“低级建模”在“仿顺序操作”上,使用“步骤”的概念,就如我们食饭的时候,首先饭来张口,然后慢慢的咽,最后才吨进食道,就这样一个动作就结束。要吃另一口饭的时候,再重复这个动作。(如果吃饭换做是状态机,事物可能会永远卡在食道)


4 P! s8 G2 x2 Q

目前笔记也只是写了“低级建模”的“思路篇”而已,因为笔者考虑到自身资格和经验的问题,笔记的续文非常不适宜。但是笔者认为这已经是足够了,因为笔记的内容可以很好的帮到初学者,从另一个角度去认识Verilog HDL建模技巧。


' @. c% Y* H  V5 j/ [! d3 P

笔者的话:

" s8 g  r' {$ p6 r

还记得自己初次接触Verilog HDL语言时候的感觉吗?曾经有没有因经历失败而灰心呢?如此过来的人,偶尔会回忆,会觉得入门(初学)时的心情是最真实的。即使现在,挫折中,迷失中,混沌中。只要回忆当时,就有继续的勇气 ......

 楼主| 发表于 2010-6-5 21:49 | 显示全部楼层
前言:

再过不久就要毕业了,毕业后就要上班,所以呀学习的时间确实比以前少了许多。不过这不是重点,我发觉自己的“自学”程度已经达到某种的限制,再也提升不了多少,是时候换换环境。故一在此之前写下一本关于Verilog HDL 心得的学习笔记。


* j! o* p0 g2 D1 U) L* @* N

每一本笔记的开始都有一个初衷:在早期练习Verilog HDL 语言(以下简称V语言),有一种莫名的奇怪感觉。相信很多初学者曾经有过这样的感觉 ......

我对这感觉执着很久,似乎要揭开什么!?我以简单的模块,进行了许多样的V语言编程风格,最后我发现有一套很简单而且非常“有效”的方法,我称为“低级建模”。


0 P; _+ h/ Z6 l

一开始,我对这与这方法没有任何“准则”要遵守而非常茫然,要我消耗了很长时间才建立起最基本的“准则”。经过许多的实验,惊讶的发现该方法对于“仿顺序操作”非常有效,我开始猜想“是不是应该建立一个适合低级建模的模板呢?”。模板的概念,有学过C++的朋友应该都知道,在C++的世界里,模板可以根据不同的“类型”,以同样的格式,创建函数,类等等。


" \$ Q& A6 b) E( X- y4 f7 ^4 }, F

在最后的几个试验中,我结论出一种“通用”的编程模板。即使,各个模块都有不同的功能,不同的代码量,不同的编程习惯,但是固定的“形状”还是存在。你应该知道V语言的解读性,不是一般的“穷”!(除非你经验老道)


  Y) p* d7 U4 t7 z6 x, G

可能会出现“鄙视群众”,“批评”自不量力的我搞原创的活儿。这一点我承认,自己才学过几个月的V语言和FPGA而已,没有任何实际的项目经验,V语言都无法精通,根本没有任何资格...  


: t9 I' W' S, t6 [3 t

被这样认为是人之常情,所以我才要事先声明:

# _& I" V) s9 X8 c

这只是个人的一个心得,一个思想而已,纯粹“分享热心”才写这一本笔记。笔记的内容好不好我不知道,有没有用我也不知道,但是有一点,对于初学者来说,它绝对有参考的价值。仅此而已。


+ A  O3 x  g: _) n

这本笔记我不论任何评价。至于该笔记的价值如何,竟可以在读前先不要做任何结论,浏览过后或许你会萌出其他的思路呢?

回复

使用道具 举报

 楼主| 发表于 2010-6-5 21:50 | 显示全部楼层
1“低级建模”的思路
7 _* x' i- G3 w/ @4 }. K) m1 a

首先,我将用一个简单的例子来说明一下,“低级建模”的最基本思路:

(一)利用C语言驱动八位发光二极管:


! y# n1 `/ ?* u( w

http://space.ednchina.com/upload/2010/6/4/8d556145-fa4a-4fb8-a8bf-874d086f1a52.jpg            

(如果我说C语言和单片机是形影不离的哈,估计没有人会反对吧?


% G  [% c, |4 I3 N3 \" {& `+ `

我们以流水灯作为例子,因为它是最经典的实验。假设我要实现流水灯效果,那么我只要建立一个简单的“流水灯函数”函数,“Flashing”。

4 E( M% X- X; e! j

void Flashing(){ ...... }  


2 a: ]' |- t1 H$ z

http://space.ednchina.com/upload/2010/6/4/27ce8e29-6ad5-4d5b-83ae-6b6fd1f39b7b.jpg

* D6 E, B8 ~; Y! ]/ D0 k- `

如果要实现自左向右或者自右向左发光的流水灯,可以使用C语言创建两个简单的函数,Flashing_To_Right”和“Flashing_To_Left”。


  m: X1 {, x9 c: c7 a5 l5 V

# `- v' P* [7 w

   void Flashing_To_Right() { ...... }

void Flashing_To_Left() { ...... }


; `" |$ M7 {0 ?) ~! S


* Z5 T# t  i* ?: C3 H/ z

假设我要实现流水灯效果:

1. 永远自右向左发亮。

2. 永远自左向右发亮。

3. 流水灯永远跑来跑去。

- J  E# c) L+ n( t& ?

那么可以这样写:

! y6 z% ^1 @3 s

    while( 1 ) { Flashing_To_Left(); } //1

    while( 1 ) { Flashing_To_Left(); } //2

while( 1 ) { Flashing_To_Left(); Flashing_To_Right(); } //3

对于C语言来说,这些任务都非常的简单。几乎是入门级的实验,但是将这些实验带入到V语言的环境下。确实一个记得思考的问题。

/ q& ]* F+ k5 I" v$ X

(二)利用V语言驱动八位发光二极管:


, A( _9 U; j; {6 J/ @8 |& a

我们先看一段非常傻瓜的一段代码:

$ _1 p% }; J8 ^. E" q% u


# L, t1 X- |/ C/ q

    module Flashing ( CLK, RSTn, Data_Out );

. g; s0 E: {% S3 A) p

    input CLK, RSTn;

    output [7:0]Data_Out;

3 _2 Q7 c1 n4 S; n9 E

reg [7:0]Counter;

8 k. R, {3 E+ u3 x$ t5 z9 ]

always @ ( posedge CLK or negedge RSTn )

    if( !RSTn )

        Counter <= 8'd0;

    else if( Counter == 200 )

        Counter <= 8'd0;

    else

        Counter <= Counter + 1'b1;


: f" t3 c; G, t1 K

reg [7:0]i;


( Q  f% k3 q# ]: `

always @ ( posedge CLK or negedge RSTn )

     if( !RSTn )

        i <= 8'd0;

     else if( Counter == 200 )

        i <= i + 1'b1;

     else if( i == 8 )

        i <= 8'd0


8 u, Z, l! i$ l/ c

reg [7:0]rData;

7 t( v& E4 X& H! E+ C

always @ ( posedge CLK or negedge RSTn )

    if( !RSTn )

        rData <= 8'b0000_0001;

    else if( i < 8 )

        rData <= { rData[6:0], 1'b0 };

    else if( i == 8 )

        rData <= 8'b0000_0001;


% W6 r! S7 b7 o% S; D/ \& O7 V/ Y

assign Data_Out = rData;


; c' c/ r! e2 O1 O  _. X, N, {

endmodule


2 Z/ \, \# H+ N! {) c' Q


" k+ K9 ]5 F: X* {0 l3 p

没错,上面是实现流水灯的代码。如果我说我要求:“ 自左向右循环3次,自右向左循环5次,然后自左向右一次,自右向左一次,然后自左向右循环30 ”。当你听到这样的要求,你可能会崩溃.... 如果按照上面的写法,你会写得很长很长。

4 i/ p' p# T; K' P

相比之下,C语言要实现以上的要求,根本就是“小儿科”的功夫。

5 R* P  A$ v% W- c! p  G& g


& n3 }. p1 ]4 I5 T1 r

    int i;

    for( i = 0; i < 3; i++ ) Flashing_To_Right();

    for( i = 0; i < 3; i++ ) Flashing_To_Left();

    Flashing_To_Right();

    Flashing_To_Left();

for( i = 0; i < 30; i++ ) Flashing_To_Right();


2 J! l: Q8 ?& }4 j8 C

% E+ g  N" O" b4 G  B; O5 _' B9 e

给自己5分钟的思考,想想我到底要表达什么?


! w$ F! Y4 s5 A, S- `. |& Z

C语言上,有“顺序操作”或者“泛型编程”的概念。从上述的代码中,for循环利用i变量,控制循环次数,然后调用3次“Flashing_To_Right()”函数。相反的V语言是“并行操作”的概念,类似的方法完全行不通。这就是新手们常常遇到的问题。

) U% j. g/ ]& Z  b- r

方法行不通,但是不代表思路不行。“低级建模”最基本的思路就是“仿顺序操作”。“低级建模”不是什么困难的东西,它只是一中的“手段”而已,只要你了解它的基本构思,它会成为很有用的工具。

回复

使用道具 举报

 楼主| 发表于 2010-6-5 21:51 | 显示全部楼层
2章“低级建模”的结构2.1低级建模”的基本结构

从一个管理系统看来,“低级建模”会是一个从上直下层次的一个概念。

http://space.ednchina.com/upload/2010/6/4/e760f799-20f2-42e9-bff5-b29e3f32ec75.jpg

从上面的示意图可以看出,老板是最顶级的,而员工是最低级的。老板从上头发号,然后经经理呀,领导呀,最后苦力集团就开始动工了。当完工的时候,一一向上报告。低级建模的概念类似如此。除了老板以外,所有经理,领导,员工的“集合”称为“低级建模”。而老板是“独立模块”,因为老板不受命令,而且也不用报告。而多个“功能模块”的集合称为“组织模块”,如上面示意图中的“永远垂死的苦力集团”

2.2“低级建模”的准则
% s4 y8 ~. K$ ]: ~6 z% @

根据上文和上示意图的分析,“低级建模”基本上有以下几个准则:

1. 有“组织模块”和“功能模块”之分。

2. “低级建模”中的“功能模块”均称为“低级功能模块”。

3. “低级功能模块”有如特点:有开始信号,完成信号,一个模块只有一个功

    能。

4. 多个“低级功能模块”组织起来称为“组织模块”。


1 E9 ~, ?: I) V

注意点:功能模块又分成“低级功能模块”和“非低级功能模块”?这话何解呢?

1 J( ?" Y; \: r, V4 i2 n0 x


1 G. \: A: T. ~% `4 X0 |$ _

http://space.ednchina.com/upload/2010/6/4/705e0fbf-e98a-43a1-86d5-4893e5037de9.jpg

从上面的示意图中可以分辨出“低级功能模块”和“非低级功能模块”。“低级功能模块”包含“开始信号”和“完成信号”而“非低级功能模块”则没有(就是这样简单而已)。

回复

使用道具 举报

 楼主| 发表于 2010-6-5 21:52 | 显示全部楼层
2.3“开始信号”和“完成信号”的作用

  l( H8 g# Y1 R, H

先看看以下一段代码:

: z+ d% W0 b) q+ o

   

   //独立模块6 ]( f* m* E( z
    alway @ ( posedge CLK or negedge RSTn )
: [9 A) y. y8 }, M! }  J     ......
7 m7 F6 j5 l7 r- m5 l2 s     else
1 T: Q8 b3 K1 h8 X          case ( cState )
+ K/ r7 L. m' _+ u, s, f
5 _! z  x: J1 L, ]1 T# w
! s/ y3 S: I4 T" c              "打扫" : & z7 ?) J, e  J. f2 ~
               if( 打扫完成 ) nState <= "洗厕所"
/ W/ N/ I6 B/ C; F& \0 p              else "发号打扫命令"2 E  P! \) I- X( O
6 H- h6 Y* A: A* a# R

) o, e8 F: d- Z' J! O" M# P( Y7 O2 _               "洗厕所" :7 l7 S. J/ ]2 X" `- x
              if( 洗厕所完成 ) nState <= "跑腿"6 m* n2 \5 h4 v, Q4 w0 _
              else "发送洗厕所命令"+ S; {9 H6 ^* V" {

' @$ g4 l, p' }# D& S7 r4 l3 r- s; z% I: S
              "跑腿" :1 G5 L4 I8 M- x% r9 M
              ......7 P' _) \2 B2 M3 a6 F, n8 y! a' N4 ?

3 m- L9 x0 P; Y$ ?; P) b8 K/ F
5 s6 H& N, {& s5 G /*********************************************************************/           
) U0 F. B) l  M7 ]( k0 o/ }
* ~7 B) k) l* }8 Z' F4 ^* V5 x% p$ E7 l6 O& r/ Q
    //低级功能模块1 - 打扫工作
8 A2 H* }) U5 N; g5 G2 _ always @ ( posedge CLK or negedge RSTn ); W4 H9 A$ d, s- k* Z
     ......- ^! F1 L1 g1 O$ Y, o
     else
) Y% S8 G' F, ~) d: u8 q         case( cState )7 o2 k; c7 w3 S( e

8 T9 C% F) n- W+ J1 H" m* A
; A# i! [: ~/ \% ^% X& v               IDLE :
+ d% B  Z; V) C4 A- f! Y, e+ [+ X               if( 到扫命令 )  nSate <= "打扫";" I. O; T7 e6 O6 U- _* `+ u0 _
              else nState <= IDLE;' U; E7 n8 H! w% o) \6 Q9 v
; y9 F7 p3 T4 z
2 v5 i# N) ^2 U
              "打扫" :8 p7 D$ o  U/ @; Y
              "执行打扫" ;
/ X/ o8 `0 h: W5 M              "打扫完毕后报告" ;
9 Y: C# e* l1 A9 L0 y: W: t              "待命..." nState <= IDLE;
' F9 H( V, j5 T                  ......1 n' g3 G1 o! M
- r# L& y. K$ e& V3 q6 o

' R& R- R( z7 n+ R" E /*********************************************************************/
& E' s4 ^1 S. v  d3 y
4 B! p! h2 j( Z% I. }
* Q" r9 k6 X/ u. f( H0 j    //低级功能模块2 - 洗厕所工作
- e2 U( T% R9 @7 d! `; \5 _/ Y always @ ( posedge CLK or negedge RSTn )( _# P! l( S+ W$ {6 Y' t7 j" V7 s
     ......+ l5 p5 ]4 s5 \% [6 C
     else if+ g& L% V; Z8 \+ Q4 l$ [
         case( cState )
! p+ k/ I9 i& g# J( M: b7 }/ d( F3 i2 M
3 Y7 Z/ j0 }8 y4 k4 c
               IDLE:
  B$ o$ K: `$ I/ W, |0 e6 Z              if( 洗厕所命令 )  nSate <= "洗厕所";4 I$ o6 H1 \7 }
              else nState <= IDLE;4 W% A  R- ~! Q
: r9 L; U3 Z$ ?' Q0 b; v6 b/ M3 T. f: A
, y! ?2 i3 Y. P( l& V
               "洗厕所" :
- V( ~+ E; u* _3 I# M$ F/ C              "执行洗厕所" ;' z% T. v# B5 z  f
              "洗厕所完毕后报告" ;- ^5 H, g9 F$ r9 R! T' ]: f* f/ ^
              "待命..." nState <= IDLE;
: I5 N* M1 z1 }8 P% q1 W; l  R              ......
* z$ k. C) @1 o0 E8 E& e9 L2 A
- t) D3 }( H: }- f" e
) V7 G+ Y' w4 O) R5 e /*********************************************************************/* ]! C% o% I5 C

9 j2 |9 N4 G6 \  R) W- c9 ?( n, S4 e# C5 T% ~
//低级功能模块3 - 跑腿工作0 q9 X* d- d% v" s. M8 K1 h
always @ ( posedge CLK or negedge RSTn )( X: a% ^3 g% V7 I" B5 c
     ......0 u. I8 N0 a! I1 K2 X  C
     else
& f% U$ _) l0 v7 q; a         case( cState )
( l. E% C. _/ S
9 a2 {" R8 V8 w7 O# |: B0 i  P7 Q$ m' d7 n& X8 ~
               IDLE:
  }' }' \8 H/ r, ^0 M* S              if( 跑腿命令 ) nState <= "跑腿";           
; d8 \; G# X. d9 @& b. k8 l1 N. J               else nState <= IDLE;1 w# @4 [/ _& E! I

: u" g" Q. ^/ G7 A9 K4 a6 Q) l( \( |& _4 ^. ^
              "跑腿" :% P- k, g5 S- L. k6 j
                 ......

$ d7 B5 P4 W" S/ Z  K; d

上面的代码可以分成两个部分,一部分是“独立模块”和另一部分是“低级功能模块”。独立模块只有一个则打工模块有三个,而且每一个打工模块仅包含一个功能而已“打扫”,“洗厕所”和“跑腿”....

注意: 独立模块不属于低级建模。

http://space.ednchina.com/upload/2010/6/5/8d7a1a60-20d3-4b06-ade3-c291dfc92b5d.jpg

假设老板有一系列的命令要发号:打扫 ==> 洗厕所 ==> 跑腿

当“负责打扫”的“低级功能模块”收到老板的第一号命令“打扫”时,该模块从“待命状态”变成“打扫状态”,此时老板可以睡一觉或者干其他的活儿。该模块便开始“执行打扫任务”,当该模块“打扫完毕”后,就给老板“报告”,然后返回“待命状态”。故老板听到“打扫完成”报告后,就给下一个“低功能模块”发下一号命令 ...

在“低级建模”的结构上,为了使不同层次的“低级功能模块”可以协调的工作,“开始信号”和“完成信号”扮演着很重要的角色。在现实中,如果 “打扫 ==> 洗厕所 ==> 跑腿”是一个有“次序的三部曲”,那么老板不可能要员工颠倒次序来干活儿 。老板得按次序,一个一个的命令员工干活。除此之外老板也不可能实时监督员工的工作状况,做老板真的很辛苦,除了“发号”以外,还要干很多事情,所以员工的“完成报告”在某种程度上可以减轻老板的活儿(使编程更简单),毕竟老板也是人,他也有疲惫的时候。


5 N5 A5 u5 E, y% N- ]+ v

接下来的话题便是:“每一个低功能模块仅包含一个功能”。


- T: ?: D, z$ K( b, ~% f

虽然在现实中,确实存在“全能的人类”打扫,洗厕所,跑腿等技能全都集于一身。但是“低级建模”的准则必须遵守。你尝试想象一下,如果一个“低级功能模块”,包含了如上的工作 “打扫 ==> 洗厕所 ==> 跑腿” 或者更多,即不是要把代码写得很长很长 ...

所以呀,“低级建模”的准则有它一定的“重要性”(在日后的深入中,你会慢慢了解的)。

1 D& `, c' }3 x( }9 Q# }/ J

回复

使用道具 举报

 楼主| 发表于 2010-6-5 21:53 | 显示全部楼层
2.4 组织的概念, l8 a" x: g# S& L, y; B, d$ |. f

“组织模块”在“低级建模”中,非常的重要。它不但简化对多个“低级功能模块”的调用,而且也解决了“两义性”或者“多义性”的问题。

* t! E% A4 f0 K' h6 n4 X

你尝试想象一下:如果有多个打工仔,散落在不同的地方。当老板要发号的时候,既不是非常不方便。同样的,在模块化设计中,设计者往往为了使使用更简单,常常都会使用“顶层模块”将多个模块“封装”到一个模块中,亦即将复杂的东西“隐藏”了起来,只剩下简单“接口”而已。这样的做法是为了使该模块可以容易被使用。

0 V" ^6 W$ ]. D4 Q: A# R

http://j.imagehost.org/0312/PIC1e.jpg


, F" Y2 F$ @6 o$ L. B3 P  Z

然而在“低级建模”的设计中,“模块化的组织”更有“层次感”。为了使“上一层模块”可以很方便调用“下一层组织模块”。“低级建模”的设计常常将一组或者一个“组织模块+低级功能模块”,“低级功能模块+低级功能模块”,“组织模块+组织模块”组织起来。虽然感觉上会有一种“杂乱感”,但是实际运用起来,真的非常方便。


% {5 h" J0 ~' \

如上面的示意图中,3个员工被组织了起来,然后3个员工的组合又和领导组织了起来。故这样的组织方法因层次关系,如此类推,最后会有两个“大组织”


4 `* D9 J. t# S2 N

组织1 = { 经理 => 领导 => 3个用工 }

组织2 = { 经理 => 3个员工 }

“低级建模”的“组织”结果会是示意图中所示。除老板意外,大家都有自己的“组织”。

% a  T5 w, W" U% f, W! A2 E

假设老板要命了员工干活,那么老板只要命令任意一个经理就行。

至于“二义性”或者“多义性”的问题,后面会讨论到。

回复

使用道具 举报

 楼主| 发表于 2010-6-5 21:55 | 显示全部楼层
3.1 模板基本结构

0 N; D. d# G  `7 z
module Template


1 X3 Z$ i$ e# R* _( d  O" l(

; `: v" s0 _3 }+ X6 h& d7 i
    CLK, RSTn,


: L% a. S2 J; w5 r    ...... ,  // "n个输入输出"

9 Q6 d/ U1 v; v, y1 p. G
    Start_Sig , Done_Sig

/ c, ~# F+ s+ J3 P# A! X% g) ]) p
);

* x  m/ W2 C/ H5 o; W( v+ W) @

       input CLK;

       input RSTn;

       input Start_Sig;

       input Done_Sig;

       ......  // "n个输出输入声明"


* p/ w1 D5 r/ {# c5 F3 ^

       /*******************************************/


+ X' y5 }* \/ t( m9 H6 r

      reg [3:0]i;

      reg isDone;

      always @ ( posedge CLK or negedge RSTn )

           if( !RSTn )

               begin

                   i <= 4'd0;  isDone <= 1'b0;

                   ......   // 任何复位的动作

               end

           else if( Start_Sig )

               case( i )9 j  Y9 D% P$ [' X

                   4'b0 :  // 一般都是用于初始化

                   Init;

                   ......   // 任何相关的步骤

                   4'b n + 1, 4'b n + 2 :  //最后两个步骤用来产生完成信号

                   Done;      
# p# ]2 y2 q; G5 a& ]

               endcase

         /*******************************************/

7 b2 m+ f+ j: P" t

         task Init;


# j2 D* C: z% h( S* S

             begin

                ......          //任何初始化的动作

                i <= 1 + 1b'1;  //指向下一个步骤

             end

         endtask

         /*******************************************/


/ ~8 W- i# @/ f% q8 N' ?9 W* |

         task  "nTask";

             .......          // "nTask的执行任务"

         endtask

         /*******************************************/


) s( r. \. |4 k" A3 y

        task Done//产生Done信号


5 Q' Z. R* w  C4 D

            if( isDone == 1 ) begin isDone <= 1'b0; i <= 4'd0; end

            else begin isDone <= 1'b1; i <= i + 1'b1; end" k6 U0 h4 l+ x0 S9 O; X0 P

        endtask

        /*******************************************/


+ \+ ]( H. r6 n% w( Z9 t. L6 P

        assign Done_Sig = isDone;

        ......  // 相关的输出

    endmodule

从上述中,模板的基本结构有以下的特征:


) f% J* J) h1 U  E! g! \

1) Start_Sig Done_Sig是固定的。

2) 寄存器i用于控制次序步骤。

3) 最后两个i步骤用于产生完成信号。

4) i 等于 0 的时候,多半都是用于初始化动作(选择性)。


* N* I; u  g. T! P/ O8 W2 U

正如准则的要求,“开始信号”和“完成信号”都是必须的。“开始信号”可以视为“片选信号”而“完成信号”如字面上的意思。寄存器i有一个重要的功能,它指向任何下一个步骤,而通常所编写的格式如下:


5 E- I& q( |1 Q6 w' j9 w! T

5 A9 V9 p1 Q6 z% E" Q
i <= i + 1;


! R2 R1 w7 I: y5 s

除此之外该模板还引入了 “task - endtask”。目的是为了提升和 “结构性” 。新手们应该知道,使用V语言如果没有良好的编程风格,代码的 “可读性” 是非常的糟糕。

. v% R7 ?$ e- S3 L) [

在这里我先简单复习一下,“task - endtask” 的用法 :


! _% k& b: @9 k& A& V' m/ u9 M

) \( u' P5 Y) d5 G1 l" V5 R) l7 s
  reg [3:0]i;  reg isDone;  reg [7:0]rData;  always @ ( posedge CLK or negedge RSTn)  if( !RSTn )      begin          i <= 4'd0          isDone <= 1'b0;          rData <= 8'd0;      end  else; y( ]' n" D, Q( B1 K" E- v: O
      case ( i )" g$ R5 V1 n7 x. B  Z0 J
4'd0 : i <= i + 1;              ......      endcase

$ X; x5 P. r: r4 G* P0 o7 t
% L9 T2 T( Q: d9 N9 F" H; Y5 hreg [3:0]i;  reg isDone;  reg [7:0]rData;  always @ ( posedge CLK or negedge RSTn )  if( !RSTn )      begin
( C: ]6 P) E9 Hi <= 4'd0;          isDone <= 1'b0;          rData <= 8'd0;      end  else      case( i )6 e1 s( S" Y" A9 `- _. D
! [, a, U9 B& f/ f* m
4'd0 : Next;          ......9 ^. c9 f/ x. k' D8 {7 u5 ]" M
      endcase
/ e4 N( b$ {$ X- f6 Y" X! u% I /**********************************/
3 U- @) C: X4 b% c& [+ l  task Next;   r4 o0 @/ \% T# m% P
) `+ i( b5 C/ R) }
i <= i + 1'b1;0 O9 b" p- a  q# ]7 y* M) v
  endtask

& L! C) P; e# c3 n% i( `) y1 v3 J3 h5 W

上面的两个写法都是等价的。如果模块是小功能,那么左边的写法很适合。但是一旦模块的功能很复杂,那么右边的写法会凸显出优势。- Q1 A. S( {+ z+ K7 R

2 j  r6 h8 [7 [$ Y" W
回复

使用道具 举报

 楼主| 发表于 2010-6-5 21:55 | 显示全部楼层
3.2 建议4 u# M% l6 g2 n) Z: e

为什么需要模板结构?


" r' J2 u* A& L" Q8 s6 `$ _6 ~: O

创建代码的工作往往都是一次性,为了供人参考,或者为日后“升级”的打算。我们不得不养成好的“编程风格”,这也是许多参考书上提出的重点之一。而“模板”便是一种已经制定好的“编程风格”,故这样会简化了编程风格上的问题,只要加以修改,便会完整一个有“结构”和“有风格”的代码。


1 t+ @5 L1 z; }1 i

为什么“低级功能模块”的步骤,需要一个计数寄存器来指向呢?

% o5 ]7 Z: }) O0 c  M, s

其实这个问题我也考虑了很久,因为是“仿顺序操作”的关系,故人类对“1, 2, 3 ... ”类似的次序(步骤)有更直接的效果。而且也很好的为代码扩展。


: o( v% _. O! o) Z/ V

编写“低级功能模块”时,必须遵守笔者提议的模板结构吗?


  q. ~: X2 ^& a% q0 M; U3 m# q

模板的结构只是一个参考而已。该“模板”结论是我经过不同风格的编程,得出“最通用”的结果。当然你可以无视我的规定,完全自定义自己的模板结构。但是有一点请注意,必须以“解读性”为优先考虑。因为好的代码不是在“执行效率”上,而是“可维护”和“被解读”。

回复

使用道具 举报

 楼主| 发表于 2010-6-5 21:56 | 显示全部楼层
4.1建立2个“低级功能模块”
$ l& Z) ^9 P) G; u, O- S" Z

“ 自左向右循环3次,自右向左循环5次,然后自左向右一次,自右向左一次,然后自左向右循环30

2 q' o+ m: K2 J9 ^$ b

假设这是实验的要求, 首先我们先建立两个“低级功能模块”。一个名为flashing_to_left flashing_to_right


) U6 W0 s$ g& M: @& Y$ I7 }

1.module flashing_to_right

2(

3.    CLK, RSTn,

4.    Start_Sig, Done_Sig,

5.    Q

6.);

7.

8.    input  CLK;

9.    input  RSTn;

10.    input  Start_Sig;

11.    output Done_Sig;

12.    output [7:0]Q;

13.1 ]+ U8 y. d! e9 Z( N

14.& r2 @' U9 [8 G" j$ Q
/***********************************/

15.3 }) {6 \# w2 P) f  J, F4 E

16.    parameter DELAY = 8'd200;

17.
" H, m% D0 I4 `/ c9 R" Y

18.7 h. ~' G5 I5 j5 S' i9 v- C& v* o9 B  j
/***********************************/

19.
6 C1 z# ?3 O5 u$ g- b

20.    reg [7:0]Counter;

21.. g  P: \# x! U3 T" N

22.    always @ ( posedge CLK or negedge RSTn )

23.        if( !RSTn )

24.            Counter <= 8'd0;

25.        else if( Counter == DELAY )

26.            Counter <= 8'd0;

27.        else if( Start_Sig )

28.            Counter <= Counter + 1'b1;

29.        else

30.            Counter <= 8'd0;

31.
+ L: L3 ]: V. ^0 Z3 {

32., `9 y6 f- U8 o  K" t
/***************************************/

33.
8 y! \$ [7 g4 k) t

34.    reg [3:0]i;

35.    reg [7:0]rData;

36.    reg isDone;

37.8 @; {9 V: q, Q. G( ]

38.    always @ ( posedge CLK or negedge RSTn )

39.        if( !RSTn )

40.            begin

41.                i <= 4'd0;

42.                isDone <= 1'b0;

43.                rData <= 8'dx;     

44.            end

45.        else if( Start_Sig )

46.            case( i )

47.
! I) d/ z! O" F, z  n, ^

48.! I, M1 p5 D2 \  z; _

; O3 ]( A6 j1 ~  N: G7 b
: y0 x2 U3 S6 J. ^; m
' c' E% q+ F9 `- S! b4'd0 :

49.
# V. ?" T8 E+ N% Y
begin rData <= 8'dx; i <= i + 1'b1; end

50.
. D, }% n/ Y! N6 ?( Z; R# _" X! N/ |: E% k
! y4 t* v* a5 d4 [1 T. }$ D3 {) d

1 u! a8 `  ~) g0 k8 E+ ~+ p

51.
, |; i1 |! D0 e9 s

0 K  \! J3 q* d& ]; b% H2 U  f- y+ ?$ U1 k, r- `1 o2 M& d
0 o& j6 E* {% }; w5 z
4'd1, 4'd2, 4'd3, 4'd4, 4'd5, 4'd6, 4'd7, 4'd8 :

52. . `! P; V  _6 h; Y& n4 @

2 s/ Y4 i8 s+ a" @0 [& ]" t1 m
2 p1 Y3 G8 B3 }8 U. Z5 M% E; a( S  l$ X
if( Counter == DELAY ) i <= i + 1'b1;

53.
' C1 R# R& B* h/ e, o6 m% ^

4 S5 G* Y8 L$ C$ n6 Y5 M6 {& w& ]; F. _/ F  B3 Y

0 G5 N4 L: k3 D+ }! Q$ X9 kelse rData <= ( 8'h80 >> i - 1 );

54.
% i) ]# c0 U' p# X. P, h* F7 }. V% @- ^: d" L
& V* N) h3 L/ b- ^3 a* p# Y

5 S" }  q  M% r4 q) ~" E# \4 ?# t! j7 }$ t

55. : }8 k! }6 d3 z

; f4 N4 B/ b6 R& }- s
0 i+ V; ~- @4 N$ a( i. a1 h  A" U& M4 y0 j0 c$ s: i6 t* s
4'd9 :

56.
0 x8 u2 c6 i- }! g" g+ j, `

  N7 o# A2 M- m, c+ w0 c& M3 H5 J& U

6 N0 j' v* Q4 t" L2 S+ z( N# A0 Z+ y# Z& g3 _, j8 f9 q5 s
begin i <= 4'd10; isDone <= 1'b1; end

57.
: a) V; ~: B7 F9 F. R; I. d
" C$ H5 |. D* T8 I9 v# C9 {3 g# x" X& P  l2 `# k7 {* R

( Y0 F! \* J8 b& x% h

58.
, F1 \6 j; k& ?$ M
" c# o# y# a& o  `7 ?  O0 v- ^

& M+ F2 Q7 p' A3 b/ t; C. A
3 i/ k6 |7 f# l2 p3 w6 _8 i1 r# F4'd10 :

59. 5 {0 E- E& w: L1 t$ |6 F; r( Q2 e  w
) \5 P  i  [  X  z  T9 c
$ d8 m- P5 C& G- J' _' e3 J
" l+ f0 h1 o: B( p
begin i <= 4'd0; isDone <= 1'b0; end

60.& ]3 o" d: R8 d0 i# z! }2 {* S+ M
1 @2 v3 V/ W5 p4 J8 ]9 s

# l3 R7 N' n5 J* @) a( B( `" B
( K6 U- G+ g3 t7 N0 H5 N# k) N

61.            endcase

62.

63.# G: A3 a4 F5 {1 H. J) [0 h  X3 L

64.5 B! V4 w  g8 k$ b
/**********************************/

65.

66.    assign Done_Sig = isDone;

67.    assign Q = ( i > 0 && i < 9 ) ? rData : 8'dx;

68., V5 Y2 V3 ~2 c2 Z1 d% x. F

69.  A! w- |5 f  j* W1 q  s
/**********************************/

70.

71.endmodule

' H, E5 ]' O+ P) e


, E: J+ q; B  t/ P! _

1.module flashing_to_left

2.(

3.    CLK, RSTn,

4.    Start_Sig, Done_Sig,

5.    Q

6.);

7.

8.     input  CLK;

9.     input  RSTn;

10.    input  Start_Sig;

11.    output Done_Sig;

12.    output [7:0]Q;

13.
3 }7 v! @) |# N

14.
( V, H$ L4 ^/ B: i& y /***********************************/

15.
5 ^' j! D8 ], U3 D) X: o

16.    parameter DELAY = 8'd200;

17.
4 c  x2 h, C. G6 S5 `

18.) x$ v2 g/ S! `+ U6 D! ]: j* y3 `
/***********************************/

19., S6 f- w8 Z3 J) S

20.    reg [7:0]Counter;

21.' Z6 L  W9 x) s( y

22.    always @ ( posedge CLK or negedge RSTn )

23.        if( !RSTn )

24.            Counter <= 8'd0;

25.        else if( Counter == DELAY )

26.            Counter <= 8'd0;

27.        else if( Start_Sig )

28.            Counter <= Counter + 1'b1;

29.        else

30.            Counter <= 8'd0;

31.
, {7 N2 I. [( i) |# I1 A( p

32." o$ R( r1 E1 I$ e, U* E3 R5 @$ @1 B
/***************************************/

33.
3 H, U  Z* d0 B; p

34.    reg [3:0]i;

35.    reg [7:0]rData;

36.    reg isDone;

37.6 z: N/ o5 F' e) L

38.    always @ ( posedge CLK or negedge RSTn )

39.        if( !RSTn )

40.            begin

41.                i <= 4'd0;

42.                isDone <= 1'b0;

43.                rData <= 8'dx;     

44.            end

45.        else if( Start_Sig )

46.            case( i )

47.8 B+ g/ h+ n! ?8 ~

48.
7 W* C" Z8 M+ |: \) s
% M! s2 _; c, {1 s

5 K# g0 a" W0 _8 T! p* E( Q2 x+ Z# H) b! i
4'd0 :

49. ( ~; J0 L' b9 c  f/ ]6 n$ n2 L

; H6 I1 l  T0 s" N: w2 p& E2 f( }1 G- k0 A7 D4 H3 w( e  }

2 F8 L) O- E6 x* [. n1 [begin rData <= 8'dx; i <= i + 1'b1; end

50.: |7 f2 W! Q6 b0 J% l, q$ Y
. ?: t- Z3 e6 W
) N; c# P$ q" h- _7 i# ]3 q1 {

: I6 _0 m' E: f$ A& o8 t

51. & ^, X1 [: ~8 n$ c" h2 M% O

5 T+ G$ T+ c5 D( V& s' @1 q: b0 X$ r  V8 f8 P4 A- }: g# S, b/ ~  y

( C: t+ `1 D/ j) G4'd1, 4'd2, 4'd3, 4'd4, 4'd5, 4'd6, 4'd7, 4'd8 :

52.
1 I" Y; |7 b4 F8 A# x
$ T/ f! h# r% Y& V3 X

- K/ T4 I$ K; s7 E
) ~7 p, k6 U" V
0 P' h) G4 a  X1 N/ h8 N( kif( Counter == DELAY ) i <= i + 1'b1;

53. 9 v$ `5 `6 S9 k+ f! @; j
$ B4 P% z( l" S' x5 z
* Y& Q: Q5 K3 E3 X0 d: f! I

+ x2 V8 G/ r. C* d$ Pelse rData <= ( 8'h01 << i - 1 );

54.
& g: e" s7 P+ |3 E$ B2 }4 w3 |7 K* N+ s# ], l- N4 z4 [
2 k( l% O! ^; w  }2 b1 {
9 y  Z& q1 q1 O) e" ]; ]; s
6 y) P( x# ^# U  x' Q3 D

55.
  C4 }+ w/ m( V7 q/ q

/ j4 P1 z" e- C/ P
0 B( }0 Y2 b. M5 \
! r3 F, e4 q! |' s8 x4'd9 :

56. ( O: w7 _$ q- n7 N" ?

: `6 m4 }0 Q! Y  a! O
& A" y% M/ J3 F9 C# s6 Q9 t1 `% {: [+ `+ p" u1 C! l5 S" e
begin i <= 4'd10; isDone <= 1'b1; end

57.
" w" ~& ?+ D$ W) W; R% l0 Z9 H/ N+ J' q1 B

* d, {) m4 y8 X( H
6 I4 \: @; f/ {2 h# O! w$ }

58.
/ P9 F5 N# y2 g" l0 @
3 o% U3 N7 S0 |

7 U: z# e8 x- h- v% u5 t/ n$ Z1 i
& j" m; y. M) r2 a' t6 U4'd10 :

59. " D3 B; b5 \4 u
% S9 V/ J6 q+ l- ?' o. F2 r2 l2 n

6 o; f, K- [% D1 Y# e+ _% A' p' T& l" v: u0 e" u3 ~
begin i <= 4'd0; isDone <= 1'b0; end

60.
! j; e4 t  g6 w; I7 M
  }- A0 F, j. B+ K) s6 ^
' X$ D9 @4 v- K6 {7 I5 V: b: V
8 Q5 I# H6 A1 d; e: W# p

61.            endcase

62.
8 N- y4 I1 S) O7 J9 l

63.
2 A5 z1 F, I+ R3 o7 N; q" Z /**********************************/

64.

65.    assign Done_Sig = isDone;

66.    assign Q = ( i > 0 && i < 9 ) ? rData : 8'dx;

67.4 o7 g( B5 P  V6 S. a9 a

68.2 ~; V% t: k3 |1 U& a& r
/**********************************/

69.

70.endmodule

两个模块几乎是一模一样,不同的地方只是在 53行而已。虽然代码都很简单,但是还是稍微关心 45 ~ 61 行的代码,因为是功能的核心部分。正如模板结构般,在第45行,如果Start_Sig 不处于高电平,那么该模块根本无法执行功能。计数寄存器i使用与指向下一个步骤,正如在第49行,当rData 被初始化过后,i指向下一个步骤。

1 W& G; c2 h8 k" h( b, I

51行到53行之间,是移位操作,每一次的移位动作都需要200个时钟周期。移位操作一共有8个步骤。最后该模块产生一个“高脉冲”以表示“完成”,然而i也被复位为0


3 d3 G3 Q& [+ x% }" x- f$ B

仿真效果如下

http://space.ednchina.com/upload/2010/6/5/a27937ce-915e-4ed0-9e21-7a1e0b72070a.jpg

(第一行是输出Q,第二行是Start_Sig,第三行是完成信号)


5 |9 T& F' ]" }2 I& Z

' o! P' E4 S4 v7 K
# h& @* ~# V& x- [5 c* m4 ^( v; \

( 最后一行是完成信号 )

http://space.ednchina.com/upload/2010/6/5/dbc4e2e6-fa71-46aa-8cdd-9c8d94da7a39.jpg

# F6 \" K9 |. [9 r

注意最后一行,当i 计数从1~8过后,就产生一个完成信号,而完成信号需要两个时钟周期的时间。

+ h) y- x$ |" q5 V2 \
完成创建2个“低级功能模块”以后,为了使日后调用方便,必须封装起来。“低级功能模块”的封装工作会比较麻烦,因为“低级功能模块”有“复用连线”的现象,换一句话说,会出现“两义性”或者“多义性”的问题 ......
回复

使用道具 举报

 楼主| 发表于 2010-6-5 21:57 | 显示全部楼层
4.2 “低级功能模块”封装 和“两义性”或者“多义性”的问题

http://a.imagehost.org/0020/PIC4_3a.jpg

如上的示意图。当我们要封装2个“低级功能模块”在一次,如果两个“低级功能模块”使用同一个输入(重用输入连线)或者同一个输出(重用输出连线)就会出现两义性的问题。为了解决这个问题,使用“多路选择器”便可以。


7 z% w  H* @8 e( T, A# I( Q% w

1.module flashing_module

2.(

3.    CLK, RSTn,

4.    Right_Start_Sig, Left_Start_Sig, Right_Done_Sig, Left_Done_Sig,

5.    Q

6.);

7.! ~2 ?. p7 r0 S9 d3 E% B

8.     input CLK;

9.     input RSTn;

10.    input Right_Start_Sig;

11.    input Left_Start_Sig;

12.. e2 b6 x' h/ Y! B9 u

13.    output Right_Done_Sig;

14.    output Left_Done_Sig;

15.    output [7:0]Q;

16.
" x1 A% E$ w- f& T6 Q) l; X

17.
% `& f; Y( o$ z /*******************************/

18.
! k/ ~  A, T. p5 n( g' Q6 d

19.    wire [7:0]Q_U1;

20.
2 p/ N" u; q9 H5 P; B  v4 {

21.    flashing_to_right U1

22.    (

23.        .CLK( CLK ),      
7 \+ v' u5 T# }
0 S4 ]7 F- O. [; r
. g7 [% @4 e: f0 I: W! E// input - from top

24.        .RSTn( RSTn ),
9 i& {4 T. o. ^; ]% \
4 j, {) X/ s7 L) v7 Q! u0 {$ S6 ~- p8 @- v

/ ?& u8 @1 Z! I) z: R' J
9 ?! g! m2 `: o// input - from top

25.        .Start_Sig( Right_Start_Sig ), 8 U. B4 w  @8 `) O8 \6 B# A
// input - from top

26.        .Done_Sig( Right_Done_Sig ),  // output - to top

27.        .Q( Q_U1 )$ b8 |+ Q+ `9 v( z- X( h7 z( ]

$ b6 r2 D- f& P$ o2 g1 t5 ]
9 O' S+ {+ ~8 f) K9 W  b# |$ h6 L2 @7 \& _7 R6 M: T

5 g* D' c2 g% A/ j. ^) g" Z
& U- c- j2 v, Y# _5 `// output - to wire

28.    );

29.
/ o' n4 y1 r( N& l. W# L

30.
7 W& M8 w' u, f  V/********************************/

31.
( m/ U" Z# O; g' ^9 z5 ~

32.    wire [7:0]Q_U2;

33.
( r3 ^0 t( R/ x- P# i$ D

34.    flashing_to_left U2

35.    (

36.        .CLK( CLK ),           $ M! u3 R3 l7 ~5 A
# I# f8 ~6 @# b3 ?* T7 @% _5 Z
// input - from top

37.        .RSTn( RSTn ),            
9 ~* @; ]3 n1 F8 h// input - from top

38.        .Start_Sig( Left_Start_Sig ),  " S* r+ U) S7 g- y  x/ N
// input - from top

39.        .Done_Sig( Left_Done_Sig ),
! K8 n: w. h) A1 Y4 R/ ]; _  F// output - to top

40.        .Q( Q_U2 )
  U5 r: D  x( ^8 c0 d) [0 X/ e2 Y  p& ?

; R, N7 {" Z, _+ R
  G% i. W/ W8 W- [5 H$ L# a
. }$ [0 g0 L+ d6 z0 U! Z4 ^
' k9 n6 N2 B! c' r9 P// output - to wire

41.    );

42.  u" g/ R& G8 v- _( T

43.
% ]# T8 B7 }0 H) A/*************************************/

44.
* {, x7 y# ?' u7 }, {' W5 E

45.    reg [7:0]rQ;

46.
8 f0 Y/ H* N5 a8 e1 e+ y, i) X2 Y

47.    always @ ( * )

48.    if( Right_Start_Sig ) rQ = Q_U1;

49.    else if( Left_Start_Sig ) rQ = Q_U2;

50.    else rQ = 3'dx;

51.
+ Q: g& H: K# R% C- G3 b, j: r( G

52.    assign Q = rQ;  

53.
+ z. b) f, f( c" J* y

54.# O7 k: n8 Z: S! C3 r' a& C# U
/*************************************/

55.2 ^# m3 b3 q" }( U

56.endmodule   
- \; s) K. v; j( m5 Q  g6 g


' s; P/ y. ^7 n4 `: w

9 L5 _/ G. y8 J1 x) s$ R6 q! Z

为了解决多“两义性”或者“多义性”的问题多路选择器常常被使用。如上述代码中45~52行(从第27,第40行引出“连线”)Q_U1”和“Q_U2”被if控制着输出。这样的写法是最优化的,生成的RTL图也非常的整洁。


1 r! g1 S3 _5 p# r; H

http://space.ednchina.com/upload/2010/6/5/0f6b6eb3-8c6b-4af8-bcdc-6946a733b70a.jpg


* P' C5 ?' T+ }8 ^1 A

当然还有其他的写法:


; q3 [! C5 w6 M% [

assign Q = Right_Start_Sig ? Q_U1 : Q_U2 ;


) U$ n- f0 f# M( X

虽然如上的写法和,第4552行的写法相比,更为简洁,而且生成的 RTL图也一样。但是这样的写法有如下的弱点:


4 ]# Z; _" R3 o  q

1. 解读性很差。

2. 只能解决两义性的问题而已。

' }. q2 x$ e- H

所以不怎么推荐使用。


/ C( P( l1 ]: X

还有一中更糟糕的写法:


8 E0 ^, p7 x3 T2 X8 m$ G+ }2 d; R

    reg [7:0]rQ;

, C. `- _7 p5 I8 ~% g9 q

    always @ ( * )

    case( { Right_Start_Sig, Left_Start_Sig } )

        2'b10   : rQ = Q_U1;

        2'b01   : rQ = Q_U2;

        default : rQ = 3'bxxx

    endcase

$ D& M% h! h2 B& J4 s

assign Q = rQ;

虽然该写法的解读性很高效果也一样,但是却很浪费资源。生成的RTL图如下:

. t5 ]) N! r- {8 Y

http://space.ednchina.com/upload/2010/6/5/2f9ae0c3-d220-4ce9-b86b-ebf273901983.jpg


, x- w% j( |+ M& ?+ o

和上述两个写法相比,它可差多了,所以不推荐使用。

' g+ P' ^2 [: ?6 Z! Y

/**********************************************************/


& C  a1 |6 b7 X  }) Z# C

    reg [7:0]rQ;


( V* B* X" w5 t& l9 e& y

    always @ ( * )

    if( Right_Start_Sig ) rQ = Q_U1;

    else if( Left_Start_Sig ) rQ = Q_U2;

    else rQ = 3'dx;


: M+ X% C8 M' g8 c' P

assign Q = rQ;  

3 l4 n! c+ d" K# S


) r9 n# X6 }; b9 j+ V. t

接下来,我们来分析上面的代码。


- j5 U$ q* h7 N5 a7 }  s


# A+ A# U' R$ V3 H* B9 R/ w

    always @ ( * )

2 E. L% z. h! c7 K- Z


2 C. r* B7 E" ~9 d. h0 f

always @ ( * )”这样的写法在Verilog HDL 2001 中已经被支持(好像是这个版本)。在敏感包中的“*”,可以理解为“任何状况都有效”。


1 F3 O. A2 T) a


6 g% ^6 c* U8 U# `& K/ T

    if( Right_Start_Sig ) rQ = Q_U1;

    else if( Left_Start_Sig ) rQ = Q_U2;

else rQ = 3'dx;  //不能省略掉

0 P; w1 f" Q) g+ `! g- G  V

7 M: j% c" l& W1 }7 b$ L# M  s

而“else rQ = 3'dx”,这行不能被省略掉。不要问我为什么,这是V语言的编程规则。你尝试注释掉后,再编译看看,你会发现会很多“Warning”。

2 v9 m& E! ?& l' t


1 j8 q9 V3 A; I( q

       always @ ( * )

1 m! L# s- s' g- \
x   if( Right_Start_Sig ) Q = Q_U1;//连线 QQ_U1 Q_U2 之间没有


( Y; f" ?; ]7 Y6 V, v2 A9 ax   else if( Left_Start_Sig ) Q = Q_U2;/ A; G. p9 R& v& P! r" G+ \
//寄存器驱动

. ~7 ?  T1 j1 H/ V% C
x   else Q = 3'dx;

4 V8 l9 \# y+ P

还有一点请注意,因为“Q_U1”和“Q_U2”是连线的关系,所以必须使用寄存器来驱动。如上的代码中“rQ”便是扮演这样的角色。如果该寄存器被省略了,会出现编译错误。

% A2 d+ ^9 {  W, R! c4 x

总结:

“两义性”或者“多义性”的问题,不仅在“低级建模”中出现,日常的建模也会出现它们的踪影,然而“低级建模”出现的频率比较高罢了。“多路选择器”在设计的时候应该经多方面的考虑,亦即取得最平衡的效果。


2 `" V! t( I" k- n' Y' m4 L8 |
回复

使用道具 举报

本版积分规则

QQ|一淘宝店|手机版|商店|一乐电子 ( 粤ICP备09076165号 ) 公安备案粤公网安备 44522102000183号

GMT+8, 2026-4-19 16:27 , Processed in 0.046233 second(s), 27 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表