Verilog定义计算位宽的函数clog2
在很多情况下要计算输入输出的位宽,比如你写一个8*8的ram,那么地址需要三位去表示,那么这个函数的方便就体现出来了,你需要使用函数定义就好了。对于一个数值的位宽求取,和数学中求log2()对应,因此函数名是
//位宽计算函数
function integer clog2 (input integer depth);
beginfor (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);
beginfor (clog2=0; depth>0; clog2=clog2+1) depth = depth >>1;
end
endfunctionwire [clog2(p_cnt_max)-1:0] w_cnt_max;
有了宏的帮助我们就可以将大量重复的功能放入宏中,然后在程序中直接写上一句宏即可。这样做的好处是,对我们整体代码以及综合后的结果没有任何影响,因为宏在编译的时候就已展开。
普通的写法
always @(posedge clk)begincase(counter)32'd1: begin answer=1/3; signal=0;signal=1;end32'd2: begin answer=2/3; signal=0;signal=1;end32'd3: begin answer=3/3; signal=0;signal=1;end...32'd16: begin answer=16/3;signal=0;signal=1;endendcaseend
使用宏定义的写法
always @(posedge clk)
begincase(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 begincounter3 = 'b0 ;repeat (11) begin //重复11次#10 ;counter3 = counter3 + 1'b1 ;end
end
下面 repeat 循环例子,实现了连续存储 8 个数据的功能:
always @(posedge clk or negedge rstn) beginj = 0 ;if (!rstn) beginrepeat (8) beginbuffer[j] <= 'b0 ; //没有延迟的赋值,即同时赋值为0j = j + 1 ;endendelse if (enable) beginrepeat (8) begin@(posedge clk) buffer[j] <= counter3 ; //在下一个clk的上升沿赋值j = j + 1 ;endend
end
rstn 拉高时,buffer 的 8 个向量同时赋值为 0。
第二个时钟周期后,buffer 依次被 counter3 赋值,实现了连续存储 8 个数据的功能。
forever 循环语法格式如下:
forever begin…
end
forever 语句表示永久循环,不包含任何条件表达式,一旦执行便无限的执行下去,系统函数 $finish 可退出 forever。
forever 相当于 while(1) 。
通常,forever 循环是和时序控制结构配合使用的。
例如,使用 forever 语句产生一个时钟:
reg clk ;
initial beginclk = 0 ;forever beginclk = ~clk ;#5 ;end
end
例如,使用 forever 语句实现一个时钟边沿控制的寄存器间数据传输功能:
reg clk ;
reg data_in, data_temp ;
initial beginforever @(posedge clk) data_temp = data_in ;
end
上一篇:NumPy数组维度
下一篇:C语言学习笔记(二二)