Verilog语法

Verilog简介

Verilog是一种硬件描述语言(HDL),可以转化成现实中的电路结构,可以实现并行执行,不同于用于变成单片机的C语言,单片机只是执行程序,并不会改变硬件,只能实现串行执行。这也使得FPGA获得了更快的执行速度、更高的上手门槛和更高昂的价格。

目前有三种主流的硬件描述语言,Verilog,VHDL,SystemVerilog,其中SystemVerilog集两者之大成,支持了更多的功能,一般用于项目中,学习的时候可以先学习Verilog和VHDL,Verilog语法规则更像C语言,更加容易上手,而VHDL更像Ada,语法严谨。在正点原子的教程中,先学习Verilog。但是,我们需要熟悉并行执行的思想,摆脱C语言串行执行的特性,这样才能做到得心应手。

Verilog可以用于描述电路的结构、功能和行为,并通过EDA工具转化为实际电路,最后再根据FPGA的结构和资源映射到使用的FPGA中,生成比特流文件,进行烧录。

Verilog语法

基础知识

逻辑状态

逻辑状态

表示状态

0

低电平,一般为GND

1

高电平,一般为VCC

X

未知状态,如同时连接高低

Z

高阻态,可以被上拉或下拉

数据表示

再Verilog中,数据的表示需要考虑位数和进制,表示方法如下

4'b1011		// 四位二进制1011
4'd10		// 四位十进制1010

其中第一个数是位宽(转换到二进制的位数),后面的字母表示进制如二进制b,十进制d, 十六进制h,最后面就是数据了,如果前面不加限定,Verilog语言默认为32'd

基础语法

标识符

标识符就相当于变量名,总体的命名规则和C语言类似,这里就不过多赘述了。

可以采用下划线分隔的方法如cpu_clk等。

变量

Verilog的变量有三种类型,寄存器,线网和参数。

名称

关键字

使用方法

特点

寄存器

reg

reg[width-1:0] identifier;,默认位宽为1

只能再always和initial赋值,初值为X

线网

wire

tri

wire identifier;位宽设置与reg相同

表征物理连接,值受到驱动它的门电路、assign语句等的影响。默认为Z

参数

parameter

parameter xxx = xxx;

常量,如果程序多处用到该常量,可以统一常量。赋值时必须使用常量赋值。

运算符

大部分和C语言一致,下面只列出不同

  • / 在Verilog中,除法只保留整数。
  • ~ 按位取反
  • & 按位与
  • | 按位或
  • ^ 按位异或
  • && 逻辑与
  • || 逻辑或
  • 位运算时,左移位宽增加,右移位宽不变(舍弃末尾)
  • {a,b}拼接,将ab拼接为一个

这里需要注意这些运算的优先级

程序框架

模块

模块是Verilog和设计的最基本单元。模块有一部分描述接口,一部分描述功能。例如

module block(a, b, c, d);	// define the interfaces of the module
	// set the mode of the interfaces
	input a, b;	
	output c, d;

	// description of the function of the module
	assign c = a | b;
	assign d = a & b;

endmodule		// any module must include

模块分为可综合和不可综合两种,可综合意味着通过模块可以生成电路,而上一课的仿真模块则是不可综合的。

