模块

FPGA开发以模块为基础,每个可综合的.v文件都是一个模块。

模块由moduleendmodule来声明,在这两个关键字的内部,完成模块功能的实现。

在Vivado的一个空项目中,新建一个.v源文件,会自动生成以下代码:

`timescale 1ns / 1ps	// 这行以后代码经常会见,表示时间单位是1ns,精度是1ps    
 
 
module verilog_base(	// module 模块名(
	...		            // 定义模块的输入输出接口
);			            // );
endmodule		        // endmodule

下面以一个与门为例,演示如何声明一个模块:

`timescale 1ns / 1ps	// 时间单位是1ns,精度是1ps    
 
 
module verilog_base(
    // input表示这是模块的输入接口
    // wire是变量类型 a是变量名
	input wire a,	
	input wire b,
    // output表示这是模块的输出接口
    // wire是变量类型 c是变量名
	output wire c
);
 
assign c = a & b;		// 完成与门的组合逻辑赋值
 
endmodule

变量类型

Verilog有两种常用数据类型:wire (线)、reg (寄存器)。

在数字电路中信号只有两种形态:传输、存储。

通过连接线传输,用寄存器存储。

因此在Verilog中常用wire和reg变量。

wire和reg变量模型如下图所示:

wire型变量在物理结构上只是一根线,在Verilog描述时,对线型变量赋值用assign即可。

C语言 a = b;

Verilog赋值得在前面加关键字 assign a = b;

reg型变量左端有一个输入端口D,右端有一个输出端口Q,并且reg型存储数据需要在clk(时钟)沿的控制下完成。

clk的低电平用数字0表示,高电平用1表示。

从低电平转变到高电平的过程叫做上升沿,从高电平转变到低电平的过程叫做下降沿。

对reg型变量赋值时,必须在always块内完成,可以选择用时钟上升沿,也可以选择时钟下降沿,具体用上升沿还是下降沿可以根据需要定。

下面以一个与门为例:

`timescale 1ns / 1ps	// 时间单位是1ns,精度是1ps    
 
 
module verilog_base(
	input		wire		clk,	// 系统时钟输入,由晶振提供
	input		wire		a,
	input		wire		b,
	output		reg		    c	    // 输出类型是reg
);
 
// reg型变量的赋值必须要在always块里面
// 注意:赋值符号不是'=',而是 '<='
// posedge clk 代表时钟上升沿
always @(posedge clk) begin
	c <= a & b;
end
 
endmodule

在 always 块中,@(posedge clk) 表示每当遇到clk的上升沿时,执行always块中的语句。

c **<=** a & b; 中的 <= 表示的是非阻塞赋值。

阻塞赋值时,输入改变输出是同时改变,在非阻塞赋值中,只有在时钟变化的时候,输出才会发生变化。

  1. '<=' 非阻塞赋值 适用于给reg变量赋值,always块 - 时序逻辑
  2. =’ 阻塞赋值 适用于给wire变量赋值,assign块 – 组合逻辑

赋值语句

assign 和 always分别用于组合逻辑的赋值 和 时序逻辑的赋值。

initial,一般仅用于仿真文件中。

initial 语句是初始化语句,会在上电(电路刚刚运行时)执行一次,不会循环执行。

在电路中只有可以存储数据的寄存器才有初始化的必要,所以initial 语句中被赋值的变量也必须为reg

reg	clk;
initial begin
	clk = 0;
    // forever和always的区别是 forever仅用于仿真
    // 每5ns时钟反转一次
	forever #(5) clk = ~clk;    
end

条件判断

Verilog HDL 中经常使用的判断语句有if else 语句和case endcase 语句.

两种判断语句必须写在****always 语句中,不能写在assign 中。

if-else

always@(posedge clk)begin
	if(a==1) begin
		b <= 1;
	end
	else if(a==2) begin
		b <= 2;
	end		
	else if(a==3) begin
		b <= 3;
	end
	else if(a==4) begin
		b <= 4;
 	end
 	else if(a==5) begin
 		b <= 5;
 	end
 end

每一个if else 语句都会生成一选择器

case

在if-else 级数过多的情况下,也可以使用case 语句,case 语句生成的是多路器

case 语句以case 开始,以endcase 结尾,在其之间,列出要判断的条件,根据条件的值,执行对应的代码。

always@(posedge clk) begin
	case(a)
		0: 
			b <= 0;
		1: 
			b <= 1;
		2: 
			b <= 2;
		default:
			b <= 0;
	endcase
end

已有 2 条评论

  1. 😍稳了!!!

  2. 寄刀片,催更

发表评论