verilog HDL复习(一)
1、敏感列表
如果组合逻辑块语句的输入变量很多,编写敏感列表就很繁琐,针对这种情况,verilog提供了
两个特殊的符号:@ * 和@(*),他们都表示对其后面语句块中所有输入变量的变化是敏感的。
//@ *操作符的使用
//用or操作符的组合逻辑
//编写敏感列表很繁琐
always@(a or b or c or d or e or f or g or h or p or m) begin out1 = a ? b + c : d + e; out2 = f ? g + h : p + m; end
//不用上述方法,用符号@(*)代替,可以把所有的输入变量自动包括进敏感列表
always@(*) begin out1 = a ? b + c : d + e; out2 = f ? g + h : p + m; end
//or事件敏感列表
//有异步复位的电平敏感锁存器
always@(reset or clock or d) //等待复位信号reset或时钟信号clock,或者输入信号d的变化 begin if(reset) q = 1'b0; else if(clock) q = d; end
2、task...endtask
a.任务定义语法:
task <任务名>
<端口及数据类型声明语句>
<语句1>
<语句2>
.
.
.
<语句n>
endtask
b.任务的调用即变量的传递:
<任务名>(端口1,端口2,...,端口n)
例子:
1 task task_demo;//任务开头,命名为task_demo 2 input [7:0] x,y; //输入端口 3 output [7:0] tmp; //输出端口 4 5 if(x > y) 6 tmp = x; 7 else 8 tmp =y; 9 endtask
说明:
在任务定义的描述语句中,可以使用出现不可综合操作语句(使用最频繁的就是延迟控制语句),但这样会造成任务不可综合;
例子:描述红绿灯行为
1 module traffic_lights; 2 reg clock,red amber,green; 3 parameter on = 1,off = 0,red_tics = 350, 4 amber_tics = 30;green_tics = 200; 5 6 //交通灯初始化 7 initial red =off; 8 initial amber=off; 9 initial green=off; 10 11 //交通灯控制时序 12 always 13 begin 14 red=on;//开红灯 15 lights(red,red_tics);//调用任务等待 16 green=on; 17 lights(green,green_tics); 18 amber=on; 19 light(amber,amber_tics); 20 end 21 22 //定义交通灯开启时间的任务 23 task light; 24 output color; 25 input [31:0] tics; 26 begin 27 repeat(tics) 28 @(posedge clock) 29 color = off; 30 end 31 //产生时钟脉冲模块 32 always 33 begin 34 #100 clock = 0; 35 #100 clock = 1; 36 end 37 38 endmodule
注:
@(条件表达式) do_something;
表示等待条件表达式满足,然后do_something,然后就往下走了。通常用在testbench中,不可综合。
------------------------------------
always @(a or b or c) begin
do_something;
end
表示不停地监测a、b、c,一旦它们任何一个发生变化,就立刻do_something,并且这个“监测”是始终存在的。这种电路综合出来时组合逻辑电路。
3、function...endfunction
a.定义函数的语法:
function<返回值的类型或范围>(函数名)
<端口说明语句>
<变量类型说明语句>
begin
<语句>
... ...
endfunction
例子:
1 function [7:0] getbyte; 2 input [15:0] address; 3 begin 4 <说明语句> //从地址字中提取低字节的程序 5 getbyte=result_expression; //把结果赋值于函数的返回字节 6 end 7 endfunction
注:<返回值的类型或范围>是可选项,如果是一位寄存器类型数据。
b.函数的调用
<函数名>(<表达式>,...<表达式>)
例子:两次调用函数getbyte,把两次调用产生的值进行拼接运算以生成一个字。
word = control ? {getbyte(msbyte),getbyte(lsbyte)} : 0;
注:函数使用规则
a.函数的定义不能包括含有任何的时间控制语句,即任何用#、@、或wait来标示的语句;
b.函数不能启动任务;
c.定义函数时至少要有一个输入参量;
d.在函数的定义中必须有一条赋值语句给函数中得一个内部变量赋以函数的结果值,该内部变量具有和函数名相同的名字;
1 function [31:0] factorial; //函数定义 2 input [3:0] operand; 3 reg [3:0] index; 4 begin 5 factorial=operand ? 1:0; 6 for(index=2;index <= operand;index=index+1) 7 fortorial=index*fatorial; 8 end 9 endfunction
task和function说明语句的不同点:
a.函数只能与主模块共用同一个仿真时间单位,而任务可以定义自己的仿真时间单位。
b.函数不能启动任务,而任务能启动其他任务和函数。
c.函数至少要有一个输入变量,而任务可以没有或有多个任何类型的变量。
d.函数返回一个值,而任务则不返回值。