Verilog HDL语法基础

一个复杂电路的完整Verilog HDL模型是由若个Verilog HDL 模块构成的,每一个模块又可以由若干个子模块构成。利用Verilog HDL语言结构所提供的这种功能就可以构造一个模块间的清晰层次结构来描述极其复杂的大型设计。

  • 每个模块的内容都是嵌在module和endmodule两个语句之间,每个模块实现特定的功能,模块是可以进行层次嵌套的。
  • 每个模块首先要进行端口定义.并说明输入(input)和输出(output),然后对模块的功能进行逻辑描述。
  • Verilog HDL程序的书写格式自由,一行可以写几个语句,一个语句也可以分多行写。
  • 除了endmodule语句外,每个语句的最后必须有分号。
  • 一个模块是由两部分组成的,一部分描述接口;另一部分描述逻辑功能,即定义输入是如何影响输出的。

模块(block)的组成

Verilog HDL结构完全嵌在module和endmodule声明语句之间,每个Verilog程序包括4个主要部分:端口定义,I/O说明,信号类型声明和功能描述。

module<模块名>(<端口列表>);
	端口说明(input,output,inout)
	参数定义(可选)
	数据类型定义
	连续赋值语句(assign)
	过程块(initial 和 always)
		行为描述语句
		低层模块实例
		任务和函数
	延时说明块
endmodule

  • 模块声明

    模块声明包括模块名和端口列表。其格式如下:

    module 模块名(端口1,端口2,端口3,…);

    模块结束的标志为关键字: endmodule

  • 端口定义

    input(输入端口),output(输出端口)和inout(双向端口)。

    格式如下:

    input 端口名1,端口名2,………,端口名N; //输入端口
    output 端口名1,端口名2,………,端口名N; //输出端口
    inout 端口名1,端口名2,………,端口名N; //输入输出端口

    也可以写在端口声明语句里,其格式如下(为了代码的可读性,一般不这么写):

    module module_name(input port1,input port2,…output port1,output port2… );

  • 信号类型说明

    信号可以分为端口信号和内部信号;

    1. 所有信号都必须进行数据类型的定义,如寄存器类型(reg等),连线类型(wire等);
    2. 如果信号没有定义数据类型,则综合器将其默认为wire型;
    3. 端口的位宽最好定义在端口定义中,不要放在数据类型定义中;
    4. 不能将input和inout类型声明为reg型;
  • 模块的端口表示的是模块的输入和输出口名,也就是说,它与别的模块联系端口的标识。

    在模块被引用时,在引用的模块中,有些信号要输入到被引用的模块中,有的信号需要从被引用的模块中取出来口。在引用模块时其端口可以用两种方法连接:

    (1)在引用时,严格按照模块定义的端口顺序来连接,不用标明原模块定义时规定的端口名,例如:

    模块名(连接端口1信号名,连接端口2 信号名,连接端口3信号名,……);

    (2)在引用时用“.”符号,标明原模块是定义时规定的端口名,例如:

    模块名( . 端口1名(连接信号1名),. 端口2名(连接信号2名),...);

    优点:在于可以用端口名与被引用模块的端口相对应,而不必严格按端口顺序对应,提高了程序的可读性和可移植性。

常量

关键字

关键字(又称保留字), 小写的英文字符串。如: module、endmodule、input、output、wire、reg、and、assign、always等。

标识符

标识符(identifier)是程序代码中给对象(如模块、端口、变量等)取名所用的字符串。

标识符的组成:由字母、数字字符、下划线_和美元符号$组 成 ,区 分大小写 , 其 第 一 个 字 符必须是英文字母或下划线。

注意:

1.关键字不能作为标识符使用。

2.用有意义的有效的名字如Sum 、CPU_addr等。

3.用下划线区分词。

4.采用一些前缀或后缀,如 时钟采用Clk 前缀:Clk_50,Clk_CPU; 低电平采用_n 后缀:Enable_n;

5.统一定的缩写如全局复位信号Rst。

6.同一信号在不同层次保持一致性,如同一时钟信号必须在各模块保持一致。

