一乐电子

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

QQ登录

只需一步,快速开始

微信扫码登录

手机号码,快捷登录

手机号码,快捷登录

搜索
查看: 9914|回复: 14

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

[复制链接]
发表于 2010-6-5 21:48 | 显示全部楼层 |阅读模式
好东西尽收其中 这个是转以下这个仁兄的  akuei2's Blog, t% ?$ Z* r# K  S7 n6 q
[Verilog HDL 建模技巧 :低级建模 仿顺序操作 · 思路篇] 1 - 封面+书语
2 W  o+ S0 |3 M8 Y* G
: g2 U  j6 G! }; C* Q/ B. A4 V3 p3 l

5 o- o8 Z9 U5 j8 W) f8 I+ ?4 t: H书语:

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

7 q4 C; F2 T# l1 v  z. U+ `

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

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


+ K% L- g; h8 z$ y# F# `# v+ E

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

8 ~5 {' G" W3 _8 X8 m, E

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

! V1 r' L+ ^: ~1 M

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

* T$ E7 O6 h/ j$ ~3 q

笔者的话:

, g) B# N  V( }! w# P1 |) t' `

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

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

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


1 O( `( U: Y# h, i& R

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

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

2 |" |8 B1 Z) m% c+ f) O

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

: I0 D& ~  a% l9 P6 W0 @" b8 J

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

& v/ d( x! J* i6 [; y

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


$ n% G8 G) N$ I0 \$ s4 T

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


; Z* J) L2 D0 B6 C/ {

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

$ o6 }. n3 n* T  A  C, }3 x8 y

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

回复

使用道具 举报

 楼主| 发表于 2010-6-5 21:50 | 显示全部楼层
1“低级建模”的思路
- G1 q3 X# m3 `9 K/ D/ M% C

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

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

) d( R& e& [& |" t

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

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

: ]. R4 K: W. I  o6 T2 |

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

; J) h; ]6 ^, _0 L4 d* i

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


2 J. I9 Y0 m: N" ?2 z

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

) l0 q2 l1 m, ~. v& X) W' l

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


  D" _7 b: @+ z: _


. ^1 p) D9 Y2 d/ \7 ]

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

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


9 w9 U; i( ]+ u3 B

' O/ h0 e, W% D% X

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

1. 永远自右向左发亮。

2. 永远自左向右发亮。

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

/ c8 i$ V4 S& ]4 l) T. v

那么可以这样写:

0 i  _" l9 ?- Q

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

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

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

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


/ m4 k: Z4 N; B

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


& v0 w& I$ x' d1 |# I/ O

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

' P* v. b/ a7 W9 |0 f


$ M! u* b& F7 G2 Y+ G7 \

    module Flashing ( CLK, RSTn, Data_Out );


- e' p/ U% W- u" b% U, z& E

    input CLK, RSTn;

    output [7:0]Data_Out;

- L8 k  b$ i) a, a1 S0 z+ Y

reg [7:0]Counter;

  {$ v! F" D; ^" d# [' t; Q2 x

always @ ( posedge CLK or negedge RSTn )

    if( !RSTn )

        Counter <= 8'd0;

    else if( Counter == 200 )

        Counter <= 8'd0;

    else

        Counter <= Counter + 1'b1;


  f6 F4 c% c: e2 |6 r0 A

reg [7:0]i;


1 B' t( H, S/ E$ M# S% o1 O) U, j

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

" z3 U& _0 h2 V# o; e

reg [7:0]rData;


4 E# {; _* s/ K8 l* M

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;

2 y! E4 ]' w# ?; M1 T3 W4 S2 {

assign Data_Out = rData;

$ h* w, j" b( T9 ~4 ^6 J

endmodule

/ t% z3 t) ~% `


7 H$ W7 {& J* G9 c! J

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


: J+ O/ X/ f6 ]9 \

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


. u% @/ m+ i! E3 M0 C4 k


1 d9 F1 L. _% e" j* A( H7 k

    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();


$ E) H* k( b+ r+ A


3 _3 w. N, `- C# ?/ f3 d$ h

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

* y3 p6 Q$ D# D  p9 P

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


