1、 Verilog中的always过程块是通用的,不能反映准确的设计意图,SystemVerilog增加了硬件专用类型的过程块,能够准确反映设计意图,使模拟、综合、形式检查、lint检查等EDA工具精确地完成任务,并使不同的EDA工具保持一致性;SystemVerilog对任务和函数进行了许多改进,增强了任务和函数对大规模、复杂设计建模能力。组合逻辑过程块 锁存逻辑过程块 时序逻辑过程块 任务与函数的改进第6章 SystemVerilog过程块、任务和函数6.1 Verilog通用目的always过程块always过程块是一个能重复执行的语句块的无限循环,循环包括了时间控制或事件控制以使模拟时间
2、向前推进。always过程块用于对象建模,可以用作组合逻辑、锁存逻辑和时序逻辑的RTL建模,也可用于对算法建模及在测试平台中时钟的建模。always过程块通常包括敏感表,只有敏感表中的信号发生变化时,过程块才能被触发执行。由于always过程块是通用的,工具必须从过程块内容推断设计意图,加大软件工具的负担。Verilog RTL综合的IEEE1364.1标准中给出了always过程块的组合逻辑、锁存逻辑和时序逻辑的综合指导方针,但并不要求强制执行,且always的模拟与综合不依照同样的语法规则,使得模拟与综合结果不一致!6.2 SystemVerilog特有的过程块SystemVerilog增
3、加了3个能够明确表示设计意图的过程块:always_comb、always_latch和always_ff;如果特有的过程块的内容与其相应逻辑不匹配,软件工具会发出警告信息;特有过程块与always一样是无限循环的,在特有块中加入了限制建模类型的句法和语义的规则,从而与IEEE1364.1综合标准一致。通过使用always_comb、always_latch和always_ff过程块,不仅是软件工具,其它查看或维护此模型的设计人员也能够很清楚地了解设计思路,提高了代码的文档性。注意:并不是使用了always_comb、always_latch、always_ff过程块就一定会综合出对应的组合、
4、锁存、触发电路!6.2.1 组合逻辑过程块always_comb过程块表示建立组合逻辑模型,always_comb能推断出其敏感表,推断的敏感表包括所有在过程块外赋值并被过程块读取的信号及过程块中调用函数的有所信号(但局部的临时变量除外)。禁止出现共享变量:always_comb过程要求被赋值的变量不能再次在其它过程块被赋值,以符合综合要求。always_comb过程块在所有的initial和always过程块启动后,会在模拟的0时刻自动触发,该特殊主义确保了组合逻辑在0时刻产生与输入相对应的输出结果尤其是在使用两态变量建模时,0时刻自动求值显得尤为重要!6.2.1 组合逻辑过程块packag
5、e chip_types;typedef enum FETCH,WRITE,ADD,SUB,MULT,DIV,SHIFT,NOP instr_t;endpackageimport chip_types:*;module controller(output logic read,write,input instr_t instruction,input wire clk,resetN);enum WAIT,LOAD,STORE state,nextState;always(posedge clk,negedge resetN)if(!resetN)state=WAIT;else state=ne
6、xtState;always(state)begin case(state)WAIT:nextState=LOAD;LOAD:nextState=STORE;仅当state变化时才触发6.2.1 组合逻辑过程块 STORE:nextState=WAIT;endcase end always(state,instruction)begin read=0;write=0;if(state=LOAD&instruction=FETCH)read=1;if(state=STORE&instruction=WRITE)write=1;endendmodulestate和nextState为枚举类型,枚举
7、标签WAIT代表的值为0,无论resetN有效否,state的值不会改变,why?6.2.1 组合逻辑过程块package chip_types;typedef enum FETCH,WRITE,ADD,SUB,MULT,DIV,SHIFT,NOP instr_t;endpackageimport chip_types:*;module controller(output logic read,write,input instr_t instruction,input wire clk,resetN);enum WAIT,LOAD,STORE state,nextState;always(po
8、sedge clk,negedge resetN)if(!resetN)state=WAIT;else state=nextState;always_comb begin case(state)WAIT:nextState=LOAD;LOAD:nextState=STORE;推断出(state),即使不被触发,在0时刻也会自动执行。6.2.1 组合逻辑过程块always_comb and always*always*没有组合逻辑语义,只能是在敏感表有变化时才执行*仅仅是一种推断事件控制列表信号的语句,可在过程块内部使用1.*推断的敏感表可能不完整:不能推断出函数调用引用的模块级信号always
9、*begin a1=data 1;b1=decode();endalways_comb begin a2=data 1;b2=decode();endfunction decode;begin case(sel)2b01:decode=d|e;2b11:decode=d&e;default:decode=c;endcase endendfunction只推断出(data)推断出(data,sel,d,e,c)6.2.2 锁存逻辑过程块always_latch过程块表示描述的是基于锁存器的逻辑,always_latch过程块的语义规则与always_comb一样,能够推断出敏感表;在锁存逻辑中,
10、过程块的输出变量不需要对所有可能的输入条件响应;同样always_latch中赋值的变量不能再次在其它过程块被赋值;always_latch过程块也会在0时刻自动执行一次。/使用always_latch过程块锁存输入脉冲module register_reader(output logic 4:0 read_p,input clk,ready,resetn);logic enable,overflow;always_latch begin if(!resetn)enable=0;else if(ready)enable=1;else if(overflow)enable=0;end alway
11、s(posedge clk,negedge resetn)begin if(!resetn)overflow,read_p=0;else if(enable)overflow,read_p=read_p+1;endendmodulealways_latch if(enable)q=d;/always_comb/if(enable)q=d;6.2.3 时序逻辑过程块always_ff过程块描述时序逻辑,always_ff过程块的敏感表必须列出,以确定时序逻辑的置位/复位是同步还是异步的,如果代码不能综合出时序逻辑时,软件工具能够报告警告信息。always_ff过程块要求明确指定敏感表中的信号是p
12、osedge还是negedge,这是对时序逻辑敏感列表的综合要求,以确保模拟结果与综合结果一致。always_ff过程块禁止在块开头以外的地方使用事件控制!always_ff (posedge clk,negedge resetn)if(!resetn)state=st0;else state=next_state;6.3 对任务和函数的改进任务和函数的隐式语句组:Verilog中,如果任务或函数包含多条语句时必须写在begin end之间,对任务也允许使用fork join结构,对SystemVerilog则可以省略begin end。function states_t nextState(
13、states_t state);nextState=state;case(state)WAIT:if(start)nextState=LOAD;LOAD:if(done)nextState=STORE;STORE:nextState=WAIT;endcaseendfunction6.3 对任务和函数的改进返回函数值:return语句的优先级高于用函数名返回值function add_and_inc(input 31:0 a,b);begin add_and_inc=a+b+1;endendfunctionfunction add_and_inc(input 31:0 a,b);return a
14、+b+1;endfunctionfunction add_and_inc(input 31:0 a,b);add_and_inc=a+b;return+add_and_inc;endfunction6.3 对任务和函数的改进在任务和函数结束前返回:Verilog必须到达任务或函数结尾才能退出function automatic int log2(input int n);if(n 1)begin n=n/2;log2=log2+1;end endendfunctionfunction automatic int log2(input int n);if(n 1)begin n=n/2;log2
15、+;end endfunction6.3 对任务和函数的改进void类型函数:void函数无返回值;与通常函数语法和语义限制一样,如不能包含任何类型的延迟或事件控制,也不能使用非阻塞赋值语句;void函数可以象任务一样被调用;void函数可以有output和inout的形式参数;void函数克服了函数不能调用任务的缺陷。typedef struct logic valid;logic 7:0 check;logic 63:0 data;packet_t;function void fill_packet(input logic 63:0 data_in,output packet_t data
16、_out);data_out.data=data_in;foreach(data_out.checki)data_out.checki=data_in(8*i)+:8;data_out.valid=1;endfunction6.3 对任务和函数的改进使用名称传递任务或函数的参数:任务或函数调用时,Verilog只允许按照任务或函数的形式参数的顺序来传递参数,否则就会出现编码错误,SystemVerilog可以使用形式参数的名称而不是顺序来传递参数值,以减少错误。always(posedge clk)result =divide(b,a);function int divide(input in
17、t numerator,denominator);if(denominator=0)begin$display(“Error!divided by zero”);return 0;end else return(numerator/denomirator);endfunction/result =divide(.denomirator(b),.numerator(a);6.3 对任务和函数的改进增强型函数形式参数:Verilog的函数只允许有input,唯一的输出就是它的返回值,SystemVerilog的函数可以象任务一样声明input、output和inout类型的形式参数,扩展了函数的建
18、模范围。对带输出的函数调用限制:不能在以下情况中调用(从综合角度考虑)事件表达式 使用过程持续赋值的表达式 不在过程语句内的表达式无形式参数的函数:Verilog要求函数至少有一个输入形式参数,SystemVerilog允许函数没有形式参数function 63:0 add(input 63:0 a,b,output overflow);overflow,add=a+b;endfunction6.3 对任务和函数的改进形式参数的缺省方向和类型:Verilog中函数的每个形式参数必须显式声明为input,而任务的每个形式参数必须显式声明为input、output或inout,方向声明后面可以跟着
19、逗号分隔的参数列表;SystemVerilog简化了任务和函数声明语法,形式参数的缺省方向为input,缺省类型为logic。function integer compare(input integer a,input integer b);endfunctiontask mytask(input a,b,output y1,y2);endtaskfunction int compare(int a,b);task mytask(a,b,output y1,y2);endfunction endtask6.3 对任务和函数的改进缺省的形式参数值:SystemVerilog允许任务与函数为每个形
20、式参数设置一个可选的缺省值,设定缺省值的语法与设置变量初始值的语法类似,设定缺省值的任务或函数调用时,可以对形式参数全部指定、部分指定或不指定值,如果不指定值,则使用缺省的值。如果对没有缺省形式参数值的任务或函数调用时不传递值给形式参数,系统会报告一个错误。function int incrementer(int count=0,step=1);incrementer=count+step;endfunctionalways(posedge clk)result=increment(data_bus);SystemVerilog允许任务或函数的实际参数数目小于形式参数数目!6.3 对任务和函数
21、的改进数组、结构体和联合体作为形式参数:SystemVerilog允许压缩或非压缩数组、结构体或联合体传递进/出任务和函数;对于结构体和联合体,形式参数必须定义为用户自定义类型。typedef struct logic valid;logic 7:0 check;logic 63:0 data;packet_t;function void fill_packet(input logic 7:0 data_in 7:0,output packet_t data_out);for(int i=0;i=7;i+)begin data_out.data(8*i)+:8=data_ini;data_ou
22、t.checki=data_ini;end data_out.valid=1;endfunction6.3 对任务和函数的改进用引用取代复制来传递参数值:任务或函数调用时,通常是将输入复制后传递给任务或函数;Verilog通过使用外部名称方式隐含传递参数给任务或函数;SystemVerilog可以显式地通过引用的方法传递参数给任务或函数,在形式参数说明中,用ref代替input、output和inout方向关键词。ref形式参数是实际值的别名,通过引用传递,变量只需要在调用部分声明,而不需要在任务或函数描述时再次声明,这样,任务或函数只在它调用的范围内引用这个变量。注意:只有自动函数或任务才可
23、以具有ref参数!6.3 对任务和函数的改进module chip();typedef struct logic valid;logic 7:0 check;logic 63:0 data;packet_t;packet_t data_packet;bit 7:0 raw_data 0:7;always(posedge clk)if(data_ready)fill_packet(.data_in(raw_data,.data_out(data_packet);function automatic void fill_packet(ref logic 7:0 data_in 7:0,ref pa
24、cket_t data_out);for(int i=0;i=7;i+)begin data_out.data(8*i)+:8=data_ini;data_out.checki=data_ini;end data_out.valid=1;endfunction endmodule6.3 对任务和函数的改进只读引用参数:通过将形式参数说明为const ref类型,只允许对引用对象进行读操作,而禁止任务或函数改动对象内容。function automatic void fill_packet(const ref logic 7:0 data_in 7:0,ref packet_t data_out
25、);endfunction对使用ref参数的函数调用限制:与带有输出形参函数调用限制相同,不能被以下几种情况调用:事件表达式 使用过程持续赋值的表达式 不在过程语句内的表达式 6.3 对任务和函数的改进任务ref参数对变化敏感:任务ref参数的一个重要特点是任务中的逻辑会对信号在调用程序内发生的变化敏感,由于函数必须零延时执行,所有函数ref参数不能包含对变化敏感的时间控制。typedef struct logic vaild;logic 7:0 check;logic 63:0 data;packet_t;packet_t send_pkt,received_pkt;task automat
26、ic check_results(input packet_t sent,ref packed_t received,ref logic done);static int error_cnt;wait(done)if(sent!=received)begin error_cnt+;$display(“ERROR!received bad packet”);endendtask 1.ref参数可以读取当前值2.ref参数可以立即传播变化而不是等到任务结束时才反映6.3 对任务和函数的改进命名的任务和函数结尾:SystemVerilog允许在任务和函数的结尾处用关键字endtask和endfunc
27、tion后面跟任务名和函数名。function int add_and_inc(int a,b)return a+b+1;endfunction:add_and_inctask automatic check_results(input packet_t sent;ref packet_t received;ref logic done);static int error_cnt;endtask:check_results空任务和空函数:SystemVerilog允许任务和函数不包含任何语句,空函数将返回表示函数名的隐含变量的当前值。空任务和空函数在非完整代码中预留出了空间,用于自顶向下建模。