7.参数(parameter)采用大写,如SIZE 。

用下列四种基本的值表示电路的逻辑状态:

0:逻辑0或“假”;

1:逻辑1或“真”;

x:未知状态,通常在信号未被赋值前;

z:高阻;

在输入或表达式中,“z”的值通常被解释成“x”,z和x是不分大小写的,如01xz 与01XZ相同;


Verilog HDL中,有3种类型的常量:整数型常量(整数)、实数型常量(实数)和参数型常量。

整数

整数的一般表达式为:

<+/-><size> ’ <base format><number>

其中 size : 大小,表示二进制位数(bit)。缺省为32位。(可有可无);

base format:数基,可为2(b)、8(o)、10(d)、16(h)进制。缺省为10进制;

number:是所选数基内任意有效数字,包括X、Z。

默认数基为10进制

当数值number大于指定的大小时,截去高位。2’b1101表示的是2’b01

一个数字可以被定义为负数,只需在位宽表达式前加一个负号,注意必须在数字定义表达式的最前面。

下划线符号_可以自由的在整数或实数中使用;就数值本身而言,它们没有任何意义。它们能够用来提高可读性;唯一的限制是下划线符号不能用来作为常数的首字符。例:a=8’b0001_0000;

-14             //十进制数-14
16’d255         //位宽为16的十进制数255
8’h9a             //位宽为8的十六进制数9a
’o21               //位宽为32的八进制数21
’hAF               //位宽为32的十六进制数AF 
-4’d10             //位宽为4的十进制数-10
(3+2)’b11001  //非法表示,位宽不能为表达式

实数

(1)十进制格式,由数字和小数点组成(必须有小数点),例如:

0.1, 3.1415, 2.0 √ 3. x

(2) 指数格式:由数字和字符e(E)组成,e(E)的前面必须要有数字而且后面必须为整数,例如:

13_5.1e2       //其值为13510.0
8.5E2          //850.0 (e与E相同)
4E-4           //0.0004   

parameter(参数型)

在Verilog HDL中为了提高程序的可读性和可维护性,用parameter来定义一个标识符代表一个常量,称为符号常量。

其说明格式如下:

parameter 参数名1 = 表达式,参数名2 = 表达式, …,参数名n = 表达式;

parameter是参数型数据的确认符。确认符后跟着一个用逗号分隔开的赋值语句表。常用参数来声明运行时的常数。可用字符串表示的任何地方,都可以用定义的参数来代替。参数是本地的,其定义只在本模块内有效。

在一个模块中改变另一个模块的参数时,需要使用defparam命令。

变量的数据类型

线状网型变量(net)wire(需要被持续的驱动,驱动它的可以是门和模块)

wire型信号定义格式如下:

wire [n-1:0] 变量名1,变量名2,…变量名n;
wire [n:1] 变量名1,变量名2,…变量名n;
wire  a;              //定义了一个1位的wire型数据
wire [7:0] b;       //定义了一个8位的wire型向量
wire [4:1] c, d;    //定义了二个4位的wire型向量

寄存器型变量 (reg)

reg  [msb:lsb] 变量名1, 变量名2,…变量名n;
例如:
reg  clock;           
reg [3:0]  regb; 
reg [4:1]  regc, regd;

可以理解为实际电路中的寄存器,具有记忆性,是数据储存单元的抽象,在输入信号消失后它可以保持原有的数值不变。常代表触发器

与线网型变量的根本区别在于:register型变量需要被明确地赋值,并且在被重新赋值前一直保持原值。

只能在initial或always赋值,默认值是x。

注意在always和initial块内被赋值的每一个信号都必须定义成reg型。

Verilog程序模块中,被声明为input或者inout型的端口,只能被定义为线网型变量,被声明为output型的端口可以被定义为线网型或者寄存器型变量,输入输出信号类型缺省时自动定义为wire型。

wire型信号可以用作任何方程式的输入,也可以用作“assign”语句或实例元件的输出,不可以在initial和always模块中被赋值。

字符串的表示:

是由一对双引号括起来的字符序列。必须在一行内写完。如”hello world!”是一个合法字符串。