module flow led(
	input sys_clk,			// System Clock
	input	sys_rst_n,		// Reset Signal, Low
	output reg[3:0] led );
	
	// reg define
	reg [23:0]counter;	
	
	// counter will count and
	always (posedge sys_clk or negedge sys_rst_n) begin
		if (!sys_rst_n)
			counter < 24'd0;
		else if (counter 24'd1000 0000)
			counter < counter +1'bl;
		else
			counter < 24'd0;
	end
	
	//通过移位寄存器控制I0口的高低电平,从而改变1ED的显示状态
	always @(posedge sys_clk or negedge sys_rst_n) begin
		if (!sys_rst_n)
			led<=4'b0001:
			else if(counter ==24'd1000_0000)
				led[3:0]<={led[2:0],led[3]}:
				else
					led <led;
	end
endmodule

一般描述功能会用到三种方法

  1. assign 描述组合逻辑
  2. always 描述时序或组合逻辑
  3. 例化实例元件

注意,这三种方法描述的是并行执行的,但是在单个always中的代码是串行的

模块调用

`timescale 1ns/1ns  // set the unit and accuracy by `timescale unit/accuracy
module TB_LED ();
    reg key;
    wire LED;
    initial begin   //run at the intitialize
    // generate an alternate changing signal
        key <= 1'b1;
        #200
    end
// connnect the test signal to the module
LED u_led(
    .Key    (key), 
    .LED    (LED)
);
endmodule

上一节课的仿真程序其实就是模块例化,第12行例化了一个LED模块。并把顶层模块的key和LED信号传入到例化模块,除了输入,还可以传递输出和参数

module seg_led_sstatic_top ();
	time_count #(
		.MAX_NUM	(TIME_SHOW)		// parameter
	) u_time_count (
		.clk	(sys_clk), 			// input

		.flag	(add_flag)			// output
	);
endmodule

Initial & Always

这两个东西有点像arduino里面的setup和loop,一个初始化执行,一个重复执行。Initial一般用在仿真文件里,它可以在初始化的时候产生测试信号。

initial begin
	button			<= 1'b0;
	#100
	button			<= 1'b1;
end

always在比那些的时候必须给一个时钟延迟,也就是执行的周期

always #10 
	sys_clk <= ~sys_clk; // generate a clock

这是通过认为设定周期来实现功能。而always语句还能够通过上升沿和下降沿触发。

always @(posedge sys_clk or negedge sys_rst_n) begin
		// your code
end  

always @(sys_clk or sys_rst_n) begin
		// your code
end  

always @( * ) begin
		// your code
end  

这种边沿触发就可以实现时序电路,而由or连接的触发调节列表被称为敏感列表。

下面一种就是电平触发的, 前面不加posedge, * 表示对所有输入变量敏感。这种电平触发可以用于构建组合逻辑。

高级语法

赋值语句

在Verilog中,分为阻塞赋值和非阻塞赋值

  1. 阻塞赋值

前面的赋值语句会阻塞后面的,也就是说前面还没有执行完,后面就不可以执行。

  1. 非阻塞赋值

相当于把多个赋值语句并行执行,先把右边的值算出,然后统一赋给左边

//阻塞赋值
a = b;
//非阻塞赋值
a <= b;

简单来说,阻塞赋值用于组合逻辑,非阻塞逻辑用于时序逻辑,因为时序逻辑涉及到电路的执行顺序

注意:

  1. 在同一个always中不要混用两种赋值方法
  2. 不能再多个always中赋值同一个变量

条件语句

if-else

在verilog中没有大括号,需要使用begin-end引导。

if-else语句必须放在由always或initial引导的程序块中。

如果条件为1则为真 0,x,z状态均为假。

其他语法与c语言相同。

case

case语句有些不同。

case (num)
	4'h0 : 	led <= 8'b0011_1010;
	4'h1 : 	led <= 8'b0101_1100;
	...
	default : 	led <= 8'b1111_1111;
endcase

直接去掉了switch,使用case引导,下面直接列举数据。

还有两种变体

  • casez不考虑条件中的高阻值,也就是只要1, 0, x相同就进入条件
  • casex不考虑条件中的高阻值和未知数x。

状态机

状态机应该是在数电中学过的,就是用来描述时序电路功能的有限状态机,它可以表示电路的状态之间的转换关系,比如转换的条件和转换过程中的输出,下面以电子密码锁来举例

每一个圆圈代表电路的一个状态,箭头表示状态之间的转换。这种可以在多个状态之间转化的时序电路被称为有限状态机。其基本结构图如下

下面这种状态机被称为Mealy电路,它的输出由输入和当前状态决定,输入和上一状态经过组合逻辑F产生新的状态并在clk边沿是进入寄存器,最后通过组合逻辑G输出

如果输出与输入无关,也就是去掉上面的蓝线,或者说输入改变状态,然后状态经由组合逻辑输出,输入不直接影响输出。这种状态机被称为Moore状态机。

Verilog状态机设计

状态机的设计分为以下四个步骤

  1. 状态空间定义
  2. 状态跳转
  3. 下一状态判断
  4. 各个状态的动作

这四个步骤分别对应上图中的圆圈、箭头、跳转条件(箭头旁的文字)和最后的解锁动作。

parameter STATEA = 4'b0001;
parameter STATEB = 4'b0010;
parameter STATEC = 4'b0100;
parameter STATED = 4'b1000;

reg[3:0] current_state;
reg[3:0] next_state;

这段代码完成了状态空间的定义,首先通过独热编码对四个状态进行编码,接下来定义了两个状态寄存器,分别存储当前状态和下一状态。

always @(posedge clk or negedge rst_n) 
	if(!rst_n)
		current_state <= STATEA;
	else
		current_state <= next_state;
end

下一状态判断就是一个组合逻辑,输入此状态和其他输入,输出下一状态

always @(current_state or input_signals) begin
	case (current_state)
		STATEA : begin
			if(signal1)
				next_state = STATEB;
			else
				next_state = STATEC;
		end
		STATEB : begin
			if(signal2)
				next_state = STATEC;
			else
				next_state = STATEB;
		end
		default : next_state = current_state;
	endcase
end

这段代码就可以通过当前状态和输入产生下一状态。

最后就是根据当前状态产生输出

assign out = (current_state == STATEA) ? behavior1 : behavior2;

always @(current_state) begin
	if(current_state == STATEA)
		out = out1;
	else 
		out = out2;
end

有两种方式可以实现,一种是简单逻辑用assign加三目运算。复杂逻辑使用always加条件语句。

这四个步骤是并行执行的,并不需要规定顺序

三段式状态机

这种状态机在输出上加一个寄存器。这个寄存器主要实现以下几种功能。

  1. 对输出的竞争冒险现象进行滤波。
  2. 方便时序计算与约束(目前了解即可,后面会学)
  3. 对齐输出信号,方便总线传输(在clk来的时候输出)

总结

通过本节学习,熟悉Verilog基本语法,掌握以下知识点。

  1. Verilog的基础语法
  2. Verilog程序框架
  3. Verilog状态机的设计
  • 27
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Verilog是一种硬件描述语言(HDL),用于描述数字电路和系统。以下是Verilog常用的语法元素: 1. 模块声明 Verilog程序由一个个模块(module)组成。模块声明包括模块名、输入和输出端口等。 ```verilog module module_name (input port1, input port2, output port3); // 模块内部代码 endmodule ``` 2. 数据类型 Verilog支持多种数据类型,包括位、字、整数、浮点数等。 ```verilog // 位类型 reg [7:0] data; // 8位寄存器 // 字类型 reg [15:0] addr; // 16位寄存器 // 整数类型 integer count = 0; // 浮点数类型 real value = 3.14; ``` 3. 运算符 Verilog支持多种运算符,包括算术运算符、位运算符、逻辑运算符等。 ```verilog // 算术运算符 a + b; // 加 a - b; // 减 a * b; // 乘 a / b; // 除 a % b; // 取余 // 位运算符 a & b; // 按位与 a | b; // 按位或 a ^ b; // 按位异或 ~a; // 按位取反 // 逻辑运算符 a && b; // 逻辑与 a || b; // 逻辑或 !a; // 逻辑取反 ``` 4. 控制语句 Verilog支持多种控制语句,包括条件语句、循环语句和跳转语句等。 ```verilog // 条件语句 if (condition) begin // 代码块 end else begin // 代码块 end // 循环语句 for (i = 0; i < 10; i = i + 1) begin // 代码块 end // 跳转语句 case (signal) 2'b00: // 代码块 2'b01: // 代码块 2'b10: // 代码块 2'b11: // 代码块 endcase ``` 5. 实例化模块 Verilog允许在一个模块中实例化另一个模块。 ```verilog module module1 (input port1, output port2); // 模块内部代码 endmodule module module2 (input port3, output port4); module1 m1 (.port1(port3), .port2(port4)); endmodule ``` 以上是Verilog常用的语法元素,掌握这些基本语法是学习和设计FPGA电路的基础。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值