第三章、Verilog高级语法及用法
- 格式:doc
- 大小:685.50 KB
- 文档页数:24
verilog中function⽤法_verilog中的function⽤法与例⼦函数的功能和任务的功能类似,但⼆者还存在很⼤的不同。
在 Verilog HDL 语法中也存在函数的定义和调⽤。
1.函数的定义函数通过关键词 function 和 endfunction 定义,不允许输出端⼝声明(包括输出和双向端⼝) ,但可以有多个输⼊端⼝。
函数定义的语法如下:function [range] function_id;input_declarationother_declarationsprocedural_statementendfunction其中,function 语句标志着函数定义结构的开始;[range]参数指定函数返回值的类型或位宽,是⼀个可选项,若没有指定,默认缺省值为 1 ⽐特的寄存器数据;function_id 为所定义函数的名称,对函数的调⽤也是通过函数名完成的,并在函数结构体内部代表⼀个内部变量,函数调⽤的返回值就是通过函数名变量传递给调⽤语句;input_declaration ⽤于对寒暑各个输⼊端⼝的位宽和类型进⾏说明,在函数定义中⾄少要有⼀个输⼊端⼝;endfunction为函数结构体结束标志。
下⾯给出⼀个函数定义实例。
定义函数实例。
function AND;//定义输⼊变量input A, B;//定义函数体beginAND = A && B;endendfunction函数定义在函数内部会隐式定义⼀个寄存器变量, 该寄存器变量和函数同名并且位宽也⼀致。
函数通过在函数定义中对该寄存器的显式赋值来返回函数计算结果。
此外,还有下列⼏点需要注意:(1)函数定义只能在模块中完成,不能出现在过程块中;(2)函数⾄少要有⼀个输⼊端⼝;不能包含输出端⼝和双向端⼝;(3) 在函数结构中, 不能使⽤任何形式的时间控制语句 (#、 wait 等) , 也不能使⽤ disable中⽌语句;(4)函数定义结构体中不能出现过程块语句(always 语句)(这样的话,函数就不能完成时序逻辑,只能做组合逻辑,是这样吗?) ;(5)函数内部可以调⽤函数,但不能调⽤任务。
verilog begin end用法
Verilog中的begin-end语句用于将多个语句组合在一起,形成一个块。
该块中的语句按照从上到下的顺序依次执行。
begin-end语句的语法如下:
```
begin
// 语句1
// 语句2
// ...
// 语句n
end
```
在begin-end语句中,可以使用其他的Verilog语句,比如if 语句、for循环语句、while循环语句等。
例如:
```
always @(posedge clk)
begin
if (reset)
begin
// 初始化操作
end
else
begin
// 处理逻辑
end
end
```
需要注意的是,在Verilog中,begin-end语句并不会创建一个新的作用域。
因此,在一个begin-end语句块中定义的变量,在该块外部仍然是可见的。
如果需要在begin-end块中创建一个新的作用域,可以使用fork-join语句,但是这种方式的效率不高,不建议使用。
总的来说,begin-end语句是Verilog中非常常用的语法结构,可以帮助我们组织代码,提高可读性和可维护性。
verilog assertion语法下载温馨提示:该文档是我店铺精心编制而成,希望大家下载以后,能够帮助大家解决实际的问题。
文档下载后可定制随意修改,请根据实际需要进行相应的调整和使用,谢谢!并且,本店铺为大家提供各种各样类型的实用资料,如教育随笔、日记赏析、句子摘抄、古诗大全、经典美文、话题作文、工作总结、词语解析、文案摘录、其他资料等等,如想了解不同资料格式和写法,敬请关注!Download tips: This document is carefully compiled by the editor. I hope that after you download them, they can help you solve practical problems. The document can be customized and modified after downloading, please adjust and use it according to actual needs, thank you!In addition, our shop provides you with various types of practical materials, such as educational essays, diary appreciation, sentence excerpts, ancient poems, classic articles, topic composition, work summary, word parsing, copy excerpts, other materials and so on, want to know different data formats and writing methods, please pay attention!Verilog Assertion语法是数字电路设计中的重要组成部分,它为工程师提供了一种强大的方式来验证设计的正确性。
verilog %用法摘要:一、Verilog简介1.Verilog是一种硬件描述语言2.用于描述数字电路和模拟混合信号电路3.被广泛应用于电子设计自动化领域二、Verilog的基本语法与结构1.模块定义2.信号声明3.行为描述4.结构描述三、Verilog的主要关键字1.模块关键字(module)2.信号关键字(wire、reg、integer、real)3.行为关键字(initial、always、assign、deassign)4.结构关键字(begin、end、architecture)四、Verilog的运算符1.算术运算符2.关系运算符3.逻辑运算符4.位运算符五、Verilog的常用函数1.基本数学函数2.逻辑函数3.位运算函数4.字符串处理函数六、Verilog的编码风格与实践1.合理使用注释2.保持代码简洁3.命名规范4.层次化设计正文:Verilog是一种硬件描述语言,被广泛应用于电子设计自动化领域,用于描述数字电路和模拟混合信号电路。
它具有简洁、清晰的语法特点,易于学习和使用。
在Verilog中,模块定义是基本单位,可以包含信号声明、行为描述和结构描述。
模块关键字为`module`,用于定义一个模块实例。
信号关键字包括`wire`(线网)、`reg`(寄存器)、`integer`(整数)和`real`(实数),用于声明信号。
行为关键字有`initial`(初始化)、`always`(always 块)和`assign`(赋值),用于描述模块的行为。
结构关键字`begin`和`end`用于组织代码结构,`architecture`用于描述模块的层次结构。
Verilog中的运算符包括算术运算符、关系运算符、逻辑运算符和位运算符。
运算符的使用可以简化代码,提高描述电路的效率。
此外,Verilog还提供了丰富的函数,包括基本数学函数、逻辑函数、位运算函数和字符串处理函数,方便用户进行各种计算和操作。
verilogdefine用法摘要:一、Verilog define 简介1.Verilog define 的基本概念2.Verilog define 的主要作用二、Verilog define 语法与规则1.Verilog define 的语法结构2.Verilog define 的关键字与参数3.Verilog define 的使用规范三、Verilog define 应用实例1.定义基本元件2.定义常用模块3.定义复杂数字电路四、Verilog define 的优势与局限1.Verilog define 的优势2.Verilog define 的局限性正文:Verilog 是一种广泛应用于电子设计自动化(EDA)的硬件描述语言(HDL),它具有强大的功能,可以描述数字电路、模拟电路和混合信号电路。
其中,Verilog define 是Verilog 提供的一种功能强大的宏定义工具,可以方便地定义常用元件、模块和数字电路,提高代码复用性和可读性。
一、Verilog define 简介Verilog define 是Verilog 中一种用于定义宏的功能,它允许用户通过简单的语法定义复杂数字电路,从而简化代码编写过程。
通过Verilog define,用户可以自定义元件、模块和数字电路,使得数字电路设计更加灵活和高效。
二、Verilog define 语法与规则Verilog define 的语法结构如下:````define <宏名> (<参数>)<宏体>`enddefine```其中,`<宏名>` 是用户自定义的宏名,`<参数>` 是可选的参数列表,用于定义宏的属性。
`<宏体>` 是宏的具体内容,可以是任意合法的Verilog 代码。
Verilog define 的关键字主要包括`define`、`enddefine`、`param` 和`generate`。
verillog语法
Verilog是一种硬件描述语言,用于描述数字电路和系统。
以下是Verilog 的基本语法:
1. 注释:Verilog中的注释以“//”开头,一直延续到该行的末尾。
另外,多行注释以“/”开始,以“/”结束。
2. 数字表达方式:在Verilog中,数字的表示方式可以是十进制、八进制或二进制。
例如,8'b表示一个8位的二进制数。
3. 数据类型:Verilog中有四种数据类型,分别是wire(线网型)、reg (寄存器型)、integer(整数型)和parameter(参数型)。
其中,wire 类型用于表示物理连线,reg类型表示数据存储单元。
4. 模块:Verilog中的模块是电路的基本单元,由输入、输出和内部信号组成。
模块的端口用于连接外部信号,内部信号用于描述电路的行为。
5. 语句:Verilog中的语句可以分为赋值语句、控制语句和过程语句。
赋值语句用于给变量赋值,控制语句用于控制流程,过程语句用于描述电路的行为。
6. 任务和函数:Verilog中的任务和函数用于实现特定的功能。
任务和函数的使用可以减少代码的重复,提高代码的可维护性。
7. 系统任务和系统函数:系统任务和系统函数是Verilog提供的用于实现特定系统级功能的任务和函数。
例如,$display系统任务用于在仿真时显示信息。
以上是Verilog的基本语法,当然还有更多的语法和概念需要学习和掌握。
建议查阅相关的Verilog教程或书籍,以深入了解Verilog的语法和用法。
veriloga赋值语法Verilog-A赋值语法Verilog-A是一种常用于模拟电路设计的硬件描述语言,它不仅可以描述电路的结构和行为,还可以进行信号赋值。
本文将介绍Verilog-A中的赋值语法,包括基本赋值、连续赋值和延时赋值。
一、基本赋值在Verilog-A中,基本赋值是最常用的赋值方式,它使用“=”符号将右侧的表达式的值赋给左侧的变量。
例如,我们有一个电路模型,其中包含一个输入电压信号Vin和一个输出电流信号Iout,我们可以使用基本赋值语法将输入电压信号赋给输出电流信号:Iout = Vin;这样,当输入电压信号发生变化时,输出电流信号也会相应地更新。
二、连续赋值连续赋值是一种特殊的赋值方式,它可以将一个或多个信号的值赋给另一个信号。
在Verilog-A中,连续赋值使用“:=”符号。
例如,我们有一个电路模型,其中包含两个输入电压信号Vin1和Vin2,我们可以使用连续赋值语法将这两个信号的和赋给一个输出电流信号Iout:Iout := Vin1 + Vin2;这样,当Vin1或Vin2信号发生变化时,Iout信号会根据新的Vin1和Vin2的值重新计算。
三、延时赋值延时赋值是一种在特定时间后才进行赋值的方式。
在Verilog-A中,延时赋值使用“<=”符号,并指定一个延时时间。
例如,我们有一个电路模型,其中包含一个输入电压信号Vin和一个输出电流信号Iout,我们可以使用延时赋值语法将输入电压信号的值延时1纳秒后赋给输出电流信号:Iout <= #1ns Vin;这样,当输入电压信号发生变化时,输出电流信号会在1纳秒后更新。
四、总结本文介绍了Verilog-A中的赋值语法,包括基本赋值、连续赋值和延时赋值。
基本赋值使用“=”符号,连续赋值使用“:=”符号,延时赋值使用“<=”符号并指定一个延时时间。
这些赋值语法可以帮助我们在Verilog-A中对信号进行赋值操作,实现电路的行为描述和仿真。
verilog 中timeunit timeprecision的用法-回复Verilog中的`timeunit`和`timeprecision`是两个在仿真环境中控制时间的重要参数,它们决定了仿真的时间单位和时间精度。
本文将详细介绍这两个关键的Verilog语法,并解释它们的具体用法和功能。
一、概述Verilog是一种硬件描述语言(HDL),用于描述数字电路和系统的行为和结构。
在使用Verilog进行仿真时,时间的表示和处理是非常重要的,因为它决定了信号传输和计时控制等方面的行为。
`timeunit`和`timeprecision`允许设计人员在仿真过程中定义和控制时间的单位和精度。
二、timeunit的用法和功能1. 定义时间单位:在Verilog中,时间单位由`timeunit`和`timeprecision`这两个关键字来定义。
`timeunit`用于指定仿真中的时间单位,默认情况下,时间单位是1纳秒(1ns)。
例如,在当前模块中,可以使用以下语法来定义时间单位为1毫秒(1ms):`timescale 1ms/1ns上述语句中,`timescale`是一个特殊的系统任务,用于设置时间单位和精度。
2. 影响模块中的时间常量:在模块中,用于表示时间的常量将根据`timeunit`的定义自动缩放。
例如,如果`timeunit`设置为1毫秒(1ms),那么在模块中定义的时间常量如`10`将等于10毫秒。
这种缩放功能可以避免在使用时间常量时手动进行单位转换。
3. 在延迟和事件描述中使用时间单位:在仿真过程中,设计人员常常需要对延迟和事件进行描述。
缺省情况下,时间延迟单位是时间单位(`timeunit`,默认为1纳秒),时间事件单位是时间刻度(默认为1纳秒)。
可以在描述延迟和事件时直接使用这些单位,例如:#10上述代码表示10个时间单位的延迟。
4. 比较和控制时间:在仿真中,可以使用比较操作符(如`<`、`<=`、`>`、`>=`)来比较不同时间点的大小。
Verilog语言是一种硬件描述语言(HDL),用于描述和设计数字电路。
它广泛应用于数字系统的建模、验证和综合,是数字电路设计领域中的重要工具之一。
在Verilog中,模块是最基本的组织单位,模块中包含了电路的功能和行为描述。
本文将介绍Verilog语言的基本语法和模块写法,以帮助读者更好地理解和应用Verilog语言。
一、Verilog基本语法1. 注释在Verilog中,使用双斜杠(//)进行单行注释,使用/* */进行多行注释。
注释可以提高代码的可读性,便于他人理解和维护。
2. 变量声明Verilog中的变量可以分为寄存器变量(reg)和线网(wire)两种类型。
寄存器变量用于存储状态信息,线网用于连接各个逻辑门的输入和输出。
3. 逻辑运算符和位运算符Verilog中包括逻辑运算符(与、或、非等)和位运算符(与、或、异或等),用于对信号进行逻辑和位级操作。
4. 控制语句Verilog支持if-else语句、case语句等控制语句,用于根据不同条件执行不同的操作。
5. 模拟时钟在Verilog中,时钟是电路中的重要部分,通常使用时钟信号来同步各个元件的动作。
时钟可以通过周期性方波信号来模拟,使用$period 函数可以定义时钟的周期。
6. 仿真指令Verilog提供了多种仿真指令,用于初始化信号、设置仿真时间、输出波形图等操作,有助于仿真和调试电路。
二、模块写法1. 模块定义在Verilog中,一个模块包含了一组功能相关的硬件描述,可以看作是一个小型电路的抽象。
模块通过module关键字进行定义,其中包括模块名、输入输出端口声明等信息。
```verilogmodule adder(input wire [3:0] a,input wire [3:0] b,output reg [4:0] c);// 模块内部逻辑描述endmodule```2. 端口声明模块的端口包括输入端口(input)和输出端口(output),可以通过wire和reg进行声明。
verilog for用法Verilog是一种硬件描述语言(HDL),用于设计和模拟数字电路。
对于硬件工程师和数字电路设计师来说,它是一种非常强大且常用的工具。
Verilog for循环在Verilog代码中被广泛使用,用于迭代执行某些语句块,以便在一定条件下重复执行特定操作。
它的基本语法如下:```verilogfor (initialization; condition; increment) begin// statementsend```在这个语法中,`initialization`是一个初始化表达式,在循环开始之前用于初始化计数器或变量。
`condition`是一个条件表达式,只有当条件为真时,循环体中的语句才会被执行。
每次循环执行完后,`increment`表达式被用于更新计数器或变量。
以下是一个用Verilog for循环语句实现计数功能的例子:```verilogmodule counterinput wire clk,input wire reset,output reg [7:0] countif (reset) begincount <= 0;endelse beginfor (count = 0; count < 8; count = count + 1) begin//执行某些操作,如显示计数器值endendendendmodule```在`if`语句中,我们检查复位信号的状态。
如果复位信号处于高电平状态,则将计数器重置为0。
否则,我们使用Verilog for循环在计数器的值范围内执行某些操作。
Verilog for循环语句非常有用,可以在硬件设计中实现循环执行的功能,例如重复检查输入状态、执行相同的操作直到满足特定条件或生成自动化测试模式等。
需要注意的是,虽然Verilog for循环语句在HDL设计中很常见,但在某些情况下,它可能会导致设计中的一些问题,如时序问题、资源消耗等。
Verilog三段式1. 引言Verilog是一种硬件描述语言(HDL),用于描述数字电路的行为和结构。
它可以用于设计、仿真和验证集成电路(IC)和系统级芯片(SoC)。
Verilog采用三段式编程模型,即分为结构描述、行为描述和功能描述三个部分。
本文将详细介绍Verilog三段式的概念、特点、使用方法以及相关实例。
2. Verilog三段式概述Verilog的三段式编程模型由结构描述、行为描述和功能描述组成。
这种分层结构使得设计人员可以更好地组织代码,提高代码的可读性和可维护性。
下面将对每个部分进行详细介绍。
2.1 结构描述结构描述是Verilog中最底层的一部分,用于定义数字电路中的各个元素以及它们之间的连接关系。
在结构描述中,我们可以定义模块(module)、输入输出端口(input/output)、信号线(wire)、寄存器(reg)等。
例如,下面是一个简单的结构描述示例:module AndGate(input a, b, output y);assign y = a & b;endmodule在上述示例中,我们定义了一个名为AndGate的模块,它有两个输入端口a和b,一个输出端口y。
通过assign语句,我们将输入端口a和b进行与运算,并将结果赋值给输出端口y。
2.2 行为描述行为描述用于描述数字电路中的各个元素的行为。
在行为描述中,我们可以使用各种逻辑运算、条件语句和循环语句来定义数字电路的功能。
例如,下面是一个简单的行为描述示例:module Counter(input clk, output reg[3:0] count);always @(posedge clk) beginif (count == 4'b1111)count <= 4'b0000;elsecount <= count + 1;endendmodule在上述示例中,我们定义了一个名为Counter的模块,它有一个时钟输入端口clk和一个四位输出寄存器count。
verilog参数Verilog是一种硬件描述语言,用于描述和设计数字电路。
在Verilog中,参数(Parameter)是一种声明的方式,允许用户定义和传递常量值。
参数在设计过程中非常有用,可以提高代码的灵活性和可重用性。
本文将介绍Verilog参数的语法和用法,以及如何使用参数进行模块化设计。
在Verilog中,参数的语法如下所示:parameter [size] [type] parameter_name = constant_value;其中,[size]是可选的,用于指定参数的位宽;[type]也是可选的,用于指定参数的数据类型;parameter_name是参数的名称;constant_value是参数的常量值。
下面是一个简单的例子,展示了如何使用参数定义一个模块的位宽:parameter WIDTH = 8; // 定义参数,位宽为8module my_module #(parameter WIDTH)(input [WIDTH-1:0] data_in,output [WIDTH-1:0] data_out);// 模块的功能代码endmodule在上面的代码中,我们使用参数WIDTH来定义了模块my_module的位宽。
参数可以在模块内部任何地方使用,包括端口的声明和模块内的代码中。
参数的值可以在模块实例化时进行传递,如下所示:my_module #(16) m1 (.data_in(in), .data_out(out)); // 使用参数值为16实例化模块在上面的代码中,参数WIDTH的值被传递为16,因此实例化的模块my_module的位宽为16。
使用参数可以使代码更具有可重用性和灵活性。
通过修改参数的值,可以轻松地改变模块的行为。
例如,可以使用参数来实现多位宽的模块,而无需重写代码。
除了定义简单的常量值,参数还可以用于定义更复杂的常量,例如使用系统函数或其他参数的值计算出来的常量。
verilogdefine用法(原创实用版)目录1.Verilog 定义语法概述2.Verilog 模块的编写方法3.Verilog 模块的实例化方法4.Verilog 模块的仿真与验证5.Verilog 的应用领域正文Verilog 是一种硬件描述语言,主要用于数字系统硬件的描述、模块的实现以及系统的仿真与验证。
Verilog 定义语法是 Verilog 语言中重要的一部分,它用于定义模块的行为和结构。
下面我们来详细了解一下Verilog 定义语法的用法。
1.Verilog 定义语法概述Verilog 定义语法主要包括两个方面:模块定义和模块实例化。
模块定义用于描述模块的结构和行为,而模块实例化用于创建模块的实例。
2.Verilog 模块的编写方法要编写一个 Verilog 模块,首先需要使用 `module` 关键字定义一个模块。
模块名可以自定义,但必须与模块声明中的模块名相同。
模块声明和模块体之间使用分号(;)分隔。
下面是一个简单的模块定义示例:```verilogmodule my_module (input wire clk, // 输入信号input wire reset, // 输入信号output reg out // 输出信号);// 模块体endmodule```3.Verilog 模块的实例化方法在 Verilog 中,模块实例化是通过 `instance` 关键字实现的。
`instance` 关键字后面跟模块名和括号,括号内是一个或多个 `port` 关键字,用于指定模块实例的输入输出端口。
下面是一个模块实例化示例:```verilogmodule top (input wire clk,input wire reset,output reg out);// 实例化模块 my_modulemy_module my_instance (.clk(clk),.reset(reset),.out(out));endmodule```4.Verilog 模块的仿真与验证在编写完 Verilog 模块后,需要对其进行仿真与验证,以确保模块的功能正确。
第三章、Verilog高级语法及用法 casex和casez语句 锁存器的生成和利用 Verilog HDL 内置元件的例化 用户自定义的module例化 例化中的参数传递 Generate语句 向量的部分选择
casex和casez语句 在上一章中,使用了case语句描述了一个4为输入的二进制数用相应的数字显示到7段数码管上的实例。在这个实例中,仔细考虑din输入情况。如果在din的四个位中出现了高阻态z或者是不定态x的情况,case语句如何执行呢? 从语法角度上讲,case语句在进行敏感表达式和分支值进行比较的时候,每个比较的位都具有4种情况,即:0、1、x、z 四个不同的值,所以如果有分支选项对应的某个位只要不同,该分支就不会执行。而实际上,从物理意义上讲,高阻态相当于从电路中“断开”,所以这样的位实际过程中是不对电路的执行有影响的,作为分支选项应该考虑这种情况;另外,x不定态是我们研究电路的时候不关心的,或者说这个位应该是0或1、或者是Z的其中任何一个,通常在研究过程中这个位对对运算的结果没有影响。例如:假设din是4位,只要din的最高位为1,低3位不管为什么都执行某一条语句的情况。所以,verilog又设计了casez和casex语句来解决这两类现象。 casez和casex的语法格式和case完全一样,只是将case关键字换成了casez或casex。
在casez语句中,如果敏感信号表达式和分支表达式某些位的值(考虑对应二进制的情况下)为高阻态(即z或Z),那么对这些位的比较就会忽略,不予考虑,而只关注其他位的比较结果。 例:
这里“?”是高阻态z的另一种表示形式,它只出现在case语句的分支选项中!有一种错casez(sel) 2'b00:out=2'b01; 2'b1?:out=2'b10; 2'b01:out=2'b11; endcase
casex(敏感信号表达式) 值1: 语句1;//case分支 值2: 语句2; …… 值n: 语句n; default:语句n+1; endcase casez(敏感信号表达式) 值1: 语句1;//case分支 值2: 语句2; …… 值n: 语句n; default:语句n+1; endcase 误的理解方式认为它是不关心态,要注意!即,它只表示z,不表示x。 若sel的电平值为2’b11或者2’b1z或者2’b10或者2’b1x时,系统会输出out=2’b10。注:此casez语句在Quartus II中仿真结果不一定对,请使用专业的Verilog HDL仿真工具如modelsim去验证该语句的正确性。 在casex语句中,如果敏感信号表达式和分支表达式某些位的值(考虑对应二进制的情况下)为高阻态或不定态(即z或x),则在进行敏感信号表达式和分支值比较时,这些位不参与比较(也就是忽略该位),而只关注其他位的比较结果。 例:
当sel端的值为2’b10或者2’b11或者2’b1z或者2’b1x均有out=2'b01;语句成立。 大多数情况下,一般使用casez语句,case语句用的也较少,强烈不推荐使用casex语句。不过需要说明的是,这三个case语句都是可综合的,都能生成RTL电路。引自《ANALYSIS OF CASE STATEMENTS》一文。 casez语句的另一种应用------并行case语句。通过实例来说明。 代码如下:
在这个代码中,如果sel端恰巧是3’b111的情况,那么,a、b和c输出值应该是多少呢?从代码上看,如果sel的高位为高电平的话,a就输出高电平,否则保持初始化值0;同理,当sel的中间位为1的话,b输出1,否则输出初始化值0;当sel的最低位为1的话,c输出1,否则输出0。在接下来的波形仿真验证之前,请准备好自己的答案。先看一下RTL电路:
module parallel_case (sel, a, b, c); input [2:0] sel; output a, b, c; reg a, b, c; always @(sel) begin {a, b, c} = 3'b0; casez (sel) 3'b1??: a = 1'b1; 3'b?1?: b = 1'b1; 3'b??1: c = 1'b1; endcase end endmodule
casex(sel) 2'b1x:out=2'b01; …… endcase IN[2..0]OUT[7..0]DECODER
b~0
ab
cWideOr0
Decoder0sel[2..0]
仿真结果, 从仿真图上我们看出,实际上的输出结果为a高电平,b和c均为低电平。 从语句本身上看,代码的作者想用sel中的每一个位分别控制a、b和c中的各个引脚的输出电平。而实际上只有第一条语句执行了,因为初始化时候a、b、c均为低,而执行后只有第一条语句运行了,很显然,sel为111的时候第一条分支语句满足了,于是第一条语句执行,然后case语句就退出了!它相当于c语言中的每条分支语句后面的break的作用!换句话说,这里的case语句是有优先级的,当第一条分支语句执行后,case语句跳出,后面的语句都不执行了。 如果说不想让case语句具有优先级,可以在case语句的后面加上综合属性,当Quartus II综合的时候会根据综合属性改变其综合后的结果。//synthesis parallel_case 是并行综合属性,它以注释的形式出现在case语句后面,它可以使case语句综合后不在具有优先级,用法见下面代码: 再次综合,看RTL电路图: abcsel[2..0]
这和刚才的RTL视图完全不同,可以看出sel的三个输入分别接到了abc三个输出端上。仿真图如下:
当sel为111时候,abc也都输出了高电平。为其他值时,对应的a、b、c端口也随之变化。 另一个综合属性------full case语句 在case语句(含casez和casex)中,通常使用default选项来对分支选项中没有列举到的敏感信号表达式的值做统一的处理,从功能上看,如果不需要处理的分支值一般来说是我们不需要的功能,可以不写,但对于综合器来说,如果分支选项不全的话,对FPGA/CPLD硬件的资源的使用甚至是性能的使用是有影响的。 以下下通过实例演示说明default选项的作用:
module parallel_case (sel, a, b, c); input [2:0] sel; output a, b, c; reg a, b, c; always @(sel) begin {a, b, c} = 3'b0; casez (sel) //synthesis parallel_case 3'b1??: a = 1'b1; 3'b?1?: b = 1'b1; 3'b??1: c = 1'b1; endcase end endmodule 本代码没有使用default分支项,综合后的RTL视图如下
SEL[1..0]DATA[3..0]OUT
MUXDENAPRECLRQSEL[1..0]
DATA[3..0]OUT
MUX
y
a[3..0]y$latchMux14' h7 --
sel[1..0]Mux01' h0 --
然后加上default语句, 然后再次查看生成的RTL视图, …… begin casez (sel) 2'b00: y = a[0]; 2'b01: y = a[1]; 2'b10: y = a[2]; default:y= 0; endcase ……
module full_case (sel, a, y); input [1:0] sel; input [3:0] a; output reg y; always @(*) begin casez (sel) 2'b00: y = a[0]; 2'b01: y = a[1]; 2'b10: y = a[2]; endcase end endmodule SEL[1..0]DATA[3..0]OUT
MUXy
a[3..0]
Mux01' h0 --sel[1..0]
从语法角度上看,这个case语句实现的是一个多路选择功能,这两个RTL图中也都体现出来了,唯独不同的是,在前一个RTL视图中,还多了一个y$latch!这是一个锁存器。也就是说,当case语句分支选项不全时,综合器会自动生成一个锁存器,一旦敏感表达式不和分支选项值都不同时,电路不会产生新的输出,而是保持上次电路的运行结果。举个例子,假设sel为2’b00,那么y输出的是a[0]的值;而当sel变为2’b11时,由于分支选项没有2’b11,这时候y不会动作,维持之前的a[0]的输出。这个维持就是靠生成的锁存器来决定的。对于带有default语句的,当sel变为2’b11时,执行的是default语句中的结果。 有时候,这种锁存器的功能我们不需要,但是它的产生占用了fpga资源。如果说不想使用default语句,也不想生成锁存器的话,可以采用综合属性full_case来避免锁存器的生成。 full_case用法见下例子,在case语句的后面,以注释形式标注//synthesis full_case即可。
综合后的RTL视图如下: SEL[1..0]DATA[3..0]OUT
MUXy
a[3..0]
sel[1..0]
Mux01' h0 --
module full_case (sel, a, y); input [1:0] sel; input [3:0] a; output reg y; always @(*) begin casez (sel) //synthesis full_case 2'b00: y = a[0]; 2'b01: y = a[1]; 2'b10: y = a[2]; endcase end endmodule