与其它编程语言一样,Verilog代码也是由一系列的词法标记组成的。组成 Verilog HDL代码的词法有以下11大类型:
标识符在 Verilog HDL中是作为对象识别的唯一名字使用,标识符可以是变量的名字实例化名字、模块名、函数名、任务名、参数名及其它对象的名字。在Verilog HDL中标识分为两种:常规标识符、扩展标识符。在Verilog HDL代码中常用的是常规标识符,合法的常规标识符的组成规则有以下四条:
data //合法
address //合法
mux_2to1
_done
_price7$9
8it //非法,不能以数字开头
love verilog //非法,包含非规则1所规定的字符之外的字符,空白符
$is //非法,不能以$开头
bus1,BUS1 //合法,bus1与BUS1是两个不同的标识符
扩展标识符是对常规标识符的扩展,主要体现在扩展标识符所包含的合法字符集比常规标识符更加广泛,它的字符集是任何可以打印的字符包括空白符。扩展标识符的组成规则有以下三条:
\fish+meat //合法,可以包含+
\-clk //合法,可以包含-
\(i-i) //合法,可以包含()
\if big //非法,中间不能有空白符,因空白符代表扩展标识符结束
扩展标识需要注意一点,虽然扩展标识符是由\开始,空白符结束,但是它们都不属于扩展标识符本身。举例如下:
\AD_DATA //扩展标识符
AD_DATA //常规标识符
//扩展标识符不包括\与空白标识符,所以以上两个标识符是同一标识符
从上面标识符的命名规则可看出,定义一个合法的标识符是非常的容易的。但是写Verilog HDL代码就像写小说一样,不仅功能要实现,而可读性也要好。一般好的小说,人物的名字都让人容易记住,如果金庸的小说中:岳不群,灭绝师太等。定义一个有意义的的标识可以大大提高 Verilog HDL代码朗可读性。
空白符是Verilog HDL代码用来分隔其它词法标记的字符,空白的正确使用会提高Verilog HDL代码的可读性与层次感。Verilog hdl语言是空自符不敏感语言,通俗的讲就是可以在Verilog HDL代码的任何位置插入空白符,Verilog HDL的空白符包括:空格(space工)、制表符(tab)、换行符或回车符(new line or retun)。但是空白符在字符串里是敏感的,在字符串里不应该有换行符或回车符。举例如下:
//没有插入空白的Verilog HDL代码
module love_verilog initial $display("I love Verilog HDL!");endmodule
//插入适当空白符的Verilog HDL代码显得更有层次感
module lover_verilog
intial
$display("I love Verilog HDL!");
endmodule
//插入过度空白的Verilog HDL代码,会让人感觉整个代码不是一个整体
//在字符串中非法使用回车符或换行符
module lover_verilog
initial
$display("I
love
Verilog
HDL!);
endmodule
从上面的举例代码可以看出,适当的空白符可以有效提高Verilog HDL代码的可读性。
Verilog hDL注释的方式很简单,与C语言的类似,有两种:单行注释与多行注释单行注释。单行注释以\开始,直到本行结束;多行注释以/* 开始,以*/结束。需要注意的是多行注释不能嵌套,举例如下:
// 这里可以进行单行注释
/*
多行注释
多行注释
多行注释
*/
//下面的注释,由于非法使用多行注释,造成注释三无效
//这也说明嵌套多行注释可能造成语法错误,应该避免使用
/*
注释一
/*
注释二
*/
注释三
*/
好的注释的也会让Verilog HDL代码提高可读性,一般在端口与变量定义、重要语句等之后或之前进行适当的注释。
Verilog HDL值集是对应1bit的取值范围,与C语言是不同的。C语言1bit的取值范围是1与0。由于Verilog HDL是硬件描述语言,需要与硬件电路的实现情况相匹配,因此Verilog HDL的值集也带着硬件电路的属性,Verilog HDL的值集由以下四种值组成:
其中0与1为逻辑互补。
Verilog HDL的数包括整型数与浮点型数,先介绍整型数。一个完整的 Verilog HDL整型数由以下四个部分组成:
占用的bit数 | ’ | 基数 | 值 |
---|
占用的的bit数是指表示该数的位宽: Verilog HDL常用的基数有二进制的b或B,十进制的d或D,十六进制的h或H,八进制的o或O;值就是该数对应基数的值。
举例如下:
4'b1010 //4bit的二进制数
5'B11011 //5bit的二进制数
4'd8 //4bit的十进制数
3'D3 //3bit的十进制数
4'ha //4bit的十六进制数
4'Hb //4bit的十六进制数
3'o5 //3bit的八进制数
6'O75 //6bit的八进制数
如果省略占用的bit数,编译器会给一个默认的位宽,本书默认位宽为32位。如果基数省略则默认为十进制数,举例如下:
'b1010 //32bit的二进制数,剩下高28位都为0
'hf1 //32bit的十六进制数,剩下24位都为0
12 //为十进制的12
未知值x与高阻状态z在整型数中的表示,二进制中一个x或是z表示1bit的x或是z;八进制中一个x或是z表示3bit的x或是z;十进制中一个x或是z表示4bit的x或是z,举例如下:
4'b11zx //
6'b1z //相当于6'b00001z
6'bx10 //相当于6'bxxxx10
6'o1x //相当于二进制的6'b001xxx
9'ox3 //相当于二进制的9'bxxxxxx001
12'h1x //相当于二进制的12'b000000001xxxx
12'bx1 //相当于二进制的12'bxxxxxxxxxxx1
负号(-)在整型数只出现在数的最前面,不能出现基数之前或之后。有符号标识s或是S只能出现在基数之前,举例如下:
-8'd6 //负数用补码相当于:11111010
4'shf //相当于-1的补码:1111
4'sh6 //相当于6的补码:0110
-4'sh6 //相当于-6的补码:1010
空格与下划线的恰当使用也可以提高Verilog HDL代码的可读。空格不能用在’与基数之间,举例如下:
8'd 12 //空格可以位宽与'之间,也可以在基数与值之间
8' d14 //非法,空格不可能用在'与基数之间
12'b1011_1100_1000 //下划线的使用
Verilog HDL支持的实数有两种表示方法:小数表示方法与指数表示方法。实数的表示需要注意一点就是小数点左右两边都必须有数字,举例如下:
1.2 //小数表示方法
0.5 //小数表示方法
1.2e2 //小数表示方法
1.2E3 //小数表示方法
.2 //非法,小数点左边没有数字
1. //非法,小数点右边没有数字
Verilog HDL的字符串变量其实就是寄存器变量,字符串中每个字符是由8bit的二进制来表示。字符串由”开始,由”结束,举例如下:
module string_test;
reg[19*8-1:0]a; //定义一个寄存器型变量存储字符串
initial
begin
a="I love Verilog HDL!"; //19个字符串
$display("a is:%H",a);
end
endmodule
代码仿真结果:
a is:00000000000000000000000000000048444c21
一些特殊字符表示方法如下:
\n //表示换行符
\t //表示制表符Tab
\\ //表示\
\" //表示引号
\ddd //表示三位八进制的数
Verilog HDL的文本宏的功能主要是用替换数字的,以提高 Verilog HDL代码的可读性以及代码修改的一致性,举例如下:
'define BUS_WIDTH 8 //定义一个文本宏
reg['BUS_WIDTH-1:0]] //使用文本宏
Verilog HDL的系统函数是提供给开发人员实现某些特定功能的以$开头的函数,方便了Verilog HDL代码的设计与验证。为了避免产生岐义,设计人员在进行标识符命名时应避免与系统函数名冲突,举例如下:
$display("I love Verilog HDL!"); //打印I love Verilog HDL!
$finish; //结束本次仿真
关键字或称为保留字是每种语言的一大显著特点,作为硬件描述语言,Verilog HDL的关键有明显的硬件特性,比如pmos、mmos、 supply、 supply0等,虽然Verilog HDL是大小敏感的语言同,但是建议不通过改变关键字字母的大小写作为普通标识符。所有关键字都用小写
例如:
module和endmodule来指出源程序模块的开始和结束;用assign来描述一个逻辑表达式等。
Verilog HDL的关键字有97个,在这里列举几个常用的关键字,具体的请网上查询!
关键字 | 含义 |
---|---|
module | 模块开始定义 |
input | 输入端口定义 |
output | 输出端口定义 |
inout | 双端口定义 |
parameter | 信号的参数定义 |
wire | wire信号定义 |
reg | reg信号定义 |
always | 产生Reg信号语句的关键字 |
assign | 产生wire信号语句的关键字 |
begin | 语句的起始标志 |
end | 语句的结束标志 |
posedge/negedge | 时序电路的标志 |
case | Case语句起始标记 |
default | Case语句的默认分支标志 |
endcase | Case语句结束标记 |
if | if/else语句标记 |
else | if/else语句标记 |
for | for语句标记 |
endmodule | 模块结束定义 |
下面以半加器模块以来介绍Verilog HDL代码的基本结构,半加器模块如【代码1-1】所示。
【代码1-1】
module half_adder(
input I_a,
input I_b,
output O_sum,
output O_cout
);
assign O_sum=I_a^I_b;
assign O_cout=I_a&I_b;
endmodule
上图是代码【代码1-1】与电路结构的对应关系。
可以看出,每一个Verilog HDL代码的功能描述语句都需要占用一定的FPGA资源。因此使用者在开始就应该有个概念,Verilog HDL是硬件描述语言,写的每一行代码在头脑都应该有与之相应的硬件电路的意识。