数字IC设计经验整理
本篇博客主要是对工作一个多月的verilog编程的总结
文章目录
1、上升沿转换为脉冲信号
always@(posedge clk or negedge rst)
if(!rstn)
a_1d <= 0;
else
a_1d <= a;
assign b = !a_1d && a;
信号a从0变为1时,b将产生一个脉冲信号,从而完成将上升沿信号a转换为脉冲信号b的功能;
2、比较运算的优化
假设我们要分别将两个输入a,b中的较小的值给min_dat,较大的值给max_dat.
如果我们这样写
assign min_dat = a<b?a:b;
assign max_dat = a>b?a:b;
由于比较运算的本质是减法运算
,那么,a和b就被比较了两次,为了减少运算资源,可以写成如下这样:
assign c = a - b;
assign max_dat = c[4] ? b:a ; //这里假设c为5bit数,最高位c[4]为符号位
assign min_dat = c[4] ? a:b;
这样a,b就只需要比较一次;
3、begin-end和always语句中非阻塞式赋值的执行顺序
本科上课时,老师说非阻塞式赋值,先靠近end的部分先被执行,后来自己试了下,并不是这样。以下两个always语句块为例,各个变量变换之前,都是按clk上升沿到来前的值算的
。若clk上升沿到来前,a_1d为1,a为2,b为3,则clk上升沿到来时,a_2d变为1,a_1d变为2,a变为3,与这三条赋值语句的书写顺序和是否靠近end无关。
always(posedge clk)
begin
a_2d <= a_1d;
a_1d <= a;
end
always(posedge clk)
begin
a <= b;
end
4、python辅助verilog编程的技巧
假如有一个数组a[15:0]和数组b[255:0], 当输入cnt为0时,a = b[15:0];cnt为1时,a=b[31:16];
依次类推,当cnt为15时,a=b[255: 240];如果我们用case语句来实现这个功能,就要写16个不同情况,但这些情况都是有规律可循的。这时候就可以考虑用python来生成语句。
python代码如下所示:
s = 'case(cnt)'
print(s)
for i in range(16):
s = ' 4\'d'+str(i)+': begin\n'
s = s + ' a = b['+str(i*16+15)+' : '+str(i*16)+'];\n'
s = s + ' end'
print(s)
执行该语句后,print显示的内容如下所示:
case(cnt)
4'd0: begin
a = b[15 : 0];
end
4'd1: begin
a = b[31 : 16];
end
4'd2: begin
a = b[47 : 32];
end
4'd3: begin
a = b[63 : 48];
end
4'd4: begin
a = b[79 : 64];
end
4'd5: begin
a = b[95 : 80];
end
4'd6: begin
a = b[111 : 96];
end
4'd7: begin
a = b[127 : 112];
end
4'd8: begin
a = b[143 : 128];
end
4'd9: begin
a = b[159 : 144];
end
4'd10: begin
a = b[175 : 160];
end
4'd11: begin
a = b[191 : 176];
end
4'd12: begin
a = b[207 : 192];
end
4'd13: begin
a = b[223 : 208];
end
4'd14: begin
a = b[239 : 224];
end
4'd15: begin
a = b[255 : 240];
end
尽量不要自己挨个敲,容易算错
;
5、verilog中generate、genvar变量,for循环,及function的使用
generate的使用用如下几个需要注意的地方:
- a. 同一个文件中genvar循环变量名不能重复,也就是说,有几个循环就需要几个不同的genvar变量;
- b. genvar定义的变量不要在always语句中使用,可以用integer变量代替
- c. generate和for循环配合时必须有标签信息;
genrate语句感觉和always(*)语句的作用功能类似;
function的程序的定义和调用如下所示:
module comb15 (A, B, CIN, S, COUT);
input [3:0] A, B;
input CIN;
output [3:0] S;
output COUT;
wire [1:0] S0, S1, S2, S3;
function signed [1:0] ADD;
input A, B, CIN;
reg S, COUT;
begin
S = A ^ B ^ CIN;
COUT = (A&B) | (A&CIN) | (B&CIN);
ADD = {COUT, S};
end
endfunction
assign S0 = ADD (A[0], B[0], CIN),
S1 = ADD (A[1], B[1], S0[1]),
S2 = ADD (A[2], B[2], S1[1]),
S3 = ADD (A[3], B[3], S2[1]),
S = {S3[0], S2[0], S1[0], S0[0]},
COUT = S3[1];
endmodule
该程序来源于参考文章【2】。
6、条件判断中的同步信号和异步信号的区别
在always语句中,边沿信号一般被综合成寄存器的时钟或复位引脚处,而同步信号则一般在输入信号引脚处
;
异步复位如下所示
always@(posedge clk or negdge rst_n)
if(!rst_n)
Q <= 0;
else
Q <= din;
同步复位如下所示:
always@(posedge clk)
if(!rst)
Q <= 0;
else
Q <= din;
若同时存在同步和异步复位,则
always@(posedge clk or negdge rst_n)
if(!rst_n || !rst)
Q <= 0;
else
Q <= din;
如图所示, rst_n和rst的与运算完全没有必要,因此我们通常写为
always@(posedge clk or negdge rst_n)
if(!rst_n)
Q <= 0;
else if(!rst)
Q <= 0;
else
Q <= din;
即,if判断语句中不要同时出现同步信号和异步信号
;
7、case语句和if-else语句的区别
在数字IC设计中,对于较长的if-else语句,尽量用case语句替代;
比如 选择信号cnt为0时,a=a0; cnt为1时 a = a1; cnt = 2 时, a = a2; cnt = 3 , a = a3;
若用if-else if -else,则电路如下所示:
always(*)
if(cnt == 2'd0)
a = a0;
else if(cnt == 2'd1)
a = a1;
else if(cnt == 2'd2)
a = a2;
else
a = a3;
若是有case语句,则电路结构如下所示:
always(*)
case(cnt)
2'd0 : a=a0;
2'd1 : a=a1;
2'd2 : a=a2;
default : a=a3;
endcase
对比两张电路图可知,case语句的延时小于if语句,因此当条件较多时,我们尽量采用case语句
。
8、verilog中加法,减法,乘法运算的位宽分析及$signed符号所起的作用
为了弄清楚加法减法乘法以及$signed的作用,我们定义如下变量;
wire [3:0] a, b;
wire [7:0] c1,c2,c3,c4,c5,c6,c7,c8,c9;
分别运算
assign c1 = a * b;
assign c2 = $signed(a) * b;
assign c3 = $signed(a) * $signed(b);
assign c4 = a + b;
assign c5 = $signed(a) + b;
assign c6 = $signed(a) + $signed(b);
assign c7 = a - b;
assign c8 = $signed(a) - b;
assign c9 = $signed(a) - $signed(b);
令a = 4’b0110, b = 1110;
c1~c9波形如上所示,经分析可知:
- $signed的作用是在运算中,将$signed操作的变量视为有符号数,最高位为整数位,负数则视为补码;
- 若有符号数和无符号数运算(c1, c2, c4, c5, c7, c8)则一律视为无符号数进行运算;
- 若两个有符号数进行运算,则计算结果为有符号数,当位宽较大时,整数最高位补0,负数补1;
9、verilog的多维数组的排序问题
定义一个二维数组
[2: 0] [1:0] a;
a = 6'b11_0100;
波形如下所示:
因此verilog中多维数组的低地址到高地址的排序为:
a[0] = b[1:0]; a[1] = b[3:2]; a[3] = b[5:4];
参考资料
【1】【Verilog】generate和for循环的一些使用总结(1)
【2】Verilog 中 function 的使用
【3】异步复位、同步复位与异步复位同步释放
【4】verilog中的for 循环