• verilog不常规用法


    一、位宽统计

     Verilog定义计算位宽的函数clog2

    在很多情况下要计算输入输出的位宽,比如你写一个8*8的ram,那么地址需要三位去表示,那么这个函数的方便就体现出来了,你需要使用函数定义就好了。对于一个数值的位宽求取,和数学中求log2()对应,因此函数名是

    1. //位宽计算函数
    2. function integer clog2 (input integer depth);
    3. begin
    4. for (clog2=0; depth>0; clog2=clog2+1)
    5. depth = depth >>1;
    6. end
    7. endfunction

     举个栗子

    1. parameter p_cnt_max = p_rev_time*p_clk_fre*1000_000 - 1; //翻转时间内所需计数的最大值
    2. //位宽计算函数
    3. function integer clog2 (input integer depth);
    4. begin
    5. for (clog2=0; depth>0; clog2=clog2+1)
    6. depth = depth >>1;
    7. end
    8. endfunction
    9. wire [clog2(p_cnt_max)-1:0] w_cnt_max;

    二、宏定义

    有了宏的帮助我们就可以将大量重复的功能放入宏中,然后在程序中直接写上一句宏即可。这样做的好处是,对我们整体代码以及综合后的结果没有任何影响,因为宏在编译的时候就已展开。

    普通的写法

    1. always @(posedge clk)
    2. begin
    3. case(counter)
    4. 32'd1: begin answer=1/3; signal=0;signal=1;end
    5. 32'd2: begin answer=2/3; signal=0;signal=1;end
    6. 32'd3: begin answer=3/3; signal=0;signal=1;end
    7. ...
    8. 32'd16: begin answer=16/3;signal=0;signal=1;end
    9. endcase
    10. end

    使用宏定义的写法

    1. always @(posedge clk)
    2. begin
    3. case(counter)
    4. 32'd1: `div(1)
    5. 32'd2: `div(2)
    6. 32'd3: `div(3)
    7. ...
    8. 32'd15: `div(16)
    9. endcase
    10. end
    11. `define div(x) begin signal=0; \
    12. answer=x/3; \
    13. signal=1; \
    14. end

    注意事项:那个 div (1) 的分号哪去了?  有人会告诉我说,verilog 里宏就是一个简单的替代,你若在 `div (x) 后面加一个分号,那么展开后将会是

    1. begin signal=0;
    2. answer=x/3;
    3. signal=1;
    4. end;

    在 end; 后面加上分号语法是不对的。

    三、repeat循环

    1. repeat (loop_times) begin
    2. end

    repeat 的功能是执行固定次数的循环,它不能像 while 循环那样用一个逻辑表达式来确定循环是否继续执行。repeat 循环的次数必须是一个常量、变量或信号。如果循环次数是变量信号,则循环次数是开始执行 repeat 循环时变量信号的值。即便执行期间,循环次数代表的变量信号值发生了变化,repeat 执行次数也不会改变。

    下面 repeat 循环例子,实现了与 while 循环中的例子一样的效果。

    1. // repeat 循环语句
    2. reg [3:0] counter3 ;
    3. initial begin
    4. counter3 = 'b0 ;
    5. repeat (11) begin //重复11次
    6. #10 ;
    7. counter3 = counter3 + 1'b1 ;
    8. end
    9. end

    下面 repeat 循环例子,实现了连续存储 8 个数据的功能:

    1. always @(posedge clk or negedge rstn) begin
    2. j = 0 ;
    3. if (!rstn) begin
    4. repeat (8) begin
    5. buffer[j] <= 'b0 ; //没有延迟的赋值,即同时赋值为0
    6. j = j + 1 ;
    7. end
    8. end
    9. else if (enable) begin
    10. repeat (8) begin
    11. @(posedge clk) buffer[j] <= counter3 ; //在下一个clk的上升沿赋值
    12. j = j + 1 ;
    13. end
    14. end
    15. end

    rstn 拉高时,buffer 的 8 个向量同时赋值为 0。

    第二个时钟周期后,buffer 依次被 counter3 赋值,实现了连续存储 8 个数据的功能。

    四、forever 循环

    forever 循环语法格式如下:

    1. forever begin
    2. end

    forever 语句表示永久循环,不包含任何条件表达式,一旦执行便无限的执行下去,系统函数 $finish 可退出 forever。

    forever 相当于 while(1) 。

    通常,forever 循环是和时序控制结构配合使用的。

    例如,使用 forever 语句产生一个时钟:

    1. reg clk ;
    2. initial begin
    3. clk = 0 ;
    4. forever begin
    5. clk = ~clk ;
    6. #5 ;
    7. end
    8. end

    例如,使用 forever 语句实现一个时钟边沿控制的寄存器间数据传输功能:

    1. reg clk ;
    2. reg data_in, data_temp ;
    3. initial begin
    4. forever @(posedge clk) data_temp = data_in ;
    5. end

  • 相关阅读:
    如何快速解决或避免EDI系统磁盘空间不足?
    .NET混合开发解决方案11 WebView2加载的网页中JS调用C#方法
    proxy配置
    SCB-Dataset3 公开 学生课堂行为数据集: A Benchmark for Detecting Student Classroom Behavior
    GZ038 物联网应用开发赛题第4套
    SSM框架学习——Spring之核心容器总结
    多商户商城系统功能拆解41讲-平台端应用-客服设置
    nginx启动报错纠正
    Vue3:ref和reactive实现响应式数据
    【代码审计】——PHP项目类RCE及文件包含下载删除
  • 原文地址:https://blog.csdn.net/baidu_25816669/article/details/128196932