1.什么是verilog语言
Verilog HDL(Hardware Description Language)是一种用于电子系统设计和建模的硬件描述语言。它广泛应用于数字电路的设计和验证,特别是在FPGA(现场可编程门阵列)和ASIC(应用特定集成电路)的开发中。Verilog HDL允许设计师通过编写代码来描述电路的行为和结构,这些代码可以被合成工具转换成实际的硬件电路。
以下是Verilog HDL的一些关键特性和概念:
1. **模块(Module)**:Verilog中的模块是设计的基本构建块。每个模块可以包含逻辑电路的描述,并且可以被实例化多次以形成更复杂的系统。
2. **数据类型**:Verilog提供了多种数据类型,包括线网(wire)、寄存器(reg)、整数(integer)、实数(real)和时间(time)等。
3. **运算符**:Verilog支持多种运算符,包括算术运算符(+、-、*、/)、逻辑运算符(&&、||、!、&、|、~)、关系运算符(==、!=、>、<、>=、<=)和位运算符(&、|、^、~、>>、<<)。
4. **并发语句**:Verilog中的并发语句(如`assign`和`always`块)用于描述电路的并发行为。`assign`语句用于描述连续赋值,而`always`块用于描述过程赋值,可以是组合逻辑或时序逻辑。
5. **时序控制**:Verilog通过`always`块和时钟信号来描述时序逻辑。`always @(posedge clk)`表示在时钟信号的正边沿触发。
6. **条件语句**:`if`、`case`和`if-else`语句用于描述设计中的条件逻辑。
7. **循环语句**:`for`、`while`和`repeat`语句用于描述设计中的循环行为。
8. **任务(Task)和函数(Function)**:任务是用于描述在模块内部执行的过程,而函数用于执行计算并返回一个值。
9. **参数化模块**:Verilog允许使用参数化模块,这使得模块可以在不同的实例中具有不同的行为。
10. **测试台(Testbench)**:Verilog提供了编写测试台的能力,用于模拟和验证设计在不同条件下的行为。
Verilog HDL的一个简单示例代码如下:
在这个例子中,定义了一个名为`and_gate`的模块,它实现了一个逻辑与门的功能。然后,定义了一个名为`testbench`的测试台模块来验证`and_gate`模块的功能。在测试台中,使用`initial`块来初始化输入信号并模拟不同的输入组合,同时使用`$monitor`系统任务来监控信号的变化。
二、Verilog HDL 基础知识
1、Verilog HDL 语言要素
1.1、命名规则
标识符被用来命名信号、模块、参数等,它可以是任意一组字母、数字、$符号和_(下划线)符号的组合。(标识符中字母区分大小写,且第一个字必须是字母或下划线)
1.2关键字(均小写)
Verilog HDL 内部已经使用的词成为关键字或保留字,是事先定义好的确认符,用来组织语言结构。总结关键字大概有以下这么多:
always, and, assign, begin, buf, bufif0, bufif1, case, casex, casez, cmos, deassign, default, defparam, disable, edge, else, end, endcase, endfunction, endmodule, endprimitive, endspecify, endtable, endtask, event, for, force, forever, fork, function, highz0, highz1, if, ifnone, initial, inout, input, integer, join, large, macromodule, medium, module, nand, negedge, nmos, nor, not, notif0, notif1, or, output, parameter, pmos, posedge, primitive, pull0, pull1, pulldown, pullup, rcmos, real, realtime, reg, release, repeat, rnmos, rpmos, rtran, rtranif0, rtranif1, scalared, small, specify, specparam, strength, strong0, strong1, supply0, supply1, table, task, time, tran, tranif0, tranif1, tri, tri0, tri1, triand, trior, trireg, vectored, wait, wand, weak0, weak1, while, wire, wor, xnor, xor
Verilog常用的一些关键字
1. always:用于创建一个时序块,其中的代码会按照时序规则执行,产生reg信号语句的关键字。
2. assign:用于创建一个组合块,其中的代码会按照组合逻辑规则执行,产生wire信号语句的关键字。
3. begin/end:用于创建一个代码块,其中的代码会按照顺序执行,语句的起始和结束标志。
4. module:模块开始的定义,用于创建一个模块,其中包含了数字电路的结构和行为。
5. input/output:用于定义模块的输入和输出端口定义。
6. wire/reg:用于定义信号的类型(wire信号定义和reg信号定义),wire表示连续信号,reg表示时序信号。
7. always_comb/always_ff:用于创建一个组合逻辑块或时序逻辑块。
8. inout 双向端口定义。
9. parameter 信号的参数定义。
10. posedge/negedge 时序电路的标志。
11. case:case语句起始标记。
12. default:ase语句的默认分支标志。
13. endcase:case语句结束标记。
14. if:if/else语句标记。
15. else:if/else语句标记。
16. for:for语句标记。
17. endmodule:模块结束定义。
可综合和不可综合的关键字
可综合(Synthesizable)是指可以被综合器(Synthesizer)转换为硬件电路的代码。在FPGA设计中,可综合的代码可以被综合器转换为硬件电路,从而实现所需的功能。可综合代码应该具有以下特点:
1. 代码应该是结构化的,不能使用goto语句或其他不可综合的语言结构。
2. 代码应该是可重用的,可以在不同的设计中使用。
3. 代码应该是可读的,易于维护和修改。
可综合关键字是指在FPGA设计中可以被综合器识别和转换为硬件电路的关键字。常见的可综合关键字包括:
1. always:用于定义时序逻辑的关键字。
2. case:用于实现多路选择器的关键字。
3. assign:用于赋值操作的关键字。
4. wire:用于定义信号的关键字。
不可综合关键字是指在FPGA设计中不能被综合器识别和转换为硬件电路的关键字。常见的不可综合关键字包括:
1. $display:用于调试输出的关键字。
2. $monitor:用于监视信号的关键字。
3. $finish:用于结束仿真的关键字。
在FPGA设计中,应该尽量避免使用不可综合关键字,以免影响设计的可综合性和性能。
Verilog所有关键字的作用和用法
1. always
always是Verilog中的一个关键字,用于创建一个时序块。在Verilog中,时序块是一种用于描述数字电路中的时序逻辑的结构,always关键字可以用于创建一个时序块,其中的代码会按照时序逻辑规则执行。always块可以根据时钟触发或者条件触发进行执行。
示例代码:
2. and
and是Verilog中的一个关键字,用于创建一个与门。在Verilog中,与门是一种用于实现布尔逻辑的结构,and关键字可以用于创建一个与门,其中的输入信号经过与运算后,输出信号为1或0。
示例代码:
```
wire a, b, c;
and gate (c, a, b);
```
3. assign
assign是Verilog中的一个关键字,用于创建一个组合块。在Verilog中,组合块是一种用于描述数字电路中的组合逻辑的结构,assign关键字可以用于创建一个组合块,其中的代码会按照组合逻辑规则执行。
示例代码:
```
assign out = (a & b) | (c & d);
```
4. begin
begin是Verilog中的一个关键字,用于创建一个代码块。在Verilog中,代码块是一种用于组织代码的结构,begin关键字可以用于创建一个代码块,其中的代码会按照顺序执行。
示例代码:
5. buf
buf是Verilog中的一个关键字,用于创建一个缓冲器。在Verilog中,缓冲器是一种用于放大电路信号的结构,buf关键字可以用于创建一个缓冲器,其中的输入信号经过放大后,输出信号与输入信号相同。
示例代码:
```
wire a, b;
buf gate (b, a);
```
6. bufif0
bufif0是Verilog中的一个关键字,用于创建一个带有使能信号的缓冲器。在Verilog中,带有使能信号的缓冲器是一种用于放大电路信号的结构,bufif0关键字可以用于创建一个带有使能信号的缓冲器,其中的输入信号经过放大后,输出信号与输入信号相同,当使能信号为0时,输出信号为高阻态。
示例代码:
```
wire a, b, enable;
bufif0 gate (b, a, enable);
```
7. bufif1
bufif1是Verilog中的一个关键字,用于创建一个带有反向使能信号的缓冲器。在Verilog中,带有反向使能信号的缓冲器是一种用于放大电路信号的结构,bufif1关键字可以用于创建一个带有反向使能信号的缓冲器,其中的输入信号经过放大后,输出信号与输入信号相同,当使能信号为1时,输出信号为高阻态。
示例代码:
```
wire a, b, enable;
bufif1 gate (b, a, enable);
```
8. case
case关键字用于描述多路选择器,它可以根据输入信号的值选择相应的输出信号。以下是一个简单的case语句示例:
在这个示例中,我们使用case语句根据sel的值选择相应的输出信号。当sel为2'b00时,out等于a;当sel为2'b01时,out等于b;以此类推。
9. casex
casex关键字也用于描述多路选择器,但它可以处理不确定的输入信号值。以下是一个简单的casex语句示例:
在这个示例中,我们使用casex语句根据sel的值选择相应的输出信号。当sel的最高位为0,次高位为0时,out等于a;当sel的最高位为0,次高位为1时,out等于b;以此类推。如果sel的后两位是不确定的,也可以使用xx表示。
10. casez
casez关键字也用于描述多路选择器,但它可以处理不确定的输入信号值,并且可以将输入信号的未知值(Z)视为0。以下是一个简单的casez语句示例:
在这个示例中,我们使用casez语句根据sel的值选择相应的输出信号。当sel的最高位为0,次高位为0时,out等于a;当sel的最高位为0,次高位为1时,out等于b;以此类推。如果sel的后两位是不确定的或者是Z,也可以使用zz表示。
11. cmos
cmos关键字用于描述CMOS逻辑门,包括CMOS反相器、CMOS与门、CMOS或门等。以下是一个简单的CMOS逻辑门示例:
在这个示例中,我们定义了一个CMOS反相器模块,它有一个输入端口a和一个输出端口y。在模块中,我们使用cmos语句描述了CMOS反相器的逻辑。
12. deassign
deassign关键字用于取消信号的赋值。以下是一个简单的deassign语句示例:
```
deassign a;
```
在这个示例中,我们使用deassign语句取消了信号a的赋值。这意味着信号a现在没有值,可以重新赋值。
13. default
default关键字用于描述case语句中的默认情况。当输入信号的值与case语句中的所有情况都不匹配时,将执行default语句。以下是一个简单的default语句示例:
在这个示例中,我们使用default语句定义了输入信号sel的默认情况。当sel不是2'b00、2'b01或2'b10时,out等于d。
14. defparam
defparam关键字用于为模块的参数赋值。以下是一个简单的defparam语句示例:
```
defparam adder.width = 8;
```
在这个示例中,我们使用defparam语句为模块adder的宽度参数赋值为8。这意味着adder将使用8位宽度进行运算。
15. disable
disable关键字用于禁用任务或函数。在Verilog中,任务和函数是用来执行特定功能的代码块。如果需要在执行任务或函数的过程中停止它们的执行,就可以使用disable语句。以下是一个简单的disable语句示例:
在这个示例中,我们定义了一个名为my_task的任务,并在initial块中执行它。然后,我们使用disable语句停止my_task的执行。
16. edge
edge关键字用于描述时钟信号的边沿类型。在数字电路中,时钟信号通常用于同步电路中,用于控制电路的行为。时钟信号的边沿类型可以是上升沿、下降沿或两者都有。以下是一个简单的edge语句示例:
```
always @(posedge clk)
// 时钟上升沿触发的代码块
```
在这个示例中,我们使用edge关键字描述时钟信号的上升沿类型,并在always块中编写了时钟上升沿触发的代码块。
17. else
else关键字用于描述if语句中的默认情况。当if语句中的条件不成立时,将执行else语句。以下是一个简单的else语句示例:
```
if (a == b)
// 条件成立的代码块
else
// 默认情况的代码块
```
在这个示例中,我们使用else语句定义了if语句中的默认情况。当a等于b时,将执行条件成立的代码块;否则,将执行默认情况的代码块。
18. end
end关键字用于结束模块、任务或函数的定义。在Verilog中,每个模块、任务或函数都必须以end关键字结束。以下是一个简单的end语句示例:
```
module my_module(input a, output b);
// 模块代码块
endmodule
```
在这个示例中,我们使用endmodule语句结束了模块my_module的定义。
19. endcase
endcase关键字用于结束case语句的定义。在Verilog中,case语句用于根据输入信号的值选择相应的输出信号。以下是一个简单的endcase语句示例:
在这个示例中,我们使用endcase语句结束了case语句的定义。
20. endfunction
endfunction关键字用于结束函数的定义。在Verilog中,函数是用来执行特定功能并返回结果的代码块。以下是一个简单的endfunction语句示例:
```
function [7:0] my_function;
// 函数代码块
endfunction
```
在这个示例中,我们使用endfunction语句结束了函数my_function的定义。
21. endmodule
endmodule关键字用于结束模块的定义。在Verilog中,模块是用来描述数字电路的基本组件。以下是一个简单的endmodule语句示例:
在这个示例中,我们使用endmodule语句结束了模块my_module的定义。
22. endprimitive
endprimitive关键字用于结束primitive的定义。在Verilog中,primitive是一种基本的数字电路元素,用于描述数字电路的物理实现。以下是一个简单的endprimitive语句示例:
```
primitive and_gate (input a, input b, output c);
// primitive代码块
endprimitive
```
在这个示例中,我们使用endprimitive语句结束了primitive and_gate的定义。
23. endspecify
endspecify关键字用于结束specify块的定义。在Verilog中,specify块用于描述数字电路的时序和延迟。以下是一个简单的endspecify语句示例:
```
specify
// specify代码块
endspecify
```
在这个示例中,我们使用endspecify语句结束了specify块的定义。
24. endtable
endtable关键字用于结束table块的定义。在Verilog中,table块用于描述数字电路的真值表。以下是一个简单的endtable语句示例:
```
table my_table (input a, input b, output c);
// table代码块
endtable
```
在这个示例中,我们使用endtable语句结束了table my_table的定义。
25. endtask
endtask关键字用于结束task的定义。在Verilog中,task是一种用于执行特定功能的代码块。以下是一个简单的endtask语句示例:
```
task my_task;
// 任务代码块
endtask
```
在这个示例中,我们使用endtask语句结束了task my_task的定义。
26. event
event关键字用于描述事件,即数字电路中的信号变化。在Verilog中,event通常与wait语句一起使用,用于等待某个事件的发生。以下是一个简单的event语句示例:
```
always @(event clk)
// 事件触发的代码块
```
在这个示例中,我们使用event关键字描述了时钟信号的边沿类型,并在always块中编写了事件触发的代码块。
27. for
for关键字用于描述循环语句。在Verilog中,for语句通常用于重复执行一段代码块。以下是一个简单的for语句示例:
```
for (i = 0; i < 10; i = i + 1)
// 循环执行的代码块
```
在这个示例中,我们使用for语句描述了一个循环,i从0开始,每次增加1,直到i小于10为止,重复执行循环执行的代码块。
28. force
force关键字用于强制改变数字电路中的信号值。在Verilog中,force通常与initial语句一起使用,用于初始化数字电路的状态。以下是一个简单的force语句示例:
```
initial begin
force a = 1;
#10 release a;
end
```
在这个示例中,我们使用force语句将信号a的值强制设为1,然后使用release语句在10个时间单位后释放a的值。
29. forever
forever关键字用于创建一个无限循环。在Verilog中,forever通常与always语句一起使用,用于重复执行一段代码块。以下是一个简单的forever语句示例:
```
always @(posedge clk)
forever begin
// 重复执行的代码块
end
```
在这个示例中,我们使用forever关键字描述了一个无限循环,在时钟上升沿触发时重复执行代码块。
30. fork
fork关键字用于创建一个并发执行的代码块。在Verilog中,fork通常与join语句一起使用,用于并发执行多个代码块。以下是一个简单的fork语句示例:
在这个示例中,我们使用fork关键字创建了两个并发执行的代码块,并使用join语句等待两个代码块的执行完成。
31. function
function关键字用于创建一个函数。在Verilog中,function通常用于执行特定的计算或操作。以下是一个简单的function语句示例:
```
function int add(int a, int b);
add = a + b;
endfunction
```
在这个示例中,我们使用function关键字创建了一个add函数,用于计算两个整数的和。
32. highz0
highz0关键字用于描述数字电路中的高阻态。在Verilog中,highz0通常用于描述三态门的输出。以下是一个简单的highz0语句示例:
```
assign out = (enable) ? data : highz0;
```
在这个示例中,我们使用highz0关键字描述了三态门的输出,在enable信号为1时输出data信号,在enable信号为0时输出高阻态。
33. highz1
highz1关键字用于描述数字电路中的高阻态。在Verilog中,highz1通常用于描述三态门的输出。以下是一个简单的highz1语句示例:
```
assign out = (enable) ? data : highz1;
```
在这个示例中,我们使用highz1关键字描述了三态门的输出,在enable信号为1时输出data信号,在enable信号为0时输出高阻态。
34. if
if关键字用于描述条件语句。在Verilog中,if语句通常用于根据某个条件执行特定的代码块。以下是一个简单的if语句示例:
在这个示例中,我们使用if语句判断a是否大于b,如果成立,执行条件成立时的代码块,否则执行条件不成立时的代码块。
35. ifnone
ifnone关键字用于描述默认值。在Verilog中,ifnone通常用于描述信号的默认值。以下是一个简单的ifnone语句示例:
```
assign out = ifnone(in, 0);
```
在这个示例中,我们使用ifnone关键字描述了信号in的默认值为0,如果in信号没有被赋值,out信号将被赋值为0。
36. initial
initial关键字用于描述初始化代码块。在Verilog中,initial语句通常用于初始化数字电路的状态。以下是一个简单的initial语句示例:
```
initial begin
// 初始化代码块
end
```
在这个示例中,我们使用initial关键字描述了一个初始化代码块,用于初始化数字电路的状态。
37. inout
inout关键字用于描述双向信号。在Verilog中,inout通常用于描述三态门的输入和输出。以下是一个简单的inout语句示例:
```
module tri_gate(inout out, input enable, input data);
assign out = (enable) ? data : 1'bz;
endmodule
```
在这个示例中,我们使用inout关键字描述了三态门的输入和输出信号out,当enable信号为1时,输出data信号,否则输出高阻态。
38. input
input关键字用于描述输入信号。在Verilog中,input通常用于描述数字电路的输入端口。以下是一个简单的input语句示例:
```
module adder(input [7:0] a, input [7:0] b, output [7:0] sum);
assign sum = a + b;
endmodule
```
在这个示例中,我们使用input关键字描述了两个8位输入信号a和b,用于加法运算。
39. integer
integer关键字用于描述整数类型。在Verilog中,integer通常用于描述计数器和状态机等数字电路。以下是一个简单的integer语句示例:
在这个示例中,我们使用integer关键字定义了一个计数器变量i,用于计数,每当i等于255时,将计数器count加1。
40. join
join关键字用于等待并发执行的代码块完成。在Verilog中,join通常与fork语句一起使用,用于等待多个并发执行的代码块的完成。以下是一个简单的join语句示例:
在这个示例中,我们使用fork关键字创建了两个并发执行的代码块,并使用join语句等待两个代码块的执行完成。