Verilog定义计算位宽的函数clog2
在很多情况下要计算输入输出的位宽,比如你写一个8*8的ram,那么地址需要三位去表示,那么这个函数的方便就体现出来了,你需要使用函数定义就好了。对于一个数值的位宽求取,和数学中求log2()对应,因此函数名是
//位宽计算函数
function integer clog2 (input integer depth);
begin
for (clog2=0; depth>0; clog2=clog2+1)
depth = depth >>1;
end
endfunction
举个栗子
parameter p_cnt_max = p_rev_time*p_clk_fre*1000_000 - 1; //翻转时间内所需计数的最大值
//位宽计算函数
function integer clog2 (input integer depth);
begin
for (clog2=0; depth>0; clog2=clog2+1)
depth = depth >>1;
end
endfunction
wire [clog2(p_cnt_max)-1:0] w_cnt_max;
有了宏的帮助我们就可以将大量重复的功能放入宏中,然后在程序中直接写上一句宏即可。这样做的好处是,对我们整体代码以及综合后的结果没有任何影响,因为宏在编译的时候就已展开。
普通的写法
always @(posedge clk)
begin
case(counter)
32'd1: begin answer=1/3; signal=0;signal=1;end
32'd2: begin answer=2/3; signal=0;signal=1;end
32'd3: begin answer=3/3; signal=0;signal=1;end
...
32'd16: begin answer=16/3;signal=0;signal=1;end
endcase
end
使用宏定义的写法
always @(posedge clk)
begin
case(counter)
32'd1: `div(1)
32'd2: `div(2)
32'd3: `div(3)
...
32'd15: `div(16)
endcase
end
`define div(x) begin signal=0; \
answer=x/3; \
signal=1; \
end
注意事项:那个 div (1) 的分号哪去了? 有人会告诉我说,verilog 里宏就是一个简单的替代,你若在 `div (x) 后面加一个分号,那么展开后将会是
begin signal=0;
answer=x/3;
signal=1;
end;
在 end; 后面加上分号语法是不对的。
repeat (loop_times) begin
…
end
repeat 的功能是执行固定次数的循环,它不能像 while 循环那样用一个逻辑表达式来确定循环是否继续执行。repeat 循环的次数必须是一个常量、变量或信号。如果循环次数是变量信号,则循环次数是开始执行 repeat 循环时变量信号的值。即便执行期间,循环次数代表的变量信号值发生了变化,repeat 执行次数也不会改变。
下面 repeat 循环例子,实现了与 while 循环中的例子一样的效果。
// repeat 循环语句
reg [3:0] counter3 ;
initial begin
counter3 = 'b0 ;
repeat (11) begin //重复11次
#10 ;
counter3 = counter3 + 1'b1 ;
end
end
下面 repeat 循环例子,实现了连续存储 8 个数据的功能:
always @(posedge clk or negedge rstn) begin
j = 0 ;
if (!rstn) begin
repeat (8) begin
buffer[j] <= 'b0 ; //没有延迟的赋值,即同时赋值为0
j = j + 1 ;
end
end
else if (enable) begin
repeat (8) begin
@(posedge clk) buffer[j] <= counter3 ; //在下一个clk的上升沿赋值
j = j + 1 ;
end
end
end
rstn 拉高时,buffer 的 8 个向量同时赋值为 0。
第二个时钟周期后,buffer 依次被 counter3 赋值,实现了连续存储 8 个数据的功能。
forever 循环语法格式如下:
forever begin
…
end
forever 语句表示永久循环,不包含任何条件表达式,一旦执行便无限的执行下去,系统函数 $finish 可退出 forever。
forever 相当于 while(1) 。
通常,forever 循环是和时序控制结构配合使用的。
例如,使用 forever 语句产生一个时钟:
reg clk ;
initial begin
clk = 0 ;
forever begin
clk = ~clk ;
#5 ;
end
end
例如,使用 forever 语句实现一个时钟边沿控制的寄存器间数据传输功能:
reg clk ;
reg data_in, data_temp ;
initial begin
forever @(posedge clk) data_temp = data_in ;
end