Verilog常见的误区
组合逻辑锁存器的生成
在Verilog语言组合逻辑的书写中,我们经常会写下面语句:
assign din_x = rvalid == 1'b1 ? {{24{din[9]}},din}: din_x;
或者,
always @(*)
if(ext_valid == 1'b1)
dout <= comb_in3;
else
dout <= dout;
直接读写的语法,我们以为编译器会生成锁存器,但是上面的语法分别核下面的等效,
assign din_x = {{24{din[9]}},din};
always @(*)
dout = comb_in3;
是不是很神奇,上面的两条语句就相当于两个信号直接相连。因为编译器自动给你避免了锁存器的生成,但是这样一来,我们的实验结果或许就出现了错误,所以这里需要大家重点关注。
Verilog语句中signed的作用
这里关键字signed的作用不体现在数字的加减上,因为我们不管声不声明这个变量是有符号数,FPGA内部都是按照二进制数的加法来计算的,减法将减数转换成补码进行运算。
test模块:
`timescale 1ns / 1ps
module test(
//System Interfaces
input sclk ,
input rst_n ,
//Communication Interfaces
input [ 7:0] a ,
input [ 7:0] b ,
output reg [ 7:0] add ,
output reg [ 7:0] subtract
);
//========================================================================================\
//**************Define Parameter and Internal Signals**********************************
//========================================================================================/
//========================================================================================\
//************** Main Code **********************************
//========================================================================================/
always @(posedge sclk or negedge rst_n)
if(rst_n == 1'b0)
add <= 8'd0;
else
add <= a + b;
always @(posedge sclk or negedge rst_n)
if(rst_n == 1'b0)
subtract <= 8'd0;
else
subtract <= a - b;
endmodule
tb模块:
`timescale 1ns / 1ps
module tb();
//System Interfaces
reg sclk ;
reg rst_n ;
reg [ 7:0] a ;
reg [ 7:0] b ;
wire [ 7:0] add ;
wire [ 7:0] subtract ;
initial begin
sclk = 1'b0;
rst_n <= 1'b0;
a <= 0;
b <= 0;
#(1000)
rst_n <= 1'b1;
#(1000)
a <= 5;
b <= 7;
#(1000)
a <= 5;
b <= -7;
#(1000)
a <= -5;
b <= 7;
#(1000)
a <= -5;
b <= -7;
#(1000);
$stop;
end
always #(10) sclk = ~sclk;
test test_inst(
//System Interfaces
.sclk (sclk ),
.rst_n (rst_n ),
//Communication Interfaces
.a (a ),
.b (b ),
.add (add ),
.subtract (subtract )
);
endmodule
运行的结果如下:
我们将使用关键字signed进行如下实验:
test模块:
`timescale 1ns / 1ps
module test(
//System Interfaces
input sclk ,
input rst_n ,
//Communication Interfaces
input signed [ 7:0] a ,
input signed [ 7:0] b ,
output reg signed [ 7:0] add ,
output reg signed [ 7:0] subtract
);
//========================================================================================\
//**************Define Parameter and Internal Signals**********************************
//========================================================================================/
//========================================================================================\
//************** Main Code **********************************
//========================================================================================/
always @(posedge sclk or negedge rst_n)
if(rst_n == 1'b0)
add <= 8'd0;
else
add <= a + b;
always @(posedge sclk or negedge rst_n)
if(rst_n == 1'b0)
subtract <= 8'd0;
else
subtract <= a - b;
endmodule
tb模块:
`timescale 1ns / 1ps
module tb();
//System Interfaces
reg sclk ;
reg rst_n ;
reg signed [ 7:0] a ;
reg signed [ 7:0] b ;
wire signed [ 7:0] add ;
wire signed [ 7:0] subtract ;
initial begin
sclk = 1'b0;
rst_n <= 1'b0;
a <= 0;
b <= 0;
#(1000)
rst_n <= 1'b1;
#(1000)
a <= 5;
b <= 7;
#(1000)
a <= 5;
b <= -7;
#(1000)
a <= -5;
b <= 7;
#(1000)
a <= -5;
b <= -7;
#(1000);
$stop;
end
always #(10) sclk = ~sclk;
test test_inst(
//System Interfaces
.sclk (sclk ),
.rst_n (rst_n ),
//Communication Interfaces
.a (a ),
.b (b ),
.add (add ),
.subtract (subtract )
);
endmodule
运行结果如下:
对比以上两组实验,我们可以发现定义signed关键字在加减实验中没有体现应有的作用。
但是关键字在移位操作的时候就得到了体现
test模块:
`timescale 1ns / 1ps
module test(
//System Interfaces
input sclk ,
input rst_n ,
//Communication Interfaces
input [ 7:0] a ,
input [ 7:0] b ,
output reg [ 7:0] add ,
output reg [ 7:0] subtract
);
//========================================================================================\
//**************Define Parameter and Internal Signals**********************************
//========================================================================================/
//========================================================================================\
//************** Main Code **********************************
//========================================================================================/
always @(posedge sclk or negedge rst_n)
if(rst_n == 1'b0)
add <= 8'd0;
else
add <= a <<< 1;
always @(posedge sclk or negedge rst_n)
if(rst_n == 1'b0)
subtract <= 8'd0;
else
subtract <= b >>> 1;
endmodule
tb模块:
`timescale 1ns / 1ps
module tb();
//System Interfaces
reg sclk ;
reg rst_n ;
reg [ 7:0] a ;
reg [ 7:0] b ;
wire [ 7:0] add ;
wire [ 7:0] subtract ;
initial begin
sclk = 1'b0;
rst_n <= 1'b0;
a <= 0;
b <= 0;
#(1000)
rst_n <= 1'b1;
#(1000)
a <= 8;
b <= 10;
#(1000)
a <= 8;
b <= -10;
#(1000)
a <= -8;
b <= 10;
#(1000)
a <= -8;
b <= -10;
#(1000);
$stop;
end
always #(10) sclk = ~sclk;
test test_inst(
//System Interfaces
.sclk (sclk ),
.rst_n (rst_n ),
//Communication Interfaces
.a (a ),
.b (b ),
.add (add ),
.subtract (subtract )
);
endmodule
运行结果:
下面是加了signed操作的移位,我们可以看出来结果的不一样。
test模块:
`timescale 1ns / 1ps
module test(
//System Interfaces
input sclk ,
input rst_n ,
//Communication Interfaces
input signed [ 7:0] a ,
input signed [ 7:0] b ,
output reg signed [ 7:0] add ,
output reg signed [ 7:0] subtract
);
//========================================================================================\
//**************Define Parameter and Internal Signals**********************************
//========================================================================================/
//========================================================================================\
//************** Main Code **********************************
//========================================================================================/
always @(posedge sclk or negedge rst_n)
if(rst_n == 1'b0)
add <= 8'd0;
else
add <= a <<< 1;
always @(posedge sclk or negedge rst_n)
if(rst_n == 1'b0)
subtract <= 8'd0;
else
subtract <= b >>> 1;
endmodule
tb模块:
`timescale 1ns / 1ps
module tb();
//System Interfaces
reg sclk ;
reg rst_n ;
reg signed [ 7:0] a ;
reg signed [ 7:0] b ;
wire signed [ 7:0] add ;
wire signed [ 7:0] subtract ;
initial begin
sclk = 1'b0;
rst_n <= 1'b0;
a <= 0;
b <= 0;
#(1000)
rst_n <= 1'b1;
#(1000)
a <= 8;
b <= 10;
#(1000)
a <= 8;
b <= -10;
#(1000)
a <= -8;
b <= 10;
#(1000)
a <= -8;
b <= -10;
#(1000);
$stop;
end
always #(10) sclk = ~sclk;
test test_inst(
//System Interfaces
.sclk (sclk ),
.rst_n (rst_n ),
//Communication Interfaces
.a (a ),
.b (b ),
.add (add ),
.subtract (subtract )
);
endmodule
运行结果:
所以,在写程序的时候对有符号数操作,关键走signed还是应该添加。
总结
该篇文章我们会一直补充完善,共同发掘一些语法中的大坑。
在查找一些资料的时候,发现一些博主只给出部分代码,其实这样别人根本看不懂,只有给出整个工程代码才易于知识的传播。创作不易,认为文章有帮助的同学们可以关注、点赞、转发支持。为行业贡献及其微小的一部分。或者对文章有什么看法或者需要更近一步交流的同学,可以加入下面的群: