请选择 进入手机版 | 继续访问电脑版

明德扬论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

微信扫一扫,快捷登录!

查看: 5357|回复: 0

【FPGA至简设计原理与应用】第一篇第三章硬件描述语言Verilog第5节if和case

[复制链接]
发表于 2020-9-7 19:02:41 | 显示全部楼层 |阅读模式

马上注册,看完整文章,学更多FPGA知识。

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
本案例的编号为:001500000143,如果有疑问,请按编号在下面贴子查找答案:MDY案例交流【汇总贴】_FPGA-明德扬科教 (mdy-edu.com)
本文为明德扬原创及录用文章,转载请注明出处

大家好,近期我们会连载《FPGA至简设计原理与应用》一书,有兴趣的同学可以学习,也希望大家可以对我们的书提出宝贵的意见和建议。

FPGA至简设计原理与应用》书籍连载索引目录

http://www.fpgabbs.cn/forum.php?mod=viewthread&tid=989


读过的朋友可积极在贴后留言,书籍正式出版时,我们会从留言者中挑选20位幸运读者,幸运读者可获潘老师亲笔签名书籍一本。

注:手机浏览可能格式会乱,建议用电脑端进行浏览。




5.8.2  if语句

本文档编号:001100000061
需要看对应的视频,请点击视频编号:001100000066
本节主要进行组合逻辑的介绍,包括:程序语句(assign语句、always语句),数字进制(二进制、不定态、高阻态),算数运算符(加、减、乘、除运算符),逻辑运算符(逻辑与、或、非运算符),按位逻辑运算符(单目按位与、或、非运算符,双目按位与、或、异或运算符),关系运算符,移位运算符(左移、右移运算符),条件运算符(三目运算符、if语句、case语句、选择语句等),拼接运算符;
ALTERA和VIVADO文档

“if”语句的语法如下:
if(condition_1)
procedural_statement_1;
{else if(condition_2)
procedural_statement_2};
{else
procedural_statement_3};

其含义为:
如果对condition_1 条件满足,不管其余的条件是否满足,都执行procedural_statement_1procedural_statement_2procedural_statement_3都不执行。
如果condition_1不满足而condition_2满足,则执行procedural_statement_2,而procedural_statement_1procedural_statement_3都不执行。
如果condition_1不满足并且condition_2也不满足时,执行procedural_statement_3,而procedural_statement_1procedural_statement_2都不执行。

通过下面一个例子来具体说明:
if(Sum < 60) begin
Grade = C;
Total_C = Total_c + 1;
end
else if(Sum < 75) begin
Grade = B;
Total_B =Total_B + 1;
end
else begin
Grade = A;
Total_A =Total_A + 1;
end
注意条件表达式必须总是用括号括起来,如果使用if -if - else 格式,那么可能会有二义性,如下面的示例所示:
if(Clk)
if(Reset)
Q = 0;
else
Q = D;
这里存在一个疑问:最后一个else 属于哪一个if语句? 是属于第一个if 的条件(Clk)还是属于第二个if的条件 (Reset)? 这在Verilog HDL 中已通过将else 与最近的没有else if语句相关联来解决。在这个例子中, else 与内层if 语句相关联。

下面再举一个if 语句的例子:
if(Sum < 100)
Sum = Sum + 10;
if(Nickel_In)
Deposit = 5;
elseif (Dime_In)
Deposit = 10;
else if(Quarter_In)
Deposit = 25;
else
Deposit = ERROR;

笔者建议:
1、条件表达式需用括号括起来。
2、若为if - if 语句,请使用块语句 begin ---end,如下所示。

if(Clk) begin
if(Reset)
Q = 0;
else
Q = D;
end
以上两点建议是为了使代码更加清晰,防止出错。

5.8.3  case语句
case 语句是一个多路条件分支形式,其语法如下:
case(case_expr)
case_item_expr{case_item_expr} :procedural_statement
. . . . . .
[default:procedural_statement]
endcase
case语句下首先对条件表达式case_expr求值,然后依次对各分支项求值并进行比较,执行第一个与条件表达式值相匹配的分支中的语句。可以在1个分支中定义多个分支项,且这些值不需要互斥。缺省分支覆盖所有没有被分支表达式覆盖的其他分支。
例:
case (HEX)
4'b0001 : LED =7'b1111001; // 1
4'b0010 : LED =7'b0100100; // 2
4'b0011 : LED =7'b0110000; // 3
4'b0100 : LED =7'b0011001; // 4
4'b0101 : LED =7'b0010010; // 5
4'b0110 : LED =7'b0000010; // 6
4'b0111 : LED =7'b1111000; // 7
4'b1000 : LED =7'b0000000; // 8
4'b1001 : LED =7'b0010000; // 9
4'b1010 : LED =7'b0001000; // A
4'b1011 : LED =7'b0000011; // B
4'b1100 : LED =7'b1000110; // C
4'b1101 : LED =7'b0100001; // D
4'b1110 : LED =7'b0000110; // E
4'b1111 : LED =7'b0001110; ,// F
default:LED =7'b1000000; // 0
endcase
书写建议: case语句的缺省项必须写,防止产生锁存器。

