Verilog代码:if-else和case的电路结构和区别

描述

本文是针对在写项目中遇到的Verilog代码写法错误,多对一和一对多赋值问题,从逻辑赋值的角度理解为何会编译出错。并在后续讨论了if-else和case的电路结构和区别。在此处列出来供大家一起交流学习。

2.对Verilog代码的理解

2.1 一对多赋值、多对一赋值行为的区别

2.1.1多对一赋值的Verilog代码:

always @(posedge clk or negedge rstn)begin

if(!rstn)begin

REG1 <= 'd0;

REG2 <= 'd0;

end

else begin

if(write) begin

case(paddr)

'h54321 : REG1 <=  pwdata;   //在32'h54321写入pwdata

'h12345 : REG2 <=  pwdata;   //在32'h12345写入pwdata

default begin

REG1 <= REG1 ;

REG2 <= REG2 ;

end

endcase

//另一种写法

//REG1 <= (paddr == 'h54321) ? pwdata : REG1; //在32'h54321写入pwdata

//REG2 <= (paddr == 'h12345) ? pwdata : REG2;  //在32'h12345写入pwdata

end

else begin

REG1 <= REG1;

REG2 <= REG2;

end

end

end

·如果将一个信号(如pwdata)对多个信号进行赋值(如REG1、REG2),应该使用译码器形式的电路结构。也就是pwdata根据paddr进行译码,从而将值赋给REG1/REG2。如下图所示

#FormatImgID_0#

·译码器一般用多个输入信号,根据padder判断取值的不同,将输入信号pwdata赋值给相应的输出信号。代码中给出了两种写法都可以。

2.1.2一对多赋值的Verilog代码:

always @(posedge clk or negedge rstn)begin

if(!rstn)begin

prdata <= 'd0;

end

else begin

if(read) begin

case(paddr)

'h54321 : prdata <= REG1; //在32'h54321读出prdata = REG1  

'h12345 : prdata <= REG2; //在32'h12345读出prdata = REG2

default : prdata <= prdata;

endcase

//注意下面这种写法是错误的(2.1.3中会分析)

//prdata <= (paddr == 'h54321) ? REG1 : prdata;

//prdata <= (paddr == 'h54321) ? REG2 : prdata;

end

else begin

prdata <= prdata;

end

end

end

·如果将多个信号(如REG1、REG2)对一个信号进行赋值(如prdata),应该使用多路选择器形式的电路结构。也就是REG1/REG2根据paddr进行判断,从而将值赋给prdata。如下图所示

#FormatImgID_1#

·多路选择器的写法一般是利用case语句进行实现,根据case的条件不同,选择不同的输入信号对输出信号进行赋值。

2.1.3 为什么多对一赋值不能用三目运算符呢?

即写成:

always @(posedge clk or negedge rstn)begin

if(!rstn)begin

prdata <= 'd0;

end

else begin

if(read) begin

//注意多对一中,下面这种写法是错误的

prdata <= (paddr == 'h54321) ? REG1 : prdata;

prdata <= (paddr == 'h54321) ? REG2 : prdata;

end

else begin

prdata <= prdata;

end

end

end

分析:这时候编译就会报错,prdata同时被两个常量赋值。假如说paddr选中了'h54321,此时 prdata<= REG1成立;但是请注意在第二条语句中,由于paddr≠'h54321,prdata <= prdata。

由此我们可以知道三目运算符和case并不等价,如果改写成if-else多层嵌套语句,编译没有出错误。

always @(posedge clk or negedge rstn)begin

if(!rstn)begin

prdata <= 'd0;

end

else begin

if(read) begin

if(paddr == 'h54321)begin

prdata <= REG1;

end

else begin

if(paddr == 'h54321)begin

prdata <= REG2;

end

else begin

prdata <= prdata;    

end

end

end

else begin

prdata <= prdata;

end

end

end

下面进一步分析if-else和case语句的区别来分析。

2.2 if—else语句与case语句的区别

2.2.1 if-else语句的电路结构

每个if-else就是一个2选1mux器。当信号有明显优先级时,首先要考虑if-else,但是if嵌套过多也会导致速度变慢;if语句结构较慢,但占用面积小。

嵌套的if语句如果使用不当,就会导致设计的更大延时,为了避免较大的路径延迟,最好不要使用特别长的嵌套if结构。如想利用if语句来实现那些对延时要求苛刻的路径时,应将最高优先级给最迟到达的关键信号。

2.2.2 case语句的电路结构

case语句综合为 n选1的mux电路。适用于无明显优先级的逻辑判断,即这些逻辑条件都处于同一个优先级且互斥;case结构电路速度较快,但占用面积较大。

2.2.3 if语句和case语句中的latch问题

if-else:组合逻辑和时序逻辑中的always语句块中实现是不同的。

组合逻辑中:if缺少else 时,会有latch;

时序逻辑中:尽管缺少else,依旧是D触发器,不存在latch。

case语句:case列举不全并且还没写default语句,则会综合出锁存器。所以一定写default,无论是组合还是时序逻辑。

总结:保证if-else对应齐全;case必写default。

2.2.4 if-else语句和case语句的区别

对于这个的讨论,本人认为是以前由于综合工具落后,导致有区别,但是随着综合工具的更新,他们之间的区别越来越小,甚至有人可以用if-else综合出无优先级的多路选择器,用case综合出有优先级的多路选择器。

“if-else的逻辑判别是有优先级的,而case的逻辑判断条件是并列的。

举个例子,如果你用IF实现译码器,综合出的是有优先级的译码器。如果用CASE,综合出的就是一个无优先级的译码器。也就是说IF是有优先级的,执行的次序有先后。而CASE执行的时候是没有先后顺序的。”

“随着综合工具的进步,已经不需要讨论if-else 和case的区别了,两者可以等同 ”

“Verilog 2001标准(IEEE 1364-2001)第132页:

The case item expressions shall be evaluated and compared in the exact order in which they are given.

指出了case是串行有优先级。又:

Apart from syntax, the case statement differs from the multiway if-else-if construct in two important ways:

a) The conditional expressions in the if-else-if construct are more general than comparing one expression with several others, as in the case statement.

b) The case statement provides a definitive result when there are x and z values in an expression.

a)是废话。b)指出了case是四态对比。除此之外和if-else没有差别。”

审核编辑:黄飞

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分