3 p" C+ U. ^0 s

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

回复

使用道具 举报

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

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

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

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

2.2“低级建模”的准则
  J9 E* M9 E  U. U7 e

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

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

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

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

    能。

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


4 Q( D- v3 q3 i% a0 H) e

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


- d* c( _5 A. r0 C9 b( ^9 z9 K8 b

0 q4 h* b0 f' F/ H8 ~5 [8 }

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

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

回复

使用道具 举报

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


9 r+ d1 V3 \5 r$ a  E! D& U

先看看以下一段代码:

' t% U8 Z  u2 ~& ^8 C' E

   

   //独立模块
" i2 E* g8 |; y8 C. k    alway @ ( posedge CLK or negedge RSTn )2 j* I- a' W( b* u# u. X. Q+ g3 A/ z
     ......1 I& \" `  ~3 Y/ F, E+ i& V" ]
     else5 _( U2 H/ x8 w0 m2 i
          case ( cState )
$ m% E0 Z; h  ]) N9 L4 Z
7 B& i# A+ R, U4 w" i1 s
/ d/ _7 t  ~  H% i0 n4 G+ f9 A              "打扫" :
+ E3 i! V0 X' D7 e  M               if( 打扫完成 ) nState <= "洗厕所"
  R1 M) e" m3 u4 ~7 c$ |; B7 ~              else "发号打扫命令"
% \/ Z& M. I7 \  y
/ k$ j; X: m7 K% Y0 ]$ @1 S& g+ \# P4 O5 O* x
               "洗厕所" :8 R0 H. I) n5 U5 F. g3 z: z
              if( 洗厕所完成 ) nState <= "跑腿"' t  m; B& t* F/ s
              else "发送洗厕所命令"
  C/ Y9 y( t9 g7 b  Z
6 c' H, B" b, ^) O! Q5 s3 D2 |' o  l. r$ u1 q# c
              "跑腿" :
0 M6 C( p/ X% `# j$ @) V9 X              ......
. D! F. P, }0 t, f  t6 w: F% }* s: A
; C) F$ _* x  A# l& D# D- r
/*********************************************************************/           ( c+ p$ b4 V! f* N  D3 \
' R7 f( a" {6 w! o) T9 d5 u' T

, E- C6 E, `& `. i- L7 e! A    //低级功能模块1 - 打扫工作- m7 L2 N; v2 }  t( N
always @ ( posedge CLK or negedge RSTn )# `# `) U$ S/ K) A
     ......  [7 z2 o* u1 d4 [" H
     else
' I( `. V8 i! s* p( x         case( cState )0 ?. w* ]( K( r" s: K- K0 [1 i
2 g$ m# @/ W) x$ W0 |$ b% O3 i$ Y" O9 b3 S

; I! _% X: b- j- h  k0 M               IDLE :
; o7 ]0 @0 J! ^               if( 到扫命令 )  nSate <= "打扫";
/ S2 ^( V& L7 Q              else nState <= IDLE;) [6 o0 u" I8 B6 N/ v
6 P1 r) A1 i- J* Z

! X9 }( R& x; M7 H2 R  z* R              "打扫" :, g9 l% N! ^  M& c( m
              "执行打扫" ;
3 {! ~# t- a3 C              "打扫完毕后报告" ;
4 S+ b" n# o1 f( ]2 P# V+ D2 K              "待命..." nState <= IDLE;- G% b- Y, \  J$ x7 s! _7 h
                  ......3 d. a' x, H  |- }, A
5 m' U! b& _# t3 M$ C) v8 V
  V' y. R' g9 m+ Y$ D
/*********************************************************************/# p3 _) B4 H6 o4 m" x
9 i& t  t1 l. J) b

. e" a) f$ `. F    //低级功能模块2 - 洗厕所工作
; Y, K. o1 G" ^6 r always @ ( posedge CLK or negedge RSTn )
2 ]+ c; f( R; d" X0 U; }. g/ K. q2 z8 k     ......
4 m  X; I* N. u4 X; Y1 c" z     else if
+ H3 C1 \' s9 Z4 ]; b) x. {         case( cState )6 o2 G9 w: G8 L; h; q8 s

+ D" O  T6 k& r# V( Q' [/ |: s6 ^$ k$ r" j
               IDLE:
2 U/ v. _# U8 \              if( 洗厕所命令 )  nSate <= "洗厕所";6 M% e* t) M) [. \% F0 U
              else nState <= IDLE;
4 d! Y. ^/ s4 F. Y  i' J6 o2 H; G+ L3 `- @5 @" E/ }" ~+ T
) n) N: S3 G6 b+ l6 E* ~! R
               "洗厕所" :! Y, I5 i4 T* R/ @8 i) y3 K
              "执行洗厕所" ;+ m$ F4 L- W$ Y: G$ r
              "洗厕所完毕后报告" ;) M! @. T) z! u! i' R' \
              "待命..." nState <= IDLE;' @8 a  K1 s1 t2 x4 \# b
              ......
