当前位置:网站首页>基于 Cyclone IV 在 Quartus 中配置 IP 核中的 PLL、RAM 与 FIFO 的详细步骤及仿真验证
基于 Cyclone IV 在 Quartus 中配置 IP 核中的 PLL、RAM 与 FIFO 的详细步骤及仿真验证
2022-08-03 02:28:00 【可乐有点好喝】
本文内容:基于 Cyclone IV在 Quartus 中配置 IP 核中的 PLL 、 RAM 与 FIFO 的详细步骤
一、配置 PLL
- 在我看来哈,PLL 的作用就是将输入时钟通过倍频、分频、相位偏移、设置占空比等操作,将输入的时钟信号转变为另外一种形式的时钟信号,这个主要看自己的需求
1.1 参数配置
- 首先需要新建一个工程,在工程里面配置 PLL
- 在【IP Catalog】界面的搜索框中输入【PLL】,双击【ALTPLL】即可
- 如果没有【IP Catalog】界面,在【View】中可以设置
- 点击【…】选择 IP 核的保存路径
- 最好新建一个 ip 文件夹,输入文件名后保存(图中有文件,是之前加的)
- 再点击【OK】
- Cyclone IV 选择 8 通道、50 MHz(细心的兄弟会发现左边的 PLL_demo 有 c0 - c3 多个输出,但是自己的界面只有个 c0 ,没关系,这是后面才配置出来的,我这个是配置好的)
- 勾选上【Create ‘locked’ output】
- 默认即可
- 默认即可
- 默认即可
- 主要的配置界面如下:
Clock multiplication factor——时钟倍频参数
Clock division factor——时钟分频参数
Clock phase shift——时钟相位偏移参数
Clock duty cycle(%)——时钟占空比 - 这里我们让每一个输出设置一种参数类型来看看实际的效果
- 首先让 c0 设置倍频参数为 2,可以看到它的时钟频率变为了 100 MHz,再点击【Next>】
- c1 让它分频参数设为 2 ,可以看到它的频率变为了 25 MHz,再点【Next>】
- c2 相位偏移设为 90,单位是 deg,表示角度,也就是偏移了 π/2 个时钟周期,除了角度还有时间单位 ns、ps
- c3 时间占空比设为 20,之后可以具体看看是什么样子
- c4 我就没有勾选上了,因为就那么四个参数,没必要再搞一个 c4 输出了
- 继续点击【Next>】
- 勾选上【PLL_demo_inst.v】,这个可以生成相应的模块调用格式
1.2 仿真测试
- 写一个仿真文件,直接调用这个模块就可以,如果不怎么会仿真的话,可以参考博客:
Quartus 与 ModelSim 联合仿真详细步骤
基于 FPGA 按键控制呼吸灯原理、仿真及验证全过程 - 贴一下仿真代码
`timescale 1ns/1ns
module tb_pll;
// Parameter definition
parameter CYC_CLK = 20 ;
// Drive signal
reg tb_clk ;
reg tb_rst_n ;
// Observation signal
wire c0 ;
wire c1 ;
wire c2 ;
wire c3 ;
wire locked ;
// Module calls
PLL_demo PLL_demo_inst (
/*input */ .inclk0 (tb_clk ),
/*input */ .areset (~tb_rst_n ),
/*output*/ .c0 (c0 ),
/*output*/ .c1 (c1 ),
/*output*/ .c2 (c2 ),
/*output*/ .c3 (c3 ),
/*output*/ .locked (locked )
);
// System initialization
initial tb_clk = 1'b1;
always #10 tb_clk = ~tb_clk;
initial begin
tb_rst_n = 1'b0;
#20;
tb_rst_n = 1'b1;
#(500 * CYC_CLK);
$stop;
end
endmodule
- 在【Simulation】选择 Test Benches 中,选择哪一个仿真文件,就会仿真哪个,同时还要设置相应的顶层模块熬
- 仿真结果如下:
- 可以看到
c0 倍频,频率高了,时钟周期短了
c1 分频,频率低了,时钟周期长了
c2 相位偏移,右移了 π/2 个时钟周期
c3 设置占空比 20,高电平区间占一个时钟周期 20% - 这就是 PLL 的作用,将输出的 clock 时钟信号转变为其它类型的时钟信号
二、配置 RAM
2.1 参数配置
- 同样在【IP Catalog】搜索 RAM,选择 1-PORT 单端口的,2-PORT 表示双端口,学会了单端口那么双端口也依葫芦画瓢就会了
- 同样的操作步骤
- 这里表示一个数据字节为 8 bits,共 256 个字节,Auto 自动配置即可,勾选 Single clock 表示单个时钟信号控制输入输出就行
- 勾选上 q 也就是数据输出,同时勾选上复位信号 aclr 和读使能信号 rden
- 这里设置 Don’t Care 即可
- 在这里使用一个 hex 文件初始化 RAM,看下面怎么创建 hex 文件
- 切回 Quartus 主界面,点击【File】→【New…】
- 点击【Hexadecimal (Intel-Format) File】创建
- 新建的文件,里面是没有数据,选中所有的字节,右键点击【Custom Fill Cells…】
- Starting address:开始地址
Ending address:结束地址
Starting value:初始值
Increment:递增操作
by:步长 - 最后点击 OK
- 保存到 prj 下面,一定要是 prj 下面!!!
- 回到刚刚的窗口,添加 hex 文件到 RAM 中
- 再点击【Next>】
- 最后勾选上【inst】即可
2.2 仿真测试
- 仿真代码如下:
`timescale 1ns/1ns
module tb_ram;
// Parameter definition
parameter CYC_CLK = 20 ;
// Drive signal
reg tb_clk ;
reg tb_rst_n ;
reg [ 7:0] address ;
reg [ 7:0] data ;
reg rden ;
reg wren ;
// Observation signal
wire [ 7:0] q_out ;
// Module calls
RAM_demo RAM_demo_inst (
.clock (tb_clk ),
.aclr (~tb_rst_n ),
.address (address ),
.data (data ),
.rden (rden ),
.wren (wren ),
.q (q_out )
);
// System initialization
initial tb_clk = 1'b1;
always #10 tb_clk = ~tb_clk;
initial begin
address = 8'd25;
data = 8'd51;
rden = 1'b0;
wren = 1'b0;
tb_rst_n = 1'b0;
#20;
tb_rst_n = 1'b1;
// 读操作
rden = 1'b1;
repeat (256) begin
address = address + 8'd1;
#(CYC_CLK);
end
rden = 1'b0;
#(500 * CYC_CLK);
// 写操作
wren = 1'b1;
repeat (256) begin
data = data + 8'd2;
address = address + 8'd1;
#(CYC_CLK);
end
wren = 1'b0;
#(500 * CYC_CLK);
// 读操作
rden = 1'b1;
repeat (256) begin
address = address + 8'd1;
#(CYC_CLK);
end
rden = 1'b0;
#(500 * CYC_CLK);
$stop;
end
endmodule
- 记得设置仿真文件
- 仿真结果:
- 第一段读操作是读的 hex 文件设置的内容,写操作写入新的数据,第二个读操作,读取的是写入的新数据
三、配置 FIFO
3.1 参数配置
- FIFO 其实就是一个队列,先进先出的原则
- 同样的,输入 FIFO/fifo 双击
- 选择存储路径
- 看自己的选择勾选与设置
- 默认设置即可
- 按照下图自己需要进行配置
- 默认就行
- 没勾选
- 一直到这一步,勾选个 inst 即可,生成个模块调用语句而已
3.2 仿真测试
- 这里使用一个 Verilog 顶层模块调用 FIFO,并不断地写数据,同时不断地读数据
- 再写一个仿真测试文件来看看仿真波形
fifo_top.v
module fifo_top (
input clk ,
input rst_n ,
output [15:0] q ,
output rdempty ,
output [ 7:0] rdusedw ,
output wrfull ,
output [ 8:0] wrusedw
);
// Parameter definition
// Signal definition
reg [ 7:0] data ;
reg rdreq ;
reg wrreq ;
// Module calls
FIFO_512_8 FIFO_512_8_inst (
/*input */ .aclr (~rst_n ),// 复位信号,高电平有效
/*input [ 7:0]*/ .data (data ),// 写数据,8bits
/*input */ .rdclk (clk ),// 读时钟信号
/*input */ .rdreq (rdreq ),// 读使能信号,高电平读
/*input */ .wrclk (clk ),// 写时钟信号
/*input */ .wrreq (wrreq ),// 写使能信号,高电平写
/*output [15:0]*/ .q (q ),// 读数据,16bits
/*output */ .rdempty (rdempty ),// 读空使能,表示读的时候队列中是否为空,1表示空,0表示非空
/*output [ 7:0]*/ .rdusedw (rdusedw ),// 读余量,表示读的时候队列中有多少个16bits的数据
/*output */ .wrfull (wrfull ),// 写满使能,表示写的时候队列中是否写满了,1表示满,0表示非满
/*output [ 8:0]*/ .wrusedw (wrusedw ) // 写余量,表示写的时候队列中有多少个8bits的数据
);
// Logic description
// 读使能
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
rdreq <= 'd0;
end
else if (rdempty) begin
rdreq <= 'd0;
end
else begin
rdreq <= 'd1;
end
end
// 写使能
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
wrreq <= 'd0;
end
else if (wrfull) begin
wrreq <= 'd0;
end
else begin
wrreq <= 'd1;
end
end
// 写数据
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
data <= 'd20;
end
else if (wrreq) begin
if (data >= 255) begin
data <= 0;
end
else begin
data <= data + 'd2;
end
end
else begin
data <= 'd20;
end
end
endmodule
- 仿真文件
tb_fifo.v
`timescale 1ns/1ns
module tb_fifo;
// Parameter definition
parameter CYC_CLK = 20 ;
// Drive signal
reg tb_clk ;
reg tb_rst_n ;
// Observation signal
wire [15:0] tb_q ;
wire tb_rdempty ;
wire [ 7:0] tb_rdusedw ;
wire tb_wrfull ;
wire [ 8:0] tb_wrusedw ;
// Module calls
fifo_top U_fifo_top(
/*input */ .clk (tb_clk ),
/*input */ .rst_n (tb_rst_n ),
/*output [15:0]*/ .q (tb_q ),
/*output */ .rdempty (tb_rdempty ),
/*output [ 7:0]*/ .rdusedw (tb_rdusedw ),
/*output */ .wrfull (tb_wrfull ),
/*output [ 8:0]*/ .wrusedw (tb_wrusedw )
);
// System initialization
initial tb_clk = 1'b1;
always #10 tb_clk = ~tb_clk;
initial begin
tb_rst_n = 1'b0;
#20;
tb_rst_n = 1'b1;
#(200 * CYC_CLK);
$stop;
end
endmodule
- 仿真结果
- 可以看到队列先进先出的原则
- 但是读余量前面一段时间为 0 ,但是明明有数据,结果却为了,过了几个时钟周期后才变成 1
- 应该是由于写数据到 M9K 中这个过程需要时间,过了几个时钟周期后,读余量才检测到有数据,才读取数据
边栏推荐
猜你喜欢
openCV第一篇
怎么从零编写一个 v3 版本的 chrome 浏览器插件实现 CSDN 博客网站的暗黑和明亮主题切换?
leetcode:172. 阶乘后的零
【TA-霜狼_may-《百人计划》】美术2.5 模型常见问题及规范
Methods annotated with ‘@Async‘ must be overridable
【云原生】阿里云ARMS业务实时监控
Incorrect datetime value: '2022-01-01' for function str_to_date
leetcode:140. 单词拆分 II
【数据分析】基于MATLAB实现SVDD决策边界可视化
能添加任意贴图超级复布局的初级智能文本提示器
随机推荐
Disable the token and update the token function without awareness
[Arduino] Reborn Arduino Monk (3)----Arduino function
【Flink】使用arthas在线诊断flink的那些事
怎么从零编写一个 v3 版本的 chrome 浏览器插件实现 CSDN 博客网站的暗黑和明亮主题切换?
记录学习--Navicat使用自定义数据库列表
豆瓣评分9.3的好书,文末给大家抽奖送几本!
简单的布局的初级智能文本提示器
WordPress博客问答小插件
zyMedia系列之播放视频
我终于逃离了互联网,却陷入了迷茫
Usage of permute() function in pytorch
vs studio install opencv environment
Topic Modeling of Short Texts: A Pseudo-Document View
Kook机器人开发日志01
Summary of some interviews
# RACE32——高级断点的设置和应用
ROS通信模块:秒懂话题通信
leetcode:149. 直线上最多的点数
钻石基础知识介绍
Incorrect datetime value: '2022-01-01' for function str_to_date