System Verilog——任务和函数 Part-I

System Verilog 可以说是Verilog+C的结合,在Verilog的基础上,引入了面向对象的思想,使得更有利于实现对电路的验证。因此很多时候需要对比Verilog,结合C,对比SV(System Verilog)的区别即可。
本博文简单介绍SV的任务函数的基本使用

Verilog中的task

主要参考菜鸟教程中的6.2 Verilog 任务,《Verilog HDL A guide to digital design and synthesis 2nd》这里简单进行总结。

task的声明

任务在模块中任意位置定义,并在模块内任意位置引用,作用范围也局限于此模块。
模块内子程序出现下面任意一个条件时,则必须使用任务而不能使用函数。
1)子程序中包含时序控制逻辑,例如延迟,事件控制等
2)没有输入变量(因为函数必须要有一个输入变量,任务可以没有)
3)没有输出或输出端的数量大于 1
(简单提一下,这里的函数就是一个输入,产生一个输出,因此没有输入,或者输出多余一个变量的时候,要将其划分为代码块儿时,必须使用任务)
Verilog 任务声明格式如下:

task [automatic] task_id ;
    port_declaration ;
    procedural_statement ;
endtask
| 
task [automatic] task_id (port_declaration );
	procedural_statement ;
endtask

[]:表示可选 |:表示或
任务中使用关键字 input、output 和 inout 对端口进行声明。input 、inout 型端口将变量从任务外部传递到内部,output、inout 型端口将任务执行完毕时的结果传回到外部调用语句的相应变量里。任务可以调用其他任务或函数。
这里使用的变量类型的声明,是用来传输变量的,与module里的端口声明本质上有所区别,端口上的是用来与外部信号连接的。

进行任务的逻辑设计时,可以把 input 声明的端口变量看做 wire 型,把 output 声明的端口变量看做 reg 型。但是不需要用 reg 对 output 端口再次说明。

对 output 信号赋值时也不要用关键字 assign。为避免时序错乱,建议 output 信号采用阻塞赋值。
实例1,该实例1的功能是声明一个bitwise_oper的任务,对输入的两个16bit变量a,b进行按位与,按位或和按位异或操作,两个十六位的计算的输出分别为ab_and,ab_or,ab_xor。同时还使用了一个delay参数进行延时。

//define task bitwise_oper
task bitwise_oper;
output [15:0] ab_and, ab_or, ab_xor; //outputs from the task
input [15:0] a, b; //inputs to the task
begin
#delay ab_and = a & b;
ab_or = a | b;
ab_xor = a ^ b;
end
endtask

或者使用如下形式进行声明

//define task bitwise_oper
task bitwise_oper (output [15:0] ab_and, ab_or, ab_xor,
input [15:0] a, b);
begin
#delay ab_and = a & b;
ab_or = a | b;
ab_xor = a ^ b;
end
endtask

task的使用实例

实例1

module operation;
parameter delay = 10;
reg [15:0] A, B;
reg [15:0] AB_AND, AB_OR, AB_XOR;
always @(A or B) //whenever A or B changes in value
begin
//invoke the task bitwise_oper. provide 2 input arguments A, B
//Expect 3 output arguments AB_AND, AB_OR, AB_XOR
//The arguments must be specified in the same order as they
//appear in the task declaration.
	bitwise_oper(AB_AND, AB_OR, AB_XOR, A, B);
end
//define task bitwise_oper
task bitwise_oper;
...
endtask

实例2

同样可以对模块内定义的变量进行赋值。如下实例可以对clock进行赋值,注意,该任务定义没有输入输出。

//Define a module that contains the task asymmetric_sequence
module sequence;
reg clock;
initial
init_sequence; //Invoke the task init_sequence
always
begin
asymmetric_sequence; //Invoke the task asymmetric_sequence
end
//Initialization sequence
task init_sequence;
begin
clock = 1'b0;
end
endtask
//define task to generate asymmetric sequence
//operate directly on the clock defined in the module.
task asymmetric_sequence;
begin
#12 clock = 1'b0;
#5 clock = 1'b1;
#3 clock = 1'b0;
#10 clock = 1'b1;
end
endtask
endmodule

关键字automatic

任务通常是静态的。所有声明的项都是静态分配的,它们在并发执行的任务的所有使用中共享。因此,如果从代码中的两个位置同时调用任务,则这些任务调用将对相同的任务变量进行操作。这种操作的结果很可能不正确。
为了避免此问题,在任务关键字前面添加了关键字automatic,以使任务重新进入。这种任务称为自动任务。自动任务中声明的所有项都会为每次调用动态分配。每个任务调用都在一个独立的空间中运行。因此,任务调用在任务变量的独立副本上运行。这将导致正确的操作。如果有可能从代码中的两个位置同时调用任务,建议使用自动任务。
实例略

System Verilog中的task

我们这里列出两者的不同之处,其他的与Verilog保持一致。

  • 默认端口方向:任何端口都视为输入,除非声明为其他类型。
    以下是端口类型
    input:copy value in at beginning(在开始时赋值)
    output copy value out at end
    inout:copy in at begin and out at end
    ref:pass reference
  • 默认数据类型:除非声明,否则都是logic类型
  • 无需使用begin end
  • 通过使用return语句变量,可以在endtask之前终止任务。
  • 变量:Systemverilog允许使用本地静态变量或本地动态变量。
  • 时间:Systemverilog允许一个任务是静态或者是自动的
  • 线网:线网型数据类型不能在端口列表中使用

System Verilog中task使用实例

实例1

module task_intro ();
initial begin
  #1 doInit(4,5);
  #1 doInit(9,6);
  #1 $finish;
end
task doInit (input bit [3:0] count, delay); 
  automatic reg [7:0] a;
  if (count > 5) begin
    $display ("@%g Returning from task", $time);
    return;
  end
  #(delay) $display ("@%g Value passed is %d", $time, count);
endtask
endmodule

仿真输出为

@6 Value passed is  4
@7 Returning from task

实例2

module traffic_lights;
logic clock, red, amber, green;
parameter 	on = 1, off = 0, red_tics = 350,
			amber_tics = 30, green_tics = 200;
// initialize colors
initial red = off;
initial amber = off;
initial green = off;
always begin // sequence to control the lights
	red = on; // turn red light on
	light(red, red_tics); // and wait.
	green = on; // turn green light on
	light(green, green_tics); // and wait.
	amber = on; // turn amber light on
	light(amber, amber_tics); // and wait.
end
// task to wait for 'tics' positive edge clocks
// before turning 'color' light off
task light (output color, input [31:0] tics);
	repeat (tics) @ (posedge clock);
	color = off; // turn light off.
endtask: light
always begin // waveform for the clock
	#100 clock = 0;
	#100 clock = 1;
end
endmodule: traffic_lights
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值