数字IC设计经验整理(一)

数字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波形如上所示,经分析可知:

  1. $signed的作用是在运算中,将$signed操作的变量视为有符号数,最高位为整数位,负数则视为补码;
  2. 若有符号数和无符号数运算(c1, c2, c4, c5, c7, c8)则一律视为无符号数进行运算;
  3. 若两个有符号数进行运算,则计算结果为有符号数,当位宽较大时,整数最高位补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 循环

  • 4
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

皮皮宽

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值