【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;elsecounter <= counter + 1'b1; always@(posedge Clk or negedge Reset_n)if(!Reset_n)Led <= 8'b0000_0001;else if(counter == 24999999) beginif(Led == 8'b1000_0000)Led <= 8'b0000_0001;elseLed <= Led << 1;endelse Led <= Led; //当然了,时序逻辑中不加这句话默认保持状态
endmodule
1.2 功能仿真
为了避免仿真跑的时间太长,我们ba0.5s替换为0.05s,所以我们姑且把24999999999替换为24999,也就是500ms→500ums。
`timescale 1ns/1nsmodule 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; //一个周期20nsinitial beginReset_n = 0;#201;Reset_n = 1;#4000000; //8*500us = 40000000ns$stop;endendmodule
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;elsecounter <= 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/1nsmodule 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; //一个周期20nsinitial beginReset_n = 0;#201;Reset_n = 1;#4000000; //8*500ms = 40000000ns$stop;endendmodule
- 由于现在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 / 1psmodule 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.1sled_flash led_flash_inst1(.Clk(Clk),.Reset_n(Reset_n), .Led(Led[1]));defparam led_flash_inst1.MCNT = 4999999;//0.2sled_flash led_flash_inst2(.Clk(Clk),.Reset_n(Reset_n), .Led(Led[2]));defparam led_flash_inst2.MCNT = 7499999; //0.3s 150ms = 150000000ns/20ns = 7500000led_flash led_flash_inst3(.Clk(Clk),.Reset_n(Reset_n), .Led(Led[3]));defparam led_flash_inst3.MCNT = 9999999; //0.4s 200ms = 200000000/20ns = 10000000endmodule
添加约束文件
右击,手动设置为target
复制之前自动生成的代码,并稍作改动,然后下载到板子上就okk啦~ 就是为了巩固一下参数化设计~~