Verilog HDL常用综合语法
前面已经记录了一些组成Verilog的基本组成,可以用这些基本组成来构成表达式。这一节,就来记录一下把这些表达式构成一个文件的各种行为描述语句。 ①这里用Verilog基本要素进行的行为描述主要是针对综合来的,也就是可以设计出实际电路来的(行为描述语句有两大子集,一个是面向综合,一个是面向仿真)。②行为描述语句一般指放在always语句中。内容提纲如下所示:
·触发事件控制
·条件语句(if与case语句)
·循环语句
·任务和函数
·编译预处理
一、触发事件控制
①电平敏感事件是指 指定信号的电平发生变化时发生指定的行为。
②边沿触发事件(信号跳变沿)是指 指定信号的边沿信号跳变时发生指定的行为,分为信号的上升沿(x→1或者z→1或者0→1)和下降沿x→0或者z→0或者1→0)。
③信号跳变沿触发电路对信号的某一跳变沿敏感名字一个时钟周期内,只有一个上升沿和一个下降沿,因此计算结果在一个周期内保持不变,而电平触发电路则可能会引起数据在一个时钟周期内变化一次或多次。
其他敏感列表的事项请查看这篇博文:http://www.cnblogs.com/IClearner/p/7253002.html。
二、条件语句
Verilog的条件语句包括if语句和case语句。
(1)if语句
①if语句中的条件判断表达式(括号中的那个)一般为逻辑表达式或者关系表达式或者就一个变量。如果表达式的值是0、X或者Z,则全部按照“假”处理;若为1,则按照“真”处理。
②在应用中,else if 分支的语句数目由实际情况决定;else分支可以省略,但在描述组合逻辑中,会综合得到锁存器。
(2)case语句
①case语句,case语句是一个多路条件分支的形式,常用于多路译码、状态机以及微处理器的指令译码等场合,有case分支 、casez分支、casex分支这三种形式。
②case语句首先对条件表达式求值,然后同时并行对各分支项求值并进行比较;当case语句跳转到某一分支后,控制指针将转移到endcase。
③case分支,case分支语句在执行时,条件表达式和分支之间进行的比较是一种按位进行的全等比较,也就是说,只有在分支项表达式和条件表达式的每一位都彼此相等的情况下,才会认为二者是相等的;此外x、z这两种逻辑状态也作为合法的状态参与比较(1 ==1,,0==0,x==x,z==z)。
④当分支的结果以常数出现时,如果没有指定位宽,则Verilog编译器默认其具有与PC字长相等的位宽。
⑤在casez分支中,如果分支取值的某些位为高阻z,则这些位的比较就不予以考虑,只关注其他位的比较结果。
⑥在casex分支中,则x、z都不予以考虑。
(3)if与case的区别
①if语句指定了一个有优先级的编码逻辑,而case语句生成的逻辑是并行的,不具有优先级。
②通常if结构得出的电路速度较慢,但是占用面积较小,由于速度慢,因此不适合构建特别长的if语句。
③case结构较if结构的速度快,但是占用面积大。
三、循环语句
循环语句有四种:for循环、repeat循环、while循环、forever循环。但是forever循环不能进行综合,而其他三种在一定情况下可以进行综合,因此这里记录可以综合的这三种。一般在电路设计中,不是经常用到循环语句,因为循环语句不好进行优化,占用的资源多,即使用到也是用到for循环。
(1)for循环
①for循环中,在循环次数确定的情况下,也就是循环结束条件是个常量下,才可以进行综合。主体注意要用begin...end来进行包括。
②在Verilog中,不支持++,--这些运算,需要用完整的i=i+1来完成。
(2)repeat循环
①repeat语句执行指定的循环次数,如果循环次数是x或者z,那么循环次数将会按照0次处理。主体注意要用begin...end来进行包括。
②当循环次数在程序编译过程中保持不变时,可以进行综合。
(3)while循环
①只有在指定的循环条件为真(0、x、z都是假)时才会重复执行循环体,注意循环体要用begin...end来包括。
②在执行语句中,必须有改变循环执行条件表达式的值的语句,否则循环可能进入死循环。
循环语句使用注意事项:
①循环语句中出现的变量都采用阻塞赋值(时序中,即沿触发中),这是因为在always块中,使用非阻塞赋值时,只有在always结束后才会把右端的值赋给左边的寄存器,如果采用非阻塞赋值,则会造成循环语句只执行一次。
②在沿触发中,语句采用阻塞赋值,这是由于循环语句本质是由组合逻辑实现的,虽然整体是基于时序逻辑,但是循环部分确是组合逻辑。
③基于循环语句的Verilog显得相对精简,但是面向硬件设计的关注点是时序、面积、功耗等,在使用循环语句进行电路设计时要慎重。
四、任务和函数
(1)任务语句(task)
任务(task)就是一段封装在“task-endtask”之间的程序。任务是通过调用来执行的,而且只有在调用时才执行,如果定义了任务,但是在整个过程中都没有调用它,则该任务不会被执行的。调用某个任务时可能需要它处理某些数据并返回操作结果,所以Verilog 中的task 存在输入端和输出端。
任务定义语法格式如下所示:
task<任务名>; // <= task task_id;
<端口及数据类型声明语句> // <= [declaration]
<语句1> // <= procedural_statement
<语句2> // <= procedural_statement
..... // <=
<语句n> // <= procedural_statement
endtask // <= endtask
上升的格式中,关键词 task 和 endtask 将它们之间的内容标志成一个任务定义,task 标志着一个任务定义结构的开始;task_id 是任务名;可选项 declaration 是端口声明语句和变量声明语句,任务接收输入值和返回输出值就是通过此处声明的端口进行的;procedural_statement 是一段用来完成这个任务操作的过程语句,如果过程语句多于一条,应将其放在语句块内;endtask 为任务定义结构体结束标志。一个任务的例子如下所示:
task find_max; //任务定义结构开头,命名为 find_max
input [:] x,y; //输入端口说明
output [:] tmp; //输出端口说明
if(x>y) //给出任务定义的描述语句
tmp = x;
else
tmp = y;
endtask
编写任务时,需要注意:
①调用某个任务时,可能需要它处理某些数据并返回操作结果,因此任务应当有接收数据的输入端和返回数据的输出端。
②任务的输入、输出和双向端口的数量不受限制,甚至可以没有输入、输出和双向端口。
③在任务定义的描述语句中,可以出现不可综合的语句,但是这样会引起任务不可综合。
④任务的定义结构定义不能在initial或者always语句中,在任务定义结构内不能出现 initial 和 always 过程块;但是任务的调用必须在这两个语句块中。
⑤任务定义中可以出现“disable”终止语句,但是这是不可综合的;在仿真中,如果出现的该终止语句,将中断正在执行的任务;任务被中断后,程序流程将返回到调用任务的地方继续向下执行。
⑥在第一行“task”语句中不能列出端口名称。
⑦可以使用出现不可综合操作符合语句(使用最为频繁的就是延迟控制语句,例如#10ns),但这样会造成该任务不可综合。
任务的使用(调用):
task_id (端口1,端口2,...,端口n);
task_id 是要调用的任务名,端口 1、端口 2,…是参数列表。参数列表给出传入任务的数据(进入任务的输入端)和接收返回结果的变量(从任务的输出端接收返回结果)。
任务调用的注意事项:
①任务调用中接收返回数据的变量必须是寄存器类型。
②任务调用语句和一条普通的行为描述语句的处理方法一致。
③可综合任务只能实现组合逻辑;也就是说调用可综合任务的时间为0。而在面向仿真的任务中可以带有时序控制,如多个时钟周期或时延,因此面向仿真的任务调用时间不为0。
④在任务中可以调用其他任务或者函数,也可以调用自身。
⑤当调用输入、输出和双向端口时,任务调用语句必须包含端口名列表,且信号端口顺序和类型必须和任务定义结构中的顺序和类型一致。任务的输出端口必须和寄存器类型的数据变量相对应。
(2)函数(function)
函数与任务类似,函数(function)是一段封装在“function-endfunction”之间的程序。函数的定义格式如下所示:
function<返回值的类型或范围>(函数名);
<端口说明语句>// input XXX;
<变量类型说明语句>// reg YYY;
begin
<语句>
........
函数名= ZZZ; //函数名就相当于输出变量;
end
endfunction
函数编写的注意事项如下:
①定义函数时至少要有一个输入参量;可以按照ANSI 和module 形式直接定义输入端口;例如:
function[:] alu (input[:] a, b,input[:] opcode );
此外,函数至少有一个输入端口,可以有多个输入端口;不允许输出声明,也不允许双向端口,因为函数名本身充当一个返回值。
②和任务一样,函数的定义只能在模块中完成,不能出现在过程块中。
③函数结果中,不能出现任何形式的时间控制语句(如#,wait),也不能使用disable。
④函数内部可以调用函数,但是不能调用任务。
⑤如果描述语句是可综合的,则必须所有分支均赋值,不允许存在不赋值情况,只能按照组合逻辑方式描述。
函数编写的一个例子如下所示,这是一个计算有符号数绝对值的函数:
function[width- : ] DWF_absval;
input [width- : ] A;
begin
DWF_absval = ((^(A ^ A) !== 'b0)) ? {width{1'bx}} :(A[width-] == 'b0) ? A : (-A);
end
endfunction
关于函数调用的注意事项:
①函数调用可以在过程块中完成,也可以在assign这样的连续赋值语句中出现。
②函数调用语句不能单独作为一条语句出现,只能作为赋值语句的右端操作数。
使用函数的一个完整实例:一个乘法电路——输入操作数a和b,输出他们的乘积;这里使用移位相加的算法来实现乘法。使用函数的实现的代码如下:
module MAC #(parameter N=)(
input clk,
input reset,
input [N-:] opa,
input [N-:] opb,
output reg[*N-:] out
); function[*N-:] mult;//函数定义,mult 函数完成乘法操作
input[N-:] opa; //函数只能定义输入端
input[N-:] opb; //输出端口为函数名本身
reg[*N-:] result;
integer i;
begin
result = opa[]? opb : ;
for(i= ; i <= N-1; i = i+)
begin
if(opa[i]==) result=result+(opb<<i);
end
mult=result;
end
endfunction wire[*N-:] sum;
assign sum = mult(opa,opb) + out;
always@(posedge clk or negedge reset)
if(!reset)
out<=;
else
out<=sum; endmodule
(3)关于任务和函数的对比和总结
①task语句和function语句都是可以综合的,但是只能实现组合逻辑,具备组合逻辑的优点和缺点。
②task和function都必须在模块内部定义,除参数个数不同外,还可以定义内部变量,包括寄存器、时间变量、整型等,但是不能定义线网变量。二者只能出现在行为描述中。
③区别:
比较点 |
任务 |
函数 |
输入、输出 |
可以有任意多个种类类型的参数 |
至少有一个输入,不能有输入和双向端口 |
调用 |
只能在过程语句中调用 |
可以在过程语句中调用,也可以在作为赋值操作的表达式用在assign赋值语句中 |
触发事件控制 |
任务可以包含延迟控制语句等,但是只能面向仿真,不可综合。 |
不能有时间控制语句 |
调用其他函数和任务 |
可以调用其他函数和任务 |
只能调用函数 |
返回值 |
任务没有返回值 |
函数向调用它的表达式返回一个值 |
其他 |
任务调用语句可以作为一条完整的语句出现 |
函数语句只能作为赋值操作的表达式,不能作为一条独立的语句出现 |
五、编译预处理语句
①编译预处理是Verilog编译系统的一个组成部分,指编译系统会对一些特殊命令进行预处理,然后将预处理结果和源程序一起在进行通常的编译处理。编译预处理是可以综合的。
②在Verilog语言编译时,特定的编译器指令在整个编译过程中有效(编译过程可跨越多个文件),直到遇到其他的不同的编译程序指令。
③常用的编译预处理语句有:`define、`undef ; `ifdef、`elsif 、`else、`endif ; `include ; `timescale。
(1)`define,`undef
格式:`define 宏的名称 宏的正文
①宏定义的名称可以是大写,也可以是小写,但是主要不要和变量名重复,此外宏定义的使用要注意带上`。
②和所有的编译器伪指令一样,宏定义在超过单个文件边界时仍然有效(对工程中的其他源文件),除非被后面的`define或者`undef伪指令覆盖,否则`define不受范围的限制。
③当用变量定义宏时,变量可以在宏正文中使用,并且在使用宏时可以用实际的变量表达式代替。
④通过用反斜杠\转移中间的换行符,宏定义可以跨越几行,新的行是宏正文的一部分。
⑤宏定义的行末不需要添加分号或者逗号表示结束
⑥宏正文不能分离的语言记号包括注释、数字、字符串、保留的关键字、运算符。
⑦编译器伪指令不允许作为宏的名字,此外红的正文可以是一个表达式,并不仅英语变量名的替换。
⑧`define和parameter的区别:
区别点 |
`define |
parameter |
作用域 |
①`define从编译器读到这条指令开始到编译结束都有效(除非遇到上面的提到的情况),可以应用于整个工程。 ②`define可以写在代码的任何位置。 |
①parameter作用于声明的当前文件,如果要让它作用与整个项目,可以将这些声明单独列在一个文件中,然后用`include进行包含。 ②parameter必须放在应用之前,也就是你要用到某个parameter参数了,你必须先parameter它。 |
传递功能 |
`define不能实现参数传递,但是不局限与定义变量,还可以定义 |
Parameter可以用作模块例化时的参数传递,实现参数化调用,但是仅局限于定义变量,而不能定义表达式。 |
(2)条件编译命令`if语句
①条件编译指令包括`ifdef 、`else 、`endif,其中`ifdef 、`endif必不可少,`else可选,且条件编译语句可以放在程序的任何地方调用。
②举例:
`ifdef AAAA
Parameter X1 = ;
`elsif BBBB
Parameter X2 = ;
`elsif CCCC
Parameter X3 = ;
`else
Parameter X4 = ;
`endif
意思是:如果用`define 定义的ABCD,那么就会执行第一个模块(Parameter X1 = 1);否则执行第二个模块( Parameter X2 = 1)。
(3)文件包含`include语句
①当某个模块需要调用某一个文件时,但是这个文件不在当前目录下,那么就需要使用`include语句进行包含,这样调用才不会出现错误。如 `include “../../xxxx.v”
②一个`include指令只能指定一个被包含的文件。如果要完成N个文件的包含,需要N个`include指令。
③可以将多个`include指令写在同一行,在`include命令行只能出现空格和注释。
④如果文件A同时包含了文件B和C,那么文件C可以直接利用B的内容,而不需要在对B文件进行包括,同理,B也可以直接利用C的内容。
(4)时间尺度`timescale语句
①`timescale用于定义延时的单位和延时的精度,如`timescale 1ns/100ps那么时间单位就是1ns,精度就是100ps。
②时间单位,表示了仿真时测量的单位,比如延时1,1ns;精度则表示仿真器只识别的范围,比如精度是100ps,那么如果你1.3ns,编译器是识别,但是如果写1.32,那么由于精度达不到那么细,所以0.02被四舍五入掉。
③`timescale影响着全部模块,知道遇到另外的`timescale。
Verilog HDL常用综合语法的更多相关文章
- 【转】Verilog HDL常用建模方式——《Verilog与数字ASIC设计基础》读书笔记(四)
Verilog HDL常用建模方式——<Verilog与数字ASIC设计基础>读书笔记(四) Verilog HDL的基本功能之一是描述可综合的硬件逻辑电路.所谓综合(Synthesis) ...
- Verilog HDL常用的行为仿真描述语句
一.循环语句 1.forever语句 forever语句必须写在initial模块中,主要用于产生周期性波形. 2.利用for.while循环语句完成遍历 for.while语句常用于完成遍历测试.当 ...
- Sublime Text 2 和 Verilog HDL
Sublime Text 2 和 Verilog HDL Date Fri 04 July 2014 Tags Sublime Text / Vivado Sublime Text 代码编辑器之于程 ...
- 关于初次使用Verilog HDL语言需要懂的基本语法
关于初次使用Verilog HDL语言需要懂的基本语法 1.常量 数字表达式全面的描述方式为:<位宽><进制><数字> 8’b10101100,表示位宽为8的二进制 ...
- Verilog HDL基础语法讲解之模块代码基本结构
Verilog HDL基础语法讲解之模块代码基本结构 本章主要讲解Verilog基础语法的内容,文章以一个最简单的例子"二选一多路器"来引入一个最简单的Verilog设计文件的 ...
- Verilog学习笔记基本语法篇(十一)········ 常用系统函数
1)系统任务:$monitor 格式: $monitor(p1,p2,p3...pn); $monitor; $monitoron; $monitoroff; 任务$monitor提供了监控输出列 ...
- 【Verilog HDL】赋值语句之阻塞赋值方式与非阻塞赋值方式
刚开始接触Verilog HDL语言时,这种硬件描述语言有一点与软件的程序设计语言直观上的最大区别大概就是这个赋值语句了(这里只是强调直观上的最大区别,事实上的最大区别并非如此). Verilog H ...
- Verilog笔记.1.基本语法
0.前 抽象模型分级: • 系统级(system):用高级语言结构实现设计模块的外部性能的模型.• 算法级(algorithm):用高级语言结构实现设计算法的模型.• RTL级(Register Tr ...
- Verilog学习笔记基本语法篇(十二)········ 编译预处理
h Verilog HDL语言和C语言一样也提供编译预处理的功能.在Verilog中为了和一般的语句相区别,这些预处理语句以符号"`"开头,注意,这个字符位于主键盘的左上角,其对应 ...
随机推荐
- CSS3学习系列之选择器(三)
E:enabled伪类选择器和E:disabled伪类选择器 E:enabled伪类选择器用来指定元素处于可用状态的样式. E:disabled伪类选择器用来指定当元素处于不可用状态时的样式. 当一个 ...
- HTML里的哪一部分Javascript 会在页面加载的时候被执行?
最近遇到一个问题:HTML里的哪一部分Javascript 会在页面加载的时候被执行()A : 文件头部 B : 文件尾 C : <head>标签部分 D : <body>标签 ...
- easyUI的简单了解
首先简单的介绍一下jQuery EasyUI,它是一组基于jQuery的UI插件集合体,而jQuery EasyUI的目标就是帮助web开发者更轻松的打造出功能丰富并且美观的UI界面.开发者不需要编写 ...
- Linux命令 用户管理命令
groupadd [功能说明] 新建用户组 [语法格式] Groupadd[-f][-r][-g<GID><-o>][组名] [选项参数] 参数 说明 -f 建立已存在的组,强 ...
- Vue按需加载提升用户体验
Vue官方文档异步组件: 在大型应用中,我们可能需要将应用拆分为多个小模块,按需从服务器下载.为了让事情更简单, Vue.js 允许将组件定义为一个工厂函数,动态地解析组件的定义.Vue.js 只在组 ...
- CSS都有哪些选择器?
派生选择器(用HTML标签申明) id选择器(用DOM的ID申明) 类选择器(用一个样式类名申明) 属性选择器(用DOM的属性申明,属于CSS2,IE6不支持,不常用,不知道就算了) 除了前3种基本选 ...
- 解决kubuntu(KDE4.8.5桌面环境)找不到中文语言包
原始日期:2013-12-30 23:16 接触linux的想必都知道KDE平台,kde精美的界面是其一大特色,不过美中不足的是,很多新手在安装完KDE后,界面包括菜单选项等都是英文界面,对于英语水平 ...
- linux 权限字母含义
查看某一文件夹下所有文件夹的权限情况:ls -l分别是:所有者(user)-所有者(user)-其他人(other)r 表示文件可以被读(read)w 表示文件可以被写(write)x 表示文件可以被 ...
- linux发行版和内核的关系
转自:http://m.blog.csdn.net/article/details?id=50595230 Linux内核是计算机操作系统的核心.一个完整的 Linux发行版包括了内核与一些其他与文件 ...
- 【LeetCode】125. Valid Palindrome
题目: Given a string, determine if it is a palindrome, considering only alphanumeric characters and ig ...