我们先看下逻辑电路中有四种值,即四种状态:
标识符(identifier)用于定义模块名、端口名和信号名等。 Verilog的标识符可以是任意一组字母、数字、 $和_(下划线)符号的组合,但标识符的第一个字符必须是字母或者下划线。另外,标识符是区分大小写的。不建议大小写混合使用,普通内部信号建议全部小写, 参数定义建议大写。
二进制表示如下: 4’b0101表示4位二进制数字0101;
十进制表示如下: 4’d2表示4位十进制数字2(二进制0010) ;
十六进制表示如下: 4’ha表示4位十六进制数字a(二进制1010) 。
当代码中没有指定数字的位宽与进制时,默认为32位的十进制。
寄存器类型(reg、 integer、 real)
寄存器类型表示一个抽象的数据存储单元,它只能在always语句和initial语句中被赋值,如果该过程语句描述的是时序逻辑,即always语句带有时钟信号,则该寄存器变量对应为寄存器;如果该过程语句描述的是组合逻辑, 即always语句不带有时钟信号,则该寄存器变量对应为硬件连线;
- reg [31:0] delay_cnt; //延时计数器
- reg key_flag ; //按键标志
线网类型(tri、wire)
线网表示Verilog结构化元件间的物理连线。它的值由驱动元件的值决定,例如连续赋值
或门的输出。
- wire data_en; //数据使能信号
- wire [7:0] data ; //数据
参数类型(parameter)
参数其实就是一个常量,常被用于定义状态机的状态、数据位宽和延迟大小等,由于它可以在编译时修改参数的值,因此它又常被用于一些参数可调的模块中,使用户在实例化模块时,可以根据需要配置参数。参数的定义是局部的,只在当前模块中有效。
parameter DATA_WIDTH = 8; //数据位宽为8位
算术运算符
关系运算符
逻辑运算符
条件运算符
位运算符
移位运算符
拼接运算符
- module led(
- input sys_clk , // 系统时钟
- input sys_rst_n, // 系统复位,低电平有效
- output reg [3:0] led // 4位LED灯
- );
-
- parameter define
- parameter WIDTH = 25 ; // 位宽
- parameter COUNT_MAX = 25_000_000; // 板载50M时钟=20ns, 0.5s/20ns=25000000,需要25bit
-
- //reg define
- reg [WIDTH-1:0] counter ;
- reg [1:0] led_ctrl_cnt;
-
- //wire define
- wire counter_en ;
-
- //***********************************************************************************
- //** main code
- //***********************************************************************************
- //计数到最大值时产生高电平使能信号
- assign counter_en = (counter == (COUNT_MAX - 1'b1)) ? 1'b1 : 1'b0;
-
- //用于产生0.5秒使能信号的计数器
- always @(posedge sys_clk or negedge sys_rst_n) begin
- if (sys_rst_n == 1'b0)
- counter <= 1'b0;
- else if (counter_en)
- counter <= 1'b0;
- else
- counter <= counter + 1'b1;
- end
-
- //led流水控制计数器
- always @(posedge sys_clk or negedge sys_rst_n) begin
- if (sys_rst_n == 1'b0)
- led_ctrl_cnt <= 2'b0;
- else if (counter_en)
- led_ctrl_cnt <= led_ctrl_cnt + 2'b1;
- end
-
- //通过控制IO口的高低电平实现发光二极管的亮灭
- always @(posedge sys_clk or negedge sys_rst_n) begin
- if (sys_rst_n == 1'b0)
- led <= 4'b0;
- else begin
- case (led_ctrl_cnt)
- 2'd0 : led <= 4'b0001;
- 2'd1 : led <= 4'b0010;
- 2'd2 : led <= 4'b0100;
- 2'd3 : led <= 4'b1000;
- default : ;
- endcase
- end
- end
- endmodule
也就是说always块内的语句是一种顺序关系,这里和C语言很类似。 符号“ =”用于阻塞的赋值(如:b = a;) ,阻塞赋值“ =”在begin和end之间的语句是顺序执行,属于串行语句。
符号“ <=”用于非阻塞赋值(如:b <= a;), 非阻塞赋值是由时钟节拍决定,在时钟上升到来时,执行赋值语句右边,然后将begin-end之间的所有赋值语句同时赋值到赋值语句的左边,注意:是begin—end之间的所有语句,一起执行,且一个时钟只执行一次, 属于并行执行语句。 这个是和C语言最大的一个差异点,大家要逐步理解并行执行的概念。