每个Verilog HDL模块都包括4个主要部分:
//模块声明//端口声明
module模块名(输入/输出端口列表);
input输入端口列表;
output输出端口列表;
inout双向端口列表;
//数据类型声明,任务或函数声明
wire [n-1:0]数据名;
reg [n-1:0]数据名;
task任务名;
端口及数据类型声明;
其他语句;
endtask
function函数名;
端口声明;
局部变量定义;
其他语句;
endfunction
//逻辑功能描述
assign结果-表达式;
//数据流描述方式
always@(敏感信号列表)
//行为描述方式
begin
//过程赋值语句
/ /if-else语句、case语句//for循环语句
//调用任务、函数
end
//元件例化结构描述方式
门元件关键字例化门元件名(端口列表);
调用模块名例化模块名(端口列表);
endmodule
// 单行注释
/*多行
注释*/
Verilog HDL中的常量主要有3种类型:
其中,整数型常量是可以综合的,而实数型和字符串型常量是不可综合的。
Verilog中四种逻辑状态:
逻辑状态 | 含义 |
---|---|
0 | 低电平、逻辑0、“非” |
1 | 高电平、逻辑1、“真” |
z | 高阻态 |
x | 不确定或未知的逻辑状态 |
Verilog HDL中的数据都是在上述4类逻辑状态中取值,其中z和x都不区分大小写,也就是说,值10xz与值10XZ是等同的,表示同一个数据。
在Verilog HDL中,根据赋值和对值的保持方式的不同,可将数据类型分为两大类:
在Verilog HDL中,参数型数据是被命名的常量,在仿真开始前对其赋值,在整个仿真过程中其值保持不变。
参数通常出现在模块内部,用来定义状态机的状态、数据位宽及延时大小等。
定义:
parameter 参数名 = 表达式
例如:
parameter msb = 15
PS:在Verilog HDL中还提供了另一种定义常量的方法,就是编译向导语句宏替换′define。′define是一种全局性的定义,在遇到′undef之前定义的内容始终有效;而parameter是一种局部定义,在模块内部使用并且可以被灵活改动,这是parameter的一个重要特征。
系统设计中,经常需要用到(memory)。Verilog HDL通过对reg型变量建立数组来对存储器建模,数组中的每个单元通过一个数组索引进行寻址。memory型数据是通过扩展reg型数据的地址范围来生成的。————类似于二维数组
定义格式:
reg [n-1 : 0] 存储器名 [m-1 : 0];
其中,reg [n-1:0] 为存储器的字长,定义了存储器中每个存储单元的大小,即该存储单元是一个n位的寄存器;存储器名后的 [m-1:0] 或 [m:1] 为存储器的容量,定义了该存储器中有多少个这样的寄存器
不允许对存储器进行位选择和域选择。不过,可以首先将存储器的值赋给寄存器,然后对寄存器进行位选择和域选择。
位拼接运算符({})是将两个或两个以上操作数或操作数的某几位拼接在一起,形成一个新的表达式。
定义格式:
{op1, op2, op3, … opn}
例如:
{a, c[2 : 1]}
位拼接运算符还可以嵌套使用,如果多次拼接同一个操作数,重复的次数可以用常数指定,这时位拼接运算符又称为复制运算符。其使用格式如下:
{重复次数{op}}
例如:
{2{a}}等同于{a, a}
位拼接运算符中不允许拼接位宽不确定的常数,例如:
{a, 2}
缩位运算符是单目运算符,其运算规则类似于位运算符,但运算过程不同。首先将操作数的第一位与第二位进行运算,其次将运算结果与第三位进行运算,依次类推,直至最后一位例如:
reg [3:0] a;
y = &a;// 此时的y=a[0]&a[1]&a[2]&a[3]
符号 | 含义 |
---|---|
== | 等于 |
!= | 不等于 |
=== | 全等 |
!== | 不全等 |
“==”和“!=”又称为逻辑等式运算符,其结果由两个操作数的值决定。由于操作数中某些位可能是x或z,结果可能是不确定值x。而“===”和“!==”运算符则不同,它在操作数进行比较时对某些不确定值x和z也进行比较,两个操作数必须完全一致,其结果才是1,否则为0。
可综合是指所设计的代码和指令能转化为具体的电路网表结构,在基于FPGA/CPLD的设计中,综合就是将Verilog HDL描述的行为级或功能级电路模型转化为RTL级功能块或门级电路网表的过程。
@(posedge clk) dout = din; // 在时钟clk上升沿跳变时,将din的值赋给dout
wait (en) dout = din; // 当括号的条件满足时,就会执行后面的语句
Verilog HDL中的过程语句有两种:initial过程语句和always过程语句。一个模块中可以包含多个initial和always语句,每一个initial或always语句都是一个独立的执行过程,并且这些执行过程彼此之间都是并行执行,即这些语句的执行顺序与其在模块内的顺序无关。每个执行过程都是在仿真时间0时刻同时开始的。
initial
begin
语句1;
语句2;
...
语句n;
end
always @(敏感信号列表)
begin
// 过程复制
// if-else, case等条件语句
// for, while, repeat等循环语句
// task, function调用
end
fork
b = a;
c =b;
join
// 由于fork-join并行块内的语句是并发执行的
//最终b和c的值是不同的,b的值等于a的值,而c的值等于改变之前b的值。