1 a. U. a2 }* e* P" i  k- ~8 m! G% x$ h3 i# u2 [; N+ z

$ q) {8 s) ^4 G, p3 x  K, ~ /*********************************************************************/
3 J9 O% R/ Y$ N- e1 |% `4 q; t  [  L3 q# D' g# L

7 ?/ u$ \# a# T //低级功能模块3 - 跑腿工作2 L- a  S# A; E5 o* N
always @ ( posedge CLK or negedge RSTn )
" t; f* Q. l* P* T, R0 x% ^( b( }     ......
, `! o2 o8 k; w+ ~9 E     else
* n3 u* q% Q4 S% L5 g' k0 S         case( cState )/ H5 s: k, r. o6 |
4 \( y8 e  N" }, n3 M8 \
/ K& y* i- O$ ?: z/ ~- C* x
               IDLE:
5 R; I, I8 @: i2 `1 ]              if( 跑腿命令 ) nState <= "跑腿";           
& v9 ]2 R2 }7 a- |! N) a               else nState <= IDLE;! ]1 T+ A* x: {
5 L# O( O7 F  k' @; H& y2 t
1 T" p; s& G- V5 M
              "跑腿" :
- @9 C: c9 x8 [: u$ D$ u2 f                 ......


9 c4 b  z0 t- J$ Z, U

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

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

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

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

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

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


  c2 j0 k4 X. _+ z1 S$ q( W

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

  S2 Q- m! k2 M, i9 o

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

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


& v0 G  w" o5 H! I2 k; X

回复

使用道具 举报

 楼主| 发表于 2010-6-5 21:53 | 显示全部楼层
2.4 组织的概念) [- T4 Y  N6 J8 y

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


( v* V( i# {1 a  a9 M+ R

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

: c: `3 F3 r6 r$ b1 h/ ~4 ?% Z

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


! ]$ ~$ s) e- a9 c2 W, }" q. @. T

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


; @/ b9 ~  O5 j" k1 q" M& A& W

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

2 o" Y) f3 Q0 Z; f

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

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

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

+ `, `. b) o8 g# C+ T

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

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

回复

使用道具 举报

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


, {8 |% P; f$ Mmodule Template


* t' |# u3 V' }  [1 {(

! l. v# \1 M, d2 N" J
    CLK, RSTn,


% [" L3 y$ ~8 X9 x1 V    ...... ,  // "n个输入输出"

) x' @/ \% {  y! v) ]8 \  D
    Start_Sig , Done_Sig

' h  C! D  m8 G% }) c) {; Q
);

6 E: z" D3 v4 h- q3 ]' O& b- ?2 Q

       input CLK;

       input RSTn;

       input Start_Sig;

       input Done_Sig;

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


) ?- u9 u3 g1 u; s! H

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


- Z) F# l- u1 n7 q

      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 )  A* q6 g0 s3 C) o

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

                   Init;

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

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

                   Done;       0 }# _+ u6 A) |6 B* T# E5 o0 Z8 x

               endcase

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


