VERDVANA'S BLOG Verdvana

Verilog HDL的一些不常见语法


1 前言

        记录一下看到的奇奇怪怪的写法, 觉得不常见的。


2 for

        for循环语法为:

for(循环变量赋初值;循环结束条件;循环变量增值)
    执行语句

        八位乘法器实现:

parameter size = 8;
reg[size-1 : 0] opa,opb;
reg[size*2-1 : 0] result;
integer bindex;
result = 0;
for(bindex = 0;bindex <= size-1;bindex = bindex+1)
    if(opa[bindex])
        result = result + (opa<<(bindex));
end

        这是一个并行完全展开语句,而不是串行多周期执行。

        该代码实践的是一个全并行的加法器。for语句等效于将以下语句完全展开:

if(opa[bindex])
    result = result + (opa<<(bindex));

3 缩减运算符

wire    [3:0]   A;
wire            B;
assign B = &A;

       等效于:

assign  B = ((A[0]&A[1])&A[2])&A[3];

4 定义存储器模型(RAM)

(* ramstyle = "MLAB"*)reg[31:0] RegFile[15:0];

        RegFile对象在Altera FPGA中将被识别为16个32位位宽的RAM,且指定为MLAB类型。在ASIC设计中,这种描述方式只会被识别为一系列的寄存器堆,并不会识别为RAM。在ASIC中应当利用RAM单元库(IP)梨花的方法描述RAM。


5 task和function

5.1 task

        task概述:

  • 含有input、output、inout语句;
  • 可以调用function;
  • 消耗仿真时间:
    • 延迟:
            #20;
      
    • 时钟周期:
            @(posedge clock)
      
    • 事件:
            event
      

        举例:

task task_name
    parameter
    input
    output
    reg

    …text body…
endtask

5.2 function

        function概述:

  • 执行时不消耗仿真时间;
  • 不能有控制仿真时间的语句,例如task中的延时等;
  • 不能调用task;
  • void function没有返回值;

        function语法为:

funtion <返回值的类型或范围> (函数名)   
    <端口说明语句>              //input XXX
    <变量类型说明语句>          //reg   YYY
begin
    <语句>
    ……
    函数名 = zzz;               //函数名就相当于输出变量
end
endfuntion

        计算有符号数绝对值的例子:

function [width-1:0] DWF_absval;
input [width-1:0] A;
begin
    DWF_absval = ((^(A^A)!==1'b0))?{width{1'bx}} : (A[width-1] == 1'b0) ? A : -A;
end
endfunction

6 并发操作

        并发性是指对于所有并发线程,在仿真工具的当前仿真时间内,安排好的时间在仿真步进到下一個仿真时间之前都会执行完成。

        当一个线程执行时,只有遇到wait语句才会停止,例如:

wait(var_a == 1);

@(router.cb);

#1;

join_any;

join;

6.1 initial

        在整个仿真时间内只执行一次,各个initial语句并发执行。

6.2 always

        对组合和时序电路建模,always语句并发执行。

6.3 assign

        对组合电路建模,并发执行。

6.4 begin end

        内部语句从上往下顺序执行。

6.5 fork join

        内部语句并行执行,与顺序无关。例如:

initial begin
    Statement1;             //父线程,第1个执行
    #10 Statement2;         //父线程,第2个执行

    fork
        Statement3;         //子线程,第3个执行
        #50 Statement4;     //子线程,第7个执行
        #10 Statement5;     //子线程,第4个执行

        begin
            #20 Statement6; //子线程,第5个执行
            #10 Statement7; //子线程,第6个执行
        end

    join

    #30 Statement8;         //父线程,第8个执行
    Statement9;             //父线程,第9个执行
end

7 generate

7.1 for循环

        8位加法器例化过程:

generate
genvar i;
for(i=0;i<=7;i=i+1)
begin:for_name
    adder U_add(a[8*i+7:8*i],b[8*i+7:8*i],ci[i],sum_for[8*i+7:8*i],c0_or[i+i]);
end
endgenerate

        在for循环里使用always语句:

generate
genvar i;
for(i=0;i<11;i=i+1)
begin:iq_data_gen
    always@(*)begin
        iq[i*2]=i_in[i];
        iq[i*2+1]=q_in[i];
    end
endgenerate

7.2 if-else例化

        数据宽度不同乘法器的例化过程:

generate
if(IF_WIDTH<10)
begin:if_name
    multiplier_imp1#(IF_WIDTH) u1 (a,b,sum_if);
end
else
begin:else_name
    multiplier_imp2#(IF_WIDTH) u2 (a,b,sum_if);
end
endgenerate

7.3 generate-case例化

        数据宽度不同乘法器的例化过程:

generate
case(WIDTH)
1:begin:case1_name
    adder#(WIDTH*8) x1 (a,b,ci,sum_case,c0_case);
end

2:begin:case2_name
    adder#(WIDTH*8) x2 (a,b,ci,sum_case,c0_case);
end

default:begin:d_case_name
    adder# x3 (a,b,ci,sum_case,c0_case);
end
endcase
endgenerate

8 宽度定义

wire [A+:B] X ;
wire [C-:D] Y ;

        X的宽度为B,高位为(A+B),低位为B。

        Y的宽度为D,高位为C,低位为(C-D)。


9 运算符

        这个不少见,只是总结一下:

符号 含义 备注
~ 按位取反 将多位操作数按位取反:a=4’b1001,~a=4’b0110
! 逻辑取反 将操作数逻辑取反:操作数为0,取反结果为1;操作数不为0,取反结果为0
& 按位与 两个多位操作数按位进行与运算:a=4’b1001,b=4’b0011,a&b=4’b0001
&& 逻辑与 对两个操作数进行逻辑与:两者相同结果为1,否则为0
| 按位或 两个多位操作数按位进行或运算:a=4’b1001,b=4’b0011,a|b=4’b1011
|| 逻辑或 对两个操作数进行逻辑或:二者其中至少有一个不为0,则结果为1;否则为0
^ 按位异或 两个多位操作数按位进行异或操作:a=4’b1001,b=4’b0011,a^b=4’b1010
^~或~^ 按位同或 两个多位操作数按位进行同或操作:a=4’b1001,b=4’b0011,a^b=4’b0101

10 系统函数

10.1 随机

        返回一个32位的有符号的随机数:

$random(seed);  //seed:传递参数

        返回一个32位的无符号的随机数:

$urandom(seed);  //seed:传递参数

        生成有一定范围的无符号的随机数:

$urandom_range(min,max);  

        随机选择有权重的可执行语句:

randcase
    10:f10;                 //10%概率执行
    20:f20;                 //20%概率执行
    40:x=100;               //40%概率执行
    30:randcase …… endcase; //30%概率执行,嵌套
endcase

10.2 停止

        停止运行:

$stop;  

        告辞。