9月份接手了一个PCIE3.0读写存储器的项目,但是对于FPGA小白的我来说太难了,所以计划抽时间系统的学一学vivado写程序,顺便在CSDN上记录一下自己的学习轨迹,总结自己的学习心得。
和大多数人一样,第一个就是流水灯。
代码设计
- 创建工程
- 工程名符号只加 “_”
- 选择自己用的FPGA芯片型号,笔者用的是KU系列芯片-XCKU040
- 添加设计文件
如下图所示,顶层设计文件
- 顶层设计文件
module run_led# //模块名 run_led
(
parameter TSET = 32'd50_000_000-1'b1 //时间参数
)
(
input clk_p,
input clk_n, //该芯片时钟输入为差分输入
input RSTn_i,
output reg [7:0]LED_o
);
wire CLK_i;
/对差分时钟采用IBUFGDS IP核去转换
IBUFGDS CLK_U(
.I(clk_p),
.IB(clk_n),
.O(CLK_i)
);
reg [31:0]tcnt;
always @(posedge CLK_i)begin //时钟上升沿进行
if(!RSTn_i) //复位信号低电平时
tcnt <= 32'd0; //tcnt赋值为0
else if(tcnt < TSET) //复位信号高电平,且tcnt小于TEST时
tcnt <= tcnt + 1'b1; //tcnt+1操作
else
tcnt <= 32'd0; //复位信号高电平,且tcnt不小于TEST时,tcnt赋值为0
end
wire led_en = (tcnt == TSET); //当 tcnt = TSET时,led_en赋值为1
always @(posedge CLK_i)
if(!RSTn_i)begin
LED_o <= 8'b1; // LED_o赋值为0000_0001
end
else if(led_en)begin // led_en为1时进行
if(LED_o == 8'b10000000) // led_en为1时进行
LED_o <= 8'b1;
else LED_o <= LED_o << 1; //高电平不到最高位时,LED_o 左移一位,即2倍原数据,LED灯到下一位
end
endmodule
对于上述代码的一些解释
【1】parameter TSET = 32’d50_000_000-1’b1 :该工程时钟为100MHZ,即周期为10ns,TEST为50_000_000个10ns,即500_000_000ns,即0.5s。
parameter用来定义常量。
【2】reg:寄存器数据类型,通过赋值改变数值,通常用来表示always内部的指定信号
wire:wire相当于物理连线,输入输出信号为wire类型。
wire只能被assign连续赋值,reg只能在initial和always中赋值
仿真设计
- 仿真文件
module tb_run_led();
reg CLK_i,RSTn_i; // CLK_i,RSTn_i需要赋值,所以为reg类型
wire [3:0] LED_o; // LED_o为输出信号,所以为wire类型
//调用了顶层设计文件
run_led#
(
.TSET(1000)
)
run_led_inst(
.clk_p(CLK_i),
.clk_n(~CLK_i), //顶层设计文件时钟端口为差分p和n,不是CLK_i
.RSTn_i(RSTn_i),
.LED_o(LED_o)
);
initial begin
CLK_i <= 1'b0;
RSTn_i <= 1'b0;
#100;
RSTn_i <= 1'b1;
end
always #5 CLK_i = ~CLK_i;
endmodule
- 仿真结果
开发版调试没有问题,流水灯跑起来了。