3 C) n( o& @. r0 R! [, Y

         task Init;


8 L1 F$ t# [( f$ ]: A0 `

             begin

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

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

             end

         endtask

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

4 k4 H$ [6 m2 X

         task  "nTask";

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

         endtask

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


. J3 j! D  ^* G* ^1 A2 e

        task Done//产生Done信号

4 o% U7 F* J: d8 ^7 ]9 u8 S

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

            else begin isDone <= 1'b1; i <= i + 1'b1; end
* C5 ~. P& c1 M# E

        endtask

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

8 s  N& g" D& H$ B8 W! Q

        assign Done_Sig = isDone;

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

    endmodule

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

+ V0 `' V3 ^" i: Q( S) @

1) Start_Sig Done_Sig是固定的。

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

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

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

) f$ a& `& {% j/ ~

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


2 g$ D- Y# A8 b' P6 `" A" C; }

' d" Z; p. r1 f# n
i <= i + 1;


# G" C) S3 [  C4 ^. K

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

3 s0 g4 Y+ T) i( H& U/ Y2 \

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

7 j7 v) D; n0 V


9 x: X; w8 N* {7 U" K  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  else8 H2 x: r3 S4 u' m! _; Z
      case ( i )9 `+ }: s+ d8 u
4'd0 : i <= i + 1;              ......      endcase
: T4 y* O: k# e( D

6 Y; W" p! i5 ?" q% }reg [3:0]i;  reg isDone;  reg [7:0]rData;  always @ ( posedge CLK or negedge RSTn )  if( !RSTn )      begin
( n# L& c, c+ }: F: s+ I6 Zi <= 4'd0;          isDone <= 1'b0;          rData <= 8'd0;      end  else      case( i )
8 a' ?2 d/ a4 l9 f* y6 l
% s7 V* o' B& ]2 P7 b1 l4'd0 : Next;          ......
8 r# \! q! S& y      endcase3 f0 G. g6 S0 W  l$ K
/**********************************/! \% p& q+ v, e9 [
  task Next;
" p% L9 {0 J" }, b$ g 6 z" o! n  s4 q; l& `
i <= i + 1'b1;
" c' G4 c! K2 p7 B; D1 E$ e   endtask


* Y" ?5 Y6 y" R, X

上面的两个写法都是等价的。如果模块是小功能,那么左边的写法很适合。但是一旦模块的功能很复杂,那么右边的写法会凸显出优势。
1 X4 Q6 C: ~4 p' Z9 m+ P

' K  [& O& `/ _; a! J
回复

使用道具 举报

 楼主| 发表于 2010-6-5 21:55 | 显示全部楼层
3.2 建议
1 g" @. a5 d/ f# U

为什么需要模板结构?

. `. p; t* P) k

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


0 W- e( W8 _) G; i, p

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


5 Z( K4 \& S; D0 E; J' q* }9 p

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

: r5 i0 i" a1 J. U2 P

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

) e1 i) s# u' O9 u3 w$ W0 l2 E. X

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

回复

使用道具 举报

 楼主| 发表于 2010-6-5 21:56 | 显示全部楼层
4.1建立2个“低级功能模块”. |: o6 S: S$ q/ ], j  \7 y

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


4 k( C! V1 I, E0 B! {: o( P

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

% M1 L# W7 C8 c) l9 Q9 |0 ^

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 c: Z$ e9 P% u: ~/ C

14.
9 u" _% e/ q3 e( j# L8 z. q$ [! [, v /***********************************/

15.9 s  w& h6 P$ Z% c  `9 w# E6 ]

16.    parameter DELAY = 8'd200;

17./ N5 ~! l/ G- S( \; D5 ^

18.5 A+ p$ {5 g5 m9 k  M+ y' n1 i5 u+ O
/***********************************/

19.
1 g6 S5 P8 g- e" L2 B

20.    reg [7:0]Counter;

21.9 Y7 v2 ]4 D, V. y5 |" \

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.
5 H! e2 k: p; ^- h8 b) j# x- k7 n

32.6 _1 V: S0 M& J+ g1 h3 I0 o
/***************************************/

33.3 J& s% G9 p' a+ F3 _) S

34.    reg [3:0]i;

35.    reg [7:0]rData;

36.    reg isDone;

37.
5 |$ f0 ^( x% y5 ]; C

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.
# ]! E$ o2 c8 t3 H' w; e

48.
+ X+ o7 M& i" f' l( F
) ]# h6 u: K$ E" O4 m) H/ u# ]# y  {! h( q  I- z5 @4 V

/ w' Y, q6 [9 l' o# R7 ?4'd0 :

49.
9 b  I1 I+ Z3 [. Q: ]3 w3 z2 X( ~1 R
begin rData <= 8'dx; i <= i + 1'b1; end

50.
& @% ^3 O/ [9 l9 w" r
# O% |& A. S/ r1 ^" r6 b0 z- x5 j0 `% X3 r2 n: N9 ?# G- r

; J4 ^+ ?/ b4 d. `8 T; G

51. 8 b; y: ?% k+ a  C' _  A0 k

% P6 u0 B5 B( o
+ G0 b+ f5 y: j- j
- U: j/ S# l- y' }/ r$ W( v6 Y4'd1, 4'd2, 4'd3, 4'd4, 4'd5, 4'd6, 4'd7, 4'd8 :

52. 6 H$ u# p% ?. K
3 q# r/ c2 t7 H* |# q
9 V- z# s+ t3 O. h, T7 G+ H' x

8 i1 p; w8 c; X3 dif( Counter == DELAY ) i <= i + 1'b1;

53.
8 ^9 h0 i+ p6 S0 y* ^+ g4 p6 v
: ], O/ g6 n( p# d3 w: W
: N$ @5 G5 i( N

: U5 |. }  r( C/ {4 [7 Helse rData <= ( 8'h80 >> i - 1 );

54.
& B5 ^+ p5 H6 m: D: H
: n; k. z2 t+ w  I
4 l8 m" \0 C( Q0 S7 s3 Q, S, O, x( E: @' }4 y' `( ]! b
4 G' N' n& Y- S, p

55.
2 ?- L! G0 A; m5 n' ?
3 @; p# O% g% v
" ~* U% J5 l% M: p2 K# A' Q0 [' c
9 o& E2 Y* [. q5 L3 r- n2 S6 ^
4'd9 :

56.
7 l2 c/ E% P3 ^$ E+ j% N! M" d

( K+ K) w  c5 Q
2 P& m7 Z1 U, i! T/ o; B' P
3 `6 S7 b# i1 h& k; v  O- ?
+ ?% s3 w0 M3 Zbegin i <= 4'd10; isDone <= 1'b1; end

57.
" r7 l+ j1 }" B! e+ E0 ]
) J% M5 @7 n( [, z0 z6 v; T- \8 ?) @

5 T: M; y+ m" f9 T2 ~

58.
& `0 E; D" ^  `* b* _

$ E% i- Z- r5 {/ ?6 H5 y+ p
" y+ g5 @; ]$ h2 {- ?# Q  n/ }
2 r% O( U5 I" x* |5 d' `4'd10 :

59.
1 s' x; e7 Z# Y) @
" b; Y2 S6 j/ ~2 n1 K  Z

: f& m% `8 k7 w0 \- H6 }1 [0 o8 ~, _! t
begin i <= 4'd0; isDone <= 1'b0; end

60.1 ]! f$ f' c3 k( ?" q$ R
& j7 b$ ^. b& ]/ r6 t
$ i# W! Y' {8 j, ?3 h0 T" D
% S' ~8 {# [1 P1 [1 W% _( ^

61.            endcase

62.

63.9 r0 v/ b( Q& d8 M/ [; B% s9 m+ O2 w

64.
' y7 I5 |2 f, } /**********************************/

65.

66.    assign Done_Sig = isDone;

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

68.
2 \& Y9 m) P. ^  }

69.
% D: A% i' n" M4 L' ]1 Z4 l' D6 V /**********************************/

70.

71.endmodule


) _) P. b* n9 D) \/ ?" @

7 j, J1 o) I* o( [8 }8 o& f

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.
+ W8 c# B4 y) p* t, ?

14.
8 J1 t4 E& n# z4 w; w/ @# J8 D" w; [0 O /***********************************/

15.' G% K) b2 h  ?8 ~/ b3 F

16.    parameter DELAY = 8'd200;

17.
' g6 L% C, v) ?, v2 M+ F9 H4 w* |, Z

18.% R# j/ x; X6 z
/***********************************/

19.0 t0 L) y' \+ c; p2 d  q0 I7 K! Z

20.    reg [7:0]Counter;

21.
' c. Z6 u1 f, z: a( W

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.
) w+ l' w3 g$ h' [

32.
6 V7 ]0 b( Q# @. `, N6 q$ ?/***************************************/

33." S7 Y/ Y. g- T8 B. J! [

34.    reg [3:0]i;

35.    reg [7:0]rData;

36.    reg isDone;

37." g7 _- E% B. ~

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.5 A4 d6 Y8 Z# s" }2 f. k1 p3 W$ p

48.
4 h* j6 j8 w" T

. S2 a: E% v8 Y5 R7 \! v
& P' V6 Z3 {; }8 ]9 _, u1 e% Y, z8 z. g& e+ `- w5 G+ y
4'd0 :

49. % B4 t) S) N( |7 ]

3 y3 x" _0 ^2 v* `% ?  x8 H5 a/ k( \% k
6 Z! u/ k# f! k" Z# }2 q5 J
begin rData <= 8'dx; i <= i + 1'b1; end

50.
% p- Z+ O/ E6 R5 ~  v: z) [) c- u0 Y: @* v6 }/ |4 ]7 V, D: v
& b  s" p3 T/ v
' P2 j+ b( s1 r4 {3 {7 k. Z

51.
* m+ u5 ?4 Y% k% }

