verilog初识-initial、always、task、function、递归函数automatic

verilog初识-initial、always、task、function

1.initial

一个程序中可以有多个initial语句块,多个initial说明语句并行执行,一个initial语句块仅执行一次
initial多用于对变量的初始化。
如:(1)用initial块对存储器变量初始化

inital
	begin
		areg = 0;	//初始化寄存器变量areg
		for(index = 0; index < size; index = index + 1)
			meory[index] = 0;	//初始化memory变量
	end

(2)用initial语句生成激励波形

initial 
	begin
		inputs = b'0000;	//初始时刻inputs为0
		#10 inputs = b'1010;	//在第10个单位时间后改变inputs的值
		#10 inputs = b'0101;	//在第20个单位时间后改变inputs的值
	end

2.always

一个程序中可以有多个always语句块,每个always说明语句在仿真的开始同时执行;always语句不断重复地执行,直到仿真结束。always语句后紧跟的过程块是否运行,要看它的触发条件是否满足,一旦触发条件满足,则运行过程块,直至仿真过程结束。
其声明结构如下:
always (时序控制) 语句
always如果没有时序控制,会使仿真器产生死锁。如:
always areg = ~areg;
这条语句会生成一个0延迟的无限循环跳变过程,会导致仿真器发生死锁。
正确的使用方法如:
always #period areg = ~arge;
这条语句生产了一个周期位2*period的无限延续的波形信号,常用这种方法来描述时钟信号。
如:
reg [7:0] counter;
reg tick;
always @(posedge areg)
begin
tick = ~tick; //在每一个arge信号上升沿到来时,tick翻转,同时counter计数加1
counter = counter + 1;
end
always块的事件控制:

  • OR事件控制(其中“or”也可以使用“,”进行替换)
    • 使用电平触发的always语句块:
      如:描述一个异步复位的的触发器
      always @(reset or clock or d) //当reset、clock、d中任意一个信号位高电平时执行always语句块
      //等价于 always @(reset, clock, d)
      begin
      if(reset) q = 1’b0;//复位时,q值初始化为0
      else if(clock)
      q = d; //当clock信号为高时,锁存输入信号d
      end
    • 使用沿触发的always语句块
      如:
      always @(posedge clk, negedge reset)//此处,代替or
      begin
      if(!reset) q <= 1’b0;
      else q <= d; //在每个clk的上升沿到来时,锁存输入信号d
      end
    • @*@(*),表示对其后面语句块中所有输入变量的变化都是敏感的
      如:
      always @(*)等价于always @( a or b or c or d or e or f)
      begin
      out1 = a?b:c;
      out2 = d?e:f;
      end
  • 电平敏感时序控制
    使用关键字wait来表示等待电平敏感的条件为真
    如:
    always
    wait(count_en) #20 count=count+1; //当count_en为1时,延迟20个单位时间,count加1,否则count值保持不变

3.task

task的特点:

  • 任务可以定义自己的仿真时间;
  • 任务能启动其他任务和函数;
  • 任务可以没有或有多个任务类型的变量;
  • 任务不需要返回值。
    task说明语句的语法结构为:
    task 任务名;
    端口及数据类型声明语句;
    语句1;
    语句2;

    语句n;
    endtask
    任务的调用结构如下:
    任务名(端口1,端口2,…,端口n);
    如:
    (1)任务定义:
    task my_task;
    input a,b;
    inout c;
    output d,e;

    c = f1;
    d = f2;
    e = f3;
    endtask
    任务调用:my_task(v,w,x,y,z);含义为:任务启动时,将v、w、x变量赋值给a、b、c,任务结束时,将c、d、e的值赋给x、y、z。
    如:描述红黄绿交通灯行为:
module traffic_lights;	//定义模块名为traffic_lights
	reg clock,red,amber,green;	//定义变量
	parameter on = 1,off = 0, red_tics = 350, amber_tics = 30, green_tics = 200;	//定义参数

	initial red = off;//初始化变量
	initial amber = off;
	initial green = off;
	always
	begin
		red = on;
		light(red,red_tics);//调用任务light
		green = on;
		light(green,green_tics);
		amber = on;
		light(amber,amber_tics);
	end
	
	task light;
	output color;
	input [31:0] tics;
	begin
		repeat(tics);
		always @(posedge clock)//在clock上升沿到来时,灭灯
			color = off;
	end
	endtask
	
	always	#100 clock = ~clock;//产生时钟脉冲
endmodule

4.function

function的特点:

  • 函数只能与主模块共用同一个仿真时间单位;
  • 函数不能启动任务;
  • 函数至少要有一个输入变量;
  • 函数的目的是返回一个用于表达式的值。
    函数的语法结构为:
    function (返回值的类型或范围) 函数名;
    端口说明语句;
    变量类型说明语句;
    begin
    语句块

    end
    endfunction
    tips:
    “返回值的类型或范围”为可选项,默认时返回值为一位寄存器类型数据。
    如:
    function [7:0] getbyte;
    input [15:0] address;
    begin

    getbyte = result_expression;//将结果赋予函数的返回字节
    end
    endfunction
    函数的调用:
    函数名(表达式,…,表达式)
    如:
    word = control?{getbyte(msbyte),getbyte(lsbyte)}:0;//control为1时,将getbyte函数的高字节与低字节拼接后赋给word,否则对word清0
    如:阶乘函数的定义和调用
module tryfact;

	function [31:0] factorial;
		input [3:0] operand;
		reg [3:0] index;
		begin
		factorial = 1;//0和1的阶乘均为1
		for(index=2;index<=operand;index=index+1)
			factorial = index*factorial;//n的阶乘=n*(n-1)*(n-2)*...*1
		end
	endfunction
	
	reg [31:0] result;
	reg [3:0] n;
	initial
	begin
		result =1;
		for(n=2;n<=9;n=n+1)
		begin
			$display("partial result n=%d result =%d",n,result);
			result = n*factorial(n-1);//调用函数factorial
		end
		$display("finalresult=%d",result);
	end
endmodule
  • 递归函数(自动函数)
    verilog中的函数不能够进行递归调用,因为设计模块中若某函数在两个不同的地方被同时并发调用,由于这两个调用同时对同一块地址空间进行操作,那么计算结果将是不确定的。
    verilog中函数声明时使用关键字automatic,将函数变为自动或可递归的,即仿真器为每一次函数调用动态地分配新的地址空间,每一个函数调用对各自的地址空间进行操作。因此,自动函数中声明的局部变量不能通过层次名进行访问。而自动函数本身可以通过层次名进行调用。
    如:
module top;
...
function automatic integer factorial;
input [31:0] oper;
interger i;
begin
	if(oper >= 2) factorial=factorial(oper-1)*oper;
	else factorial = 1;
end
endfunction

integer result;
intial
begin
	result = factorial(4);
	$display("factorial of 4 is %d",result);
end

endmodule
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值