【FPGA】verilog语法的学习与应用 —— 位操作 | 参数化设计
学习新语法,争做新青年
计数器实验升级,让8个LED灯每个0.5s的速率循环闪烁,流水灯ahh好久不见~ 去年光这个就把我折磨够呛。。我肉眼可见的脱发就是从那时候开始的。。在那两个月我直接掉了10斤啊喂~ (没节食、没运动、没失恋哈哈哈
- 产生0.5s周期的计数器
文章目录
- 【FPGA】verilog语法的学习与应用 —— 位操作 | 参数化设计
- 1. version 1 - 移位法
- 1.1 设计输入
- 1.2 功能仿真
- 1.3 板子调试
- 2. version 2 - 循环移位
- 3. version 3 - 3-8译码器
- 4. 参数化设计
- 添加约束文件
1. version 1 - 移位法
1.1 设计输入
module led_run(
Clk,
Reset_n,
Led
);
input Clk;
input Reset_n;
output reg[7:0] Led;
reg[24:0] counter;
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
counter <= 0;
else if(counter == 24999999)
counter <= 0;
else
counter <= counter + 1'b1;
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
Led <= 8'b0000_0001;
else if(counter == 24999999) begin
if(Led == 8'b1000_0000)
Led <= 8'b0000_0001;
else
Led <= Led << 1;
end
else
Led <= Led; //当然了,时序逻辑中不加这句话默认保持状态
endmodule
1.2 功能仿真
为了避免仿真跑的时间太长,我们ba0.5s替换为0.05s,所以我们姑且把24999999999替换为24999,也就是500ms→500ums。
`timescale 1ns/1ns
module led_run_tb();
//激励信号
reg Clk;
reg Reset_n;
wire[7:0] Led;
led_run led_run_inst( //例化
//连线
.Clk(Clk),
.Reset_n(Reset_n),
.Led(Led)
);
initial Clk = 1;
always #10 Clk = ~Clk; //一个周期20ns
initial begin
Reset_n = 0;
#201;
Reset_n = 1;
#4000000; //8*500us = 40000000ns
$stop;
end
endmodule
1.3 板子调试
别忘了把时间调回来啊喂!不然可看不出流水了~
是的,我写完这句话就忘调了。。不愧是我
2. version 2 - 循环移位
改进移位
module led_run1(
Clk,
Reset_n,
Led
);
input Clk;
input Reset_n;
output reg[7:0] Led;
reg[24:0] counter;
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
counter <= 0;
else if(counter == 25'd24999999)
//else if(counter == 25'd24999)
counter <= 0;
else
counter <= counter + 1'b1;
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
Led <= 8'b0000_0001;
else if(counter == 25'd24999999)
//else if(counter == 25'd24999)
Led <= {Led[6:0], Led[7]};
else
Led <= Led; //当然了,时序逻辑中不加这句话默认保持状态
endmodule
Led <= {Led[6:0], Led[7]};
{}
:位拼接- 循环移位
虽然。。这种写法用的也不多~
那我们来仿真一下,test bench把例化时名称改一下就ok
没问题~~
3. version 3 - 3-8译码器
引入3-8译码器的逻辑
模块中调用模块:把文件拷贝过来 → Add files即可
这里例化模块和test bench中是一模一样的方法~ 我我我悟了!
`timescale 1ns/1ns
module led_flash_tb();
//激励信号
reg Clk;
reg Reset_n;
wire[7:0] Led;
led_run2 led_run_inst( //例化
//连线
.Clk(Clk),
.Reset_n(Reset_n),
.Led(Led)
);
initial Clk = 1;
always #10 Clk = ~Clk; //一个周期20ns
initial begin
Reset_n = 0;
#201;
Reset_n = 1;
#4000000; //8*500ms = 40000000ns
$stop;
end
endmodule
- 由于现在Led是由底层模块驱动的,我们在底层已经定义为
reg
型了,所以顶层要去掉
4. 参数化设计
是的,你看到了,我转头就忘了把时间改回来了~
啊这就相当于C语言中的**#define定义常量**
我们在led_run中添加 ——
parameter MCNT = 25'd24999;
并在led_run_tb中这样写:
led_run led_run_inst( //例化
//连线
.Clk(Clk),
.Reset_n(Reset_n),
.Led(Led)
);
defparam led_run_inst.MCNT = 24999;
或者在led_run_tb中这样来写
led_run2
#(
.MCNT(24999)
)
led_run_inst( //例化
//连线
.Clk(Clk),
.Reset_n(Reset_n),
.Led(Led)
);
让4个LED灯以不同的频率进行闪烁
0.1s, 0.2s, 0.3s, 0.4s…
led_flash.v
module led_flash (
//端口
Clk,
Reset_n, //复位
Led
);
//端口定义
input Clk;
input Reset_n;
output reg Led;
parameter MCNT = 24999999;
reg[24:0] counter;
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
counter <= 0;
else if(counter == MCNT)
counter <= 0;
else
counter <= counter + 1'd1;
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
Led <=0;
else if(counter == MCNT)
Led <= !Led;
endmodule
led_run_8_test.v
`timescale 1ns / 1ps
module led_run_8_test(
//端口
Clk,
Reset_n, //复位
Led
);
//端口定义
input Clk;
input Reset_n;
output[3:0] Led;
led_flash led_flash_inst0(
.Clk(Clk),
.Reset_n(Reset_n),
.Led(Led[0])
);
defparam led_flash_inst0.MCNT = 2499999;//0.1s
led_flash led_flash_inst1(
.Clk(Clk),
.Reset_n(Reset_n),
.Led(Led[1])
);
defparam led_flash_inst1.MCNT = 4999999;//0.2s
led_flash led_flash_inst2(
.Clk(Clk),
.Reset_n(Reset_n),
.Led(Led[2])
);
defparam led_flash_inst2.MCNT = 7499999; //0.3s 150ms = 150000000ns/20ns = 7500000
led_flash led_flash_inst3(
.Clk(Clk),
.Reset_n(Reset_n),
.Led(Led[3])
);
defparam led_flash_inst3.MCNT = 9999999; //0.4s 200ms = 200000000/20ns = 10000000
endmodule
添加约束文件
右击,手动设置为target
复制之前自动生成的代码,并稍作改动,然后下载到板子上就okk啦~ 就是为了巩固一下参数化设计~~