本文是针对在写项目中遇到的Verilog代码写法错误,多对一和一对多赋值问题,从逻辑赋值的角度理解为何会编译出错。并在后续讨论了if-else和case的电路结构和区别。在此处列出来供大家一起交流学习。
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赋值给相应的输出信号。代码中给出了两种写法都可以。
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的条件不同,选择不同的输入信号对输出信号进行赋值。
即写成:
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.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没有差别。”
审核编辑:黄飞
全部0条评论
快来发表一下你的评论吧 !