理论教育 FPGA设计:结构声明语句

FPGA设计:结构声明语句

时间:2023-11-20 理论教育 版权反馈
【摘要】:Verilog HDL的任何过程模块都是放在结构声明语句中的,结构声明语句包括always块语句、initial语句、task语句和function语句4种结构。1)利用initial语句生成激励波形2)对各变量进行初始化3.task语句在Verilog HDL模块中,task语句用来定义任务。希望能够对一些信号进行一些运算并输出多个结果时,宜采用task语句结构。②定义任务时,没有端口名列表,但要进行端口和数据类型的声明,任务用顺序语句完成功能的描述。

FPGA设计:结构声明语句

Verilog HDL的任何过程模块都是放在结构声明语句中的,结构声明语句包括always块语句、initial语句、task语句和function语句4种结构。

always块语句——不断重复执行,直到运行结束。

initial语句——只执行一次。

task语句——可在程序模块中的一处或多处被调用。

function语句——可在程序模块中的一处或多处被调用。

1.always块语句

在一个Verilog HDL模块中,always块语句的使用次数是不受限制的,块内的语句也是不断重复执行的。always块语句的语法结构为

在always块语句中,敏感变量表达式中应该列出影响块内取值的所有变量(一般指设计电路的输入变量或者其他结构声明语句中的reg型变量),多个变量之间用“or”分隔(也可以用逗号“,”分隔)。当表达式中任何变量发生变化时,系统就会执行一遍块内的语句。块内语句可以包括过程赋值、if、case、for、while、repeat、task和function等语句。

在always块中被赋值的只能是register型变量(如reg型、integer型、real型和time型)。

每个always块在仿真一开始便开始执行,执行完块中最后一个语句后,继续从always块的开头执行。

在进行时序逻辑电路描述时,敏感变量表达式中经常使用“posedge”和“negedge”这两个关键字来声明事件是由时钟的正边沿(上升沿)或负边沿(下降沿)触发的。若clk是设计电路的时钟变量,则“always@(posedge clk)”表示模块的事件是由clk的上升沿触发的,而“always@(negedge clk)”表示模块的事件是由clk的下降沿触发的。在8位二进制加法计数器的模块中,就使用了这类语句(见例6-2)。

在进行组合逻辑电路描述时,敏感变量表达式中不使用边沿触发“posedge”和“negedge”这两个关键字,而是使用电平触发,多个变量之间用“or”分隔(也可以用逗号“,”分隔)。

always块语句是用于综合过程的最有用的语句之一,为得到最好的综合效果,always块程序应严格按以下模板来编写。

①模板1:

②模板2:

③模板3:

④模板4:

注意:

(1)当always块语句中有多个敏感信号时,一定要采用if-else if语句,而不能采用并列的if语句,否则易造成一个寄存器由多个时钟驱动,出现编译错误。正确语句示例如下:

(2)通常采用异步清零,只有在时钟周期很小或清零信号为电平信号(容易捕捉到清零信号)时采用同步清零,即在敏感列表中不写negedge reset信号。

2.initial语句

initial语句的语法格式为

initial语句的使用次数也是不受限制的,其特点与always块语句相同,不同之处在于其块内的语句仅执行一次(不重复),因此initial语句常用于设计电路的初始化数据设置和仿真。

1)利用initial语句生成激励波形

2)对各变量进行初始化

3.task语句

在Verilog HDL模块中,task语句用来定义任务。任务类似高级语言中的子程序,用来单独完成某项具体任务,并可以被模块或其他任务调用。利用task语句可以把一个大的程序模块分解成为若干小的任务,使程序清晰易懂,而且便于调试。

希望能够对一些信号进行一些运算并输出多个结果(即有多个输出变量)时,宜采用task语句结构。task语句常常用来帮助实现结构化的模块设计,将批量的操作以任务的形式独立出来,使设计简单明了。

可以被调用的任务必须事先用task语句定义,定义格式如下:

任务定义与模块定义的格式相同,但任务用task-endtask语句来定义,而且没有端口名列表。例如,8位加法器任务的定义如下:

任务调用的格式如下:(www.daowen.com)

任务名(端口名列表);

例如,8位加法器任务调用语句如下:

adder8(tsum,tcout,t ina,t inb,t cin);

例6-13 编写完整的8位加法器任务调用的源程序

源程序如下:

使用task语句时,需要注意几点:

①任务的定义和调用必须在同一个module模块内,任务调用语句应在always块或task-endtask块中。

②定义任务时,没有端口名列表,但要进行端口和数据类型的声明,任务用顺序语句完成功能的描述。

③当任务被调用时,任务被激活。任务调用与模块调用一样,通过任务名实现,调用时需列出端口名列表,端口名的排序和类型必须与任务定义中的排序和类型一致。例如,8位加法器任务调用时的端口名列表中的端口tsum、tcout、tina、tinb、tcin与任务定义中的端口sum、cout、ina、inb、cin的排序和类型保持一致。

④一个任务可以调用别的任务或函数,可调用的任务和函数的个数不受限制。

任务的作用是方便编程,模块也具有任务的性质,可以被其他模块调用(调用方法与调用任务相同),而且模块可以独立存在(任务只能包含在模块中),因此在电路设计的编程中,可以用模块替代任务。

4.function语句

在Verilog HDL模块中,function语句用来定义函数。此处函数类似高级语言中的函数,用来单独完成某项具体操作,并可以作为表达式中的一个操作数,被模块或任务以及其他函数调用,函数调用时返回一个用于表达式的值。

调用函数的目的是通过返回一个用于某表达式的值,来响应输入信号,适用于对不同变量采取同一运算的操作。函数在模块内部定义,通常在本模块中调用,也能根据按模块层次分级的函数名从其他模块中调用;而任务只能在同一模块内定义与调用。

可以被调用的函数必须事先定义,函数定义格式如下:

在函数定义语句中,“[最高有效位:最低有效位]”是函数调用返回值位宽或类型声明。

例6-14 定义求最大值的函数。

函数调用的格式如下:

函数名(关联参数表);

函数调用一般出现在模块、任务或函数语句中,通过函数的调用来完成某些数据的运算或转换。例如,调用例6-14中的求最大值的函数:

Peak=max(data,peak);

其中,data和peak是与函数定义的两个参数a、b关联的关联参数,通过函数的调用,求出data和peak中的最大值,并用函数名max返回。

函数的定义不能包含任何时间控制语句——用延迟“#”、事件控制“@”或等待“wait”标识的语句。函数不能启动(即调用)任务。定义函数时至少要有一个输入变量,且不能有任何输出变量或输入/输出双向变量。在函数的定义中必须有一条赋值语句,给函数中的一个内部寄存器赋以函数的结果值,该内部寄存器与函数同名。

例6-15 利用函数对一个8位二进制数中为0的位进行计数。

函数和任务存在以下几处区别:

①任务可以有任意不同类型的输入/输出变量,函数不能将inout类型作为输出变量类型。

②任务只可以在过程语句中调用,不能在连续赋值语句中调用;函数可以作为表达式中的一个操作数,在过程赋值语句和连续赋值语句中调用。

③任务可以调用其他任务或函数;函数可以调用其他函数,但不能调用任务。

④任务不向表达式返回值,函数向调用它的表达式返回一个值。

免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。

我要反馈