5.8.4 选择语句
Verilog语法中有一个常用的选择语句,其语法形式为:
vect[a +: b]vect [a -: b]
vect为变量名字,a为起始位置,加号或者减号代表着升序或者降序,b表示进行升序或者降序的宽度。
vect[a +: b]等同于vect[a : a+b-1]vect的区间从a开始向大于a的方向进行b次计数;vect [a -: b]等同于vect[a : a-b+1]vect的区间从a开始向a小的方向进行b次计数。a可以是一个常数也可以是一个可变的数,但b必须是一个常数。

1vect[7 +: 3]
其中,起始位置为7+代表着升序,宽度为3。即从7开始向比7大的方向数3个数。其等价形式为:vect[7 +: 3]==vect[7: 9]

2vect[9 -: 4]
其中,起始位置为9-代表着降序,宽度为4。即从9开始向比9小的方向数4个数。其等价形式为:vect[9 -:4]==vect[9 : 6]
在实际使用的过程中该语法最常用的形式是将a作为一个可变的数来使用。例如需要设计具有如下功能的代码:
cnt==0时,将din[7:0]赋值给data[15:8];当cnt==1时将din[7:0]赋值给data[7:0]
在设计的时候便可以写成:data[15-8*cnt-: 8] <= din[7:0](此时需要将15-8*cnt视为一个整体a,其会随着cnt变化而发生变化),这样一来就完成了对代码的精简工作。

选择语句的硬件电路结构如下图所示,其本质上是一个选择器。当cnt==0时,选中data[15:8]的锁存器,将din[7:0]赋值给data[15:8],而data[7:0]的锁存器保持输出不变;当cnt==1时,选中data[7:0]的锁存器,将din[7:0]赋值给data[7:0],而data[15:8]的锁存器保持输出不变。

Modelsim对以上例子进行功能仿真后的仿真图如下所示。

可以看出仿真结果满足实际的设计需求。
笔者经验:在实际工程中可以多使用选择语句vect[a +: b]或vect [a -: b]的形式来进行代码编写,这将有助于精简设计代码。

5.8.5 经验总结
if 语句和case语句是Verilog里两个非常重要的语句, if case语句有一定的相关性,也有一定的区别。相同的地方在于两者几乎可以实现一样的功能,下面主要介绍一下两者之间的区别。

if 语句每个分支之间是有优先级的,综合得到的电路是类似级联的结构。case语句每个分支是平等的,综合得到的电路则是一个多路选择器。因此,多个if else-if语句综合得到的逻辑电路延时有可能会比case语句稍大。对于初学者而言,在一开始学习Veriolg的过程中往往喜欢用if else-if语句,因为这种语法表达起来更加直接。但是在运行速度比较关键的项目中,使用case语句的效果会更好。下面通过一个具体的案例来对比一下,使用if语句和case语句来描述同一功能电路的综合结果。

首先是用if语句写的代码:
1
  
2
  
3
  
4
  
5
  
6
  
7
  
8
  
9
  
10
  
11
  
12
  
13
  
14
module if_case(
  
     input [1:0] en,
  
     input [1:0] a,
  
     output reg q
  
);
  
always @(*) begin
  
        if(en[0]==1)
  
            q  = a[0];
  
      else if(en[1]==1)
  
            q  = a[1] ;
  
      else
  
           q = 0 ;
  
end
  
endmodule
其综合后的RTL视图如下所示。

从上图中所示的RTL图可以看到,此电路中含有两个二选一多路选择器,并且右边的优先级要高于左边(因为q的值是直接与右边的二选一选择器连接),当en[0]不为1时才会继续判断en[1]。也就是说,在if语句下综合出的电路含有优先级。
接下来分析一下使用case语句描述的代码。
1
  
2
  
3
  
4
  
5
  
6
  
7
  
8
       always @(*)
  
begin
  
        case(en)
  
        2'b01: q = a[0];
  
        2'b10: q = a[1];
  
    default:q = 0;
  
endcase
  
end
其综合后的RTL视图如下所示:

可以看出,使用case语句编写的逻辑代码综合出的电路是并行的,没有优先级,不影响电路的运行速度。
虽然在RTL视图中,两种语句综合出的电路存在着较大的差别,但是由于目前的开发工具已经足够智能,在布局布线的时候会自动对电路进行优化,其最终映射到FPGA内部的电路之间基本毫无差别。



最后总结一下if语句和case语句之间的区别与联系:
If语句具有优先级,当if下的条件不满足时才执行else后面的部分。而case语句是并行的,没有优先级,这在两者综合出来的RTL视图中可以明显的观察出来。但由于现在的仿真和综合工具已经足够强大,最后综合后的结果if..else...case...语句其实并无不同,只不过是两种不同的实现方式而已,因此基本上不用考虑这两者间的区别。在不影响功能的前提下设计师不需要做局部的优化工作,例如不需要考虑if/case语句的资源耗费差异、不需要考虑优化电路。只有在影响功能(即时序约束报错)的前提下,根据提示对电路进行优化。




您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|小黑屋|MDYBBS ( 粤ICP备16061416号 )

GMT+8, 2024-3-29 12:47 , Processed in 0.048995 second(s), 21 queries .

Powered by Discuz! X3.4

本论坛由广州健飞通信有限公司所有

© 2001-2019 Comsenz Inc.

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