Quartus提供的LPM_counter IP 核的使用
一、FPGA主要设计方式
1、原理图(不推荐):
原理图设计早期应该用比较广泛,但当系统比较大时,修改比较困难,因此,目前已逐渐被HDL设计方式所取代,仅在有些设计的顶层描述会有使用。Quartus内嵌的原理图编辑器时Schematic Editor。
2、Verilog HDL 设计方式
应用最广泛,目前常用的语言有Verilog和VHDL语言。Quartus内嵌的文本编辑器为Text Editor,其可以根据语法来用不同的颜色显示关键字。除此之外,常用的文本编辑器还有Ultra Edit。
3、IP核输入方式
IP核输入方式是FPGA设计中的一个重要设计输入方式。所谓的IP核是指Mega-functions/Mega Wizard,它能生成IP核功能较多,无论是简单的基本设计模块还是复杂的处理器都可以,适当地使用IP核,可以很大程度上减轻工程师地设计工作量,并且也可提高设计质量,缩短开发周期。
4、其他辅助性设计输入
其他辅助性设计输入方法还有状态机输入、真值表输入和波形图输入等。
二、IP核介绍
1、定义
将在数字电路中常用但较复杂的功能块,如FFT、FIR滤波器、PCI接口等设计成可修改参数的模块,让其他用户可以直接调用这些模块,从而减轻了工程师负担,避免重复劳动。
2、分类
核是一种预定义的并经过验证的复杂功能模块,其可以集成到系统设计中。
在FPGA设计中的核分为三种:硬核、固核和软核。
- 硬核:针对特定的实现技术优化的,具有不可修改的结构和布局布线,可作为库元件使用,时序性能稳定,但是无法按照设计进行修改和调整时序。
- 固核:由HDL源码和实现技术有关的网表组成,使用者可按照规定增减部分功能。固核的关键路径时序是固定的,但其实现技术无法更改,即不同厂家的FPGA固核无法互换使用。
- 软核:可综合的硬件描述语言源码,其与实现技术无关,可按照使用者进行修改,具有很大的灵活性,但软核的关键路径时序性能无保证,最终性能主要决定于使用者采用的综合、布局布线和实现技术。
3、核基FPGA设计流程
- 设计输入:一般采用HDL语言,输入完设计和仿真模型后就可进行第二步;
- 功能仿真
- 逻辑电路综合:这一步应该加上合适的时序约束,从而满足设计的要求,约束条件可以由综合文件给出,完成设计输入后进入第四步;
- 设计实现阶段:在此阶段,用户综合出的网表和设计约束文件一起输入给FPGA布局布线工具,完成FPGA的最后实现,并产生时序文件用于时序仿真和功能验证;
- 设计验证阶段:这一阶段用静态时序分析判定设计是否达到性能要求,对比仿真结果和时序仿真结果,验证设计的时序和功能是否正确。若性能无法达到要求,则需要找出影响性能的关键路径,并返回延时信息,修改约束文件,对设计进行重新综合和布局布线,如此重复多次指导满足设计要求为止。若仍不满足设计要求,则需要修改设计或采用其他实现技术。
三、实操
1、调用Quartus自带的计数器IP核
Tools--->MegaWizard Plug-In Manger--->Creat --->Next--->LPM_COUNTER--->Next--->打开了参数配置页面,设置计数器输出多少位(这里设置4位),创建端口有只增、只减和增减(这里选择只增)--->Next--->计数器类型(选择计数器计数到10时自动清零),设计其他端口(进位输入,进位输出)--->Next--->设置其他输入信号(这里暂不添加)--->Next--->Next--->Finish
点击Files,单击右键,点击Adds/Remove Files in Project,点击三个点,点击counter,点击Add,点击ok。
点击counter.v文件,选择将其设计为顶层文件后,分析和综合后,双击RTL Files查看结构。
2、仿真验证
`timescale 1ns/1ns
`define clock_period 20 //设置时钟周期20ns,即频率为50MHz
module counter_tb;
reg cin; //进位输入
reg clk; //计数基准时钟
wire cout; //进位输出
wire [3:0] q;
counter counter0(
.cin(cin),
.clock(cout),
.cout(cout),
.q(q)
);
initial clk = 1;
always #(`clock_period/2 ) clk = ~clk; //每次到达时钟周期一半时,信号翻转
initial begin
repeat(5) begin //重复5次,产生脉冲信号
cin = 0;
#{`clock_period*5} cin = 1; //延时5个时钟周期后,cin为1
#(`clock_period) cin = 0; //延时1个时钟周期后,cin为0
end
#{`clock_period*200} ;
$stop;
end
endmodule
3、结果分析
由于在程序中设置的重复5次,因此cin有五次信号,且5个时钟周期后变为高电平,1个时钟周期后,变为低电平,当cin为高电平时,进位输出q加1,从000变为101
四、将四位计数器修改为八位计数器
方法一:直接在IP核中修改
方法二:将两个四位计数器级联为八位计数器,具体如下图所示:
将两个四位计数器级联,当counter0计满后,cout输入信号给counter1的cin。
程序如下所示:
module counter_top(cin,clk,cout,q);
input cin;
input clk;
output cout;
output [7:0] q;
wire cout0;
counter counter0(
.cin(cin),
.clock(clk),
.cout(cout0),
.q(q[3:0])
);
counter counter1(
.cin(cout0),
.clock(clk),
.cout(cout),
.q(q[7:4])
);
endmodule
对其进行测试程序输入:
`timescale 1ns/1ns
`define clock_period 20
module counter_top_tb;
reg cin;//进位输入
reg clk;//计数基准时钟
wire cout;//进位输出
wire [7:0] q;
counter_top counter0(
.cin(cin),
.clk(clk),
.cout(cout),
.q(q)
);
initial clk = 1;
always #(`clock_period/2) clk = ~clk;
initial begin
repeat(300)begin
cin = 0;
#(`clock_period*5) cin = 1;
#(`clock_period) cin = 0;
end
#(`clock_period*200);
$stop;
end
endmodule
对其进行RTL仿真,得到如下结果:
从图中可以看出,当低四位到9后,counter0的cout向counter1的cin输入信号,当高四位和低四位到99后,cout输出一个信号。