9 H' u- L2 n! k- Q. b7 i9 Z4 |  `9 ^/ i" Q& Q2 ~, a- U
- T1 ]& {. u/ K2 @9 w! j- R* H. k
4'd1, 4'd2, 4'd3, 4'd4, 4'd5, 4'd6, 4'd7, 4'd8 :

52.: [" ^* M, a& `( z5 `  P$ C, r
$ N0 U% J( i: m& C" \3 }

0 m, [8 S5 l. W2 q2 }7 m' @1 ~$ s! [3 ^5 B/ ?1 ]! @- Q0 k" F) k7 e7 p
6 j* E0 B' s9 R! L/ x
if( Counter == DELAY ) i <= i + 1'b1;

53.
3 p9 h4 l3 h; l  W) ^8 ~7 a
  X! F) ?% b0 ?

- G$ n( I6 F0 z$ a$ l
( K5 K& @: f& Z$ S  Kelse rData <= ( 8'h01 << i - 1 );

54.
7 i1 [9 h5 x1 d1 B3 y
6 @( [& I+ Q5 m  O
+ j# C$ M7 A% F1 F2 F$ w
3 Q7 [. |! {8 o' h  [/ L6 O/ l7 ^1 |# U6 `- |* f$ C$ A

55.
$ F# W  ^3 E. \/ u; f% Y

( A7 M. |! x& D" s( y( K5 k/ d$ ^# N% ~# S& r; z7 j/ K

! j7 ~" V" V3 `) ]4'd9 :

56. ( t7 U, S/ A& d  y! \

7 a( L. `0 \3 N7 J" M! W
$ @4 X1 N+ F& s- ?: s
7 w" E" N0 I+ O7 Sbegin i <= 4'd10; isDone <= 1'b1; end

57.
: g7 \/ |# X# l: v4 b9 m4 \2 T& B) Z4 A3 p
; O9 F$ K: s9 a2 Y2 A1 u
$ \( s1 S0 u; n6 d4 v+ T

58.
4 }/ X4 W( W. v2 j/ i# @: b1 B6 N. Y
1 w" D2 Z& f  t! r3 ]  ^

8 g+ r% r9 K! ]& P; B" n" `4 P4 e, K6 q; [3 T) d/ p
4'd10 :

59. 6 r% K1 R( L( W7 y4 z
% ~) J" @7 ?4 L$ F6 E, f

8 L: \& m. ^; u1 |1 }# ^8 i7 o# R
/ R, X& ]3 d! V+ m8 Z, {7 y' {$ zbegin i <= 4'd0; isDone <= 1'b0; end

60.
* v) J1 Q5 q/ |/ ~
1 h& h, D0 W8 I- d
* e0 H* I8 O  U5 h; d5 y' b
' p' k& ]! w& g& C" W

61.            endcase

62.
7 f5 a! g1 T5 ?' _/ b

63., l* ?) C' a0 C% z) g& E0 e4 O
/**********************************/

64.

65.    assign Done_Sig = isDone;

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

67.7 a7 c9 q  R7 _, C

68.
# z+ h: Q$ z$ F1 w7 v& ]$ a( s! {/**********************************/

69.

70.endmodule

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

2 t, u, e, `9 h' A9 ?3 X

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


; X; `: B, l" H" I

仿真效果如下

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

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


* ?5 ?) F7 l- R+ B( T- y


# _4 ^3 x7 o, V% a) ]( K
$ k% `  ~3 X, r5 n  `6 m

( 最后一行是完成信号 )

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

( V$ ^* x$ @1 \; y$ V8 K. V

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


( P  m4 j8 d6 V! I# P$ T3 z完成创建2个“低级功能模块”以后,为了使日后调用方便,必须封装起来。“低级功能模块”的封装工作会比较麻烦,因为“低级功能模块”有“复用连线”的现象,换一句话说,会出现“两义性”或者“多义性”的问题 ......
回复

使用道具 举报

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

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

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

4 q' b- a: U6 x# s; A& \

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.
6 a8 F/ v: P# o% c0 T

8.     input CLK;

9.     input RSTn;

10.    input Right_Start_Sig;

11.    input Left_Start_Sig;

12.
( v8 N) G/ B. X/ M

13.    output Right_Done_Sig;

14.    output Left_Done_Sig;

15.    output [7:0]Q;

16.
6 ]( L5 v7 K. Y

17.
) |# f1 F9 ?( W/ I /*******************************/

18.
, k$ W0 t8 N7 d( {

19.    wire [7:0]Q_U1;

20./ `  q5 a& S% i9 T

21.    flashing_to_right U1

22.    (

23.        .CLK( CLK ),      
" o) A- j4 T, X
/ X5 t. X! L% v$ \# ^) A5 k
3 |$ B, @& ~6 _0 j// input - from top

24.        .RSTn( RSTn ),
5 p  L# Q* N  B# F8 X6 ~+ v* K! s* _# h" y# z$ X  a. D

5 z+ ~7 n  V" s5 K8 {$ K- g* T  t( y. f1 G
6 K& \( r% c5 ]4 d! x, l
// input - from top

25.        .Start_Sig( Right_Start_Sig ), 7 W7 S; m4 |1 G( W* \
// input - from top

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

27.        .Q( Q_U1 )# X  h% M8 Q' B5 c2 a

. v- Q, l' d# I8 e
2 ^1 x9 w' s9 l' S- ]( ?2 R
* e* v1 G6 k# K8 O  v) S4 }! Y( n3 G2 J  ^0 W8 J( g3 }4 g

* D% e( L+ |* _7 X% |// output - to wire

28.    );

29.7 s$ \. m6 t5 w" K4 n- z

30.; _6 @, ^$ g/ S, g' ^1 Y
/********************************/

31.' i9 q( l( I: M2 o

32.    wire [7:0]Q_U2;

33.- w: w" y4 x; G; N! O' V

34.    flashing_to_left U2

35.    (

36.        .CLK( CLK ),           2 X: s9 P" H8 ?- q# ~. @
  A3 [+ U$ m& }, v8 ~2 b0 \- \3 @
// input - from top

37.        .RSTn( RSTn ),            & y7 h. Z% P# n, U3 p" O
// input - from top

38.        .Start_Sig( Left_Start_Sig ),  ( e  r8 Z: X2 v* F
// input - from top

39.        .Done_Sig( Left_Done_Sig ),$ f, L+ y8 O; ^4 E
// output - to top

40.        .Q( Q_U2 )
% w* y- Z( m4 X0 V7 {" i) V3 A) H  R3 M

" _6 j: R" N( t1 D8 X! a6 p- v9 T( A  S4 T+ I8 i' O' q9 D# Z
: u9 P4 f. [" Y! I& F% @4 `

* w$ p$ c. H. r; j// output - to wire

41.    );

42.# S$ O3 O% Q2 @$ \; E

43.
- v: G6 s8 i' @9 `/*************************************/

44.
4 V& H0 v1 b9 @: y6 J6 A: g/ D

45.    reg [7:0]rQ;

46.  X3 Y4 j* N, g2 r

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.
4 P" i- F( ^$ J$ u& V

52.    assign Q = rQ;  

53.0 n% [$ |1 a  r. `2 |( r

54.5 {1 W' Q! S) x" X* U+ H
/*************************************/

55.0 j: I& r3 @0 _& S8 }5 Q8 A

56.endmodule   
) s" l" _! C* D6 W6 G3 L


% {+ N% {+ |1 E& J( a% ~4 Q- t


& \) f) d5 w8 [

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


/ ?8 u% Y" G9 h3 j0 j

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


9 h+ }' P8 a3 V) S  m% D) ~1 }

当然还有其他的写法:

; d: t% c2 v6 |: B' ^3 G

assign Q = Right_Start_Sig ? Q_U1 : Q_U2 ;

! C2 f3 E3 k. n: M0 g

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


, E7 F5 F1 b! g6 s0 A

1. 解读性很差。

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


% _7 Q2 |, Q, e, D: Q! v

所以不怎么推荐使用。


1 l% a2 `0 i# a  W+ A

还有一中更糟糕的写法:


/ g; ~1 N: v# Q/ T' c) Z

    reg [7:0]rQ;

; P; k) u8 d* z& D

    always @ ( * )

    case( { Right_Start_Sig, Left_Start_Sig } )

        2'b10   : rQ = Q_U1;

        2'b01   : rQ = Q_U2;

        default : rQ = 3'bxxx

    endcase

) d6 F( s* R/ @' {) {+ G

assign Q = rQ;

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


  k; e/ P& q/ M" n

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

( l5 u9 P$ D2 \/ B1 K" B3 h

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


9 t0 Y7 |6 S$ i, n1 S% D) ~

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

2 j7 y& }( C! ]2 X2 F6 G! F

    reg [7:0]rQ;

  x9 ~$ W7 i4 Z$ K

    always @ ( * )

    if( Right_Start_Sig ) rQ = Q_U1;

    else if( Left_Start_Sig ) rQ = Q_U2;

    else rQ = 3'dx;


" ]6 a" ]& {& b! |: d# `$ w* B

assign Q = rQ;  

& O8 O: `# B0 i+ u7 x


4 S$ E" w: ?: c9 C# v* ~* X# \

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

! F( `- o" M+ o, ~6 G2 G$ ^7 K# u


: H* m( l- S! M9 F2 Z) a

    always @ ( * )

4 o6 j7 A. s) _

5 ^: }  ?# b+ d. T' B% d' V4 i4 c

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

# Y5 r! T4 {: [1 \


, T0 Y3 _: }  b" }' r1 f2 Y

    if( Right_Start_Sig ) rQ = Q_U1;

    else if( Left_Start_Sig ) rQ = Q_U2;

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


! V- t7 D, i  V% P, x

' v! v: f- y0 e  u

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

+ f9 d' j8 b' X3 }( \* Q

5 a# G" t! }* j! y% D' P

       always @ ( * )


; U: v2 l# h+ e" E3 \x   if( Right_Start_Sig ) Q = Q_U1;//连线 QQ_U1 Q_U2 之间没有

' z0 L$ j: o) c$ v$ w% J; ~! v
x   else if( Left_Start_Sig ) Q = Q_U2;$ J- \, \3 k/ @, \- @% X
//寄存器驱动

, m; E7 S* v  E- O
x   else Q = 3'dx;

4 T$ ?' x0 G2 a$ k

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


, d1 v7 v/ p( ^9 J6 @  ~6 E- z

总结:

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


& _1 k! }7 l0 {
回复

使用道具 举报

本版积分规则

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

GMT+8, 2025-8-20 16:10 , Processed in 0.047490 second(s), 27 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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