模块
FPGA开发以模块为基础,每个可综合的.v文件都是一个模块。
模块由module和endmodule来声明,在这两个关键字的内部,完成模块功能的实现。
在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;
中的 <=
表示的是非阻塞赋值。
阻塞赋值时,输入改变输出是同时改变,在非阻塞赋值中,只有在时钟变化的时候,输出才会发生变化。
- '<=' 非阻塞赋值 适用于给reg变量赋值,always块 - 时序逻辑
- ‘=’ 阻塞赋值 适用于给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
😍稳了!!!
寄刀片,催更