每个字符串(包括空格)被看作是8位的ASCII值序列。存储字符串“hello world!”,就需要定义一个8*12位的变量:

reg[8*12:1] stringvar;
initial 
    begin
		stringvar = “ hello world”;
    end

端口数据类型

一个端口看成是由相互连接的两个部分组成,一部分位于模块的内部,另一部分位于模块的外部。当在一个模块中调用(引用)另一个模块时,端口之间的连接必须遵守一些规则。

  • 输入端口:从模块内部来讲,输入端口必须为线网数据类型,从模块外部来看,输入端口可以连接到线网或者reg数据类型的变量。

    输出端口:从模块内部来讲,输出端口可以是线网或者reg数据类型,从模块外部来看,输出必须连接到线网类型的变量,而不能连接到reg类型的变量。

    输入/输出端口

    从模块内部来讲,输入/输出端口必须为线网数据类型;从模块外部来看,输入/输出端口也必须连接到线网类型的变量。

    位宽匹配

    在对模块进行调用的时候,verilog允许端口的内、外两个部分具有不同的位宽。一般情况下,verilog仿真器会对此警告。

  • 未连接端口

    Verilog允许模块实例的端口保持未连接的状态。例如,如果模块的某些输出端口只用于调试,那么这些端

    口可以不与外部信号连接。端口与外部信号的连接在对模块调用的时候,可以使用两种方法将模块定义的端口与外部环境中的信号连接起来:按顺序连接以及按名字连接。但两种方法不能混合在一起使用。

  • 顺序端口连接:需要连接到模块实例的信号必须与模块声明时目标端口在端口列表中的位置保持一致。

运算符与表达式

1.算数运算符

在进行算术运算时,如果操作数的某一位为x或z,则整个表达式运算结果为不确定。 例1 + z = unknown。

两个整数进行除法运算时,结果为整数,小数部分被截去。如,6/4=1。

在进行加法运算时,如果结果和操作数的位宽相同,则进位被截去。

2.位运算符(除了~,其余都是双目运算符)

缩位运算符(单目运算符)

缩位运算符(Reduction Operators):又称缩减运算符,仅对一个操作数进行运算,按照从右到左的顺序依次对所有位进行运算,并产生一位的逻辑值

4.关系运算符

在进行关系运算时,如果声明的关系是假,则返回值是0;如果声明的关系是真,则返回值是1;如果操作数的某一位为x或z,则结果为不确定值。

5.等式运算符

逻辑相等:==

逻辑不等:!=

全等:===

z, x等位严格相等

非全等:!==

相等运算符(==)和全等运算符(===)的区别:

对于相等运算符,当参与比较的两个操作数逐位相等,其结果才为1,如果某些位是不定态或高阻值,其相等比较得到的结果就会是不定值。

对于全等比较(===)是对这些不定态或高阻值的位也进行比较,两个操作数必须完全一致,其结果才为1,否则结果是0。

6.逻辑运算符

逻辑运算符中,“&&”和“||”是双目运算符,它要求有两个操作数。

“!”是单目运算符,只要求一个操作数。

7.移位运算符

Verilog HDL的移位运算符只有左移和右移两个。其用法为:A>>n或 A<<n; 表示把操作数A右移或左移n位,同时用0填补移出的位。

8.位拼接运算符

在Verilog语言中有一个特殊的运算符:位拼接运算符{ }。

位拼接运算符{}可以把两个或多个信号的某些位拼接起来,表示一个整体信号进行运算操作。其使用方法如下:

{信号1的某几位,信号2的某几位,..,..,信号n的某几位}

对于一些信号的重复连接,可以使用简化的表示方式{n{A}}。这里A是被连接的对象,n是重复的次数。

9.条件运算符

三目运算符,对3个操作数进行运算,方式如下:

信号 = 条件?表达式1:表达式2

说明:当条件成立时,信号取表达式1的值,反之取表达式2的值。

例如:

assign out= (sel == 0) ? a : b;

posted @ 2021-08-20 23:18  快乐气氛组阿宇  阅读(1008)  评论(0编辑  收藏  举报