🎉欢迎来到FPGA专栏~ip核基础知识之计数器
- ☆* o(≧▽≦)o *☆嗨~我是小夏与酒🍹
- ✨博客主页:小夏与酒的博客
- 🎈该系列文章专栏:FPGA学习之旅
- 文章作者技术和水平有限,如果文中出现错误,希望大家能指正🙏
- 📜 欢迎大家关注! ❤️
🎉 目录-ip核基础知识之计数器
- 一、效果演示
- 二、ip核创建流程
- 三、四位计数器仿真与分析
- 四、计数器级联与仿真
一、效果演示
LPM_COUNTER IP核的RTL视图:
IP核计数器级联的RTL视图:
二、ip核创建流程
需要注意:本篇博客所使用的Quartus Ⅱ版本为13.0。
创建LPM_COUNTER IP核的过程如下所示:
1、点击“Tools”,选择魔术棒“MegaWizard Plug-In Manager”。
2、选择“Create a new custom megafunction variation”, 创建一个新的自定义兆函数变体(先这么翻译吧)。
该对话框中的三个选项分别是新建一个定制IP核、编辑一个现有的IP核和复制一个现有的定制IP核。
3、本次项目使用LPM_COUNTER,选择好输出目录。
4、先使用4位的计数器,选择递增计数方式。
5、配置为计数值计数且为10d,有进位输入以及输出。
6、对于该IP核的基础使用,其余选项默认即可,直到Finish。这时我们能在Files中看到counter.qip文件,双击之后显示如下,这仅仅只是IP核的说明文件而已,我们还需要手动添加counter.v文件。
7、添加counter.v文件。
8、进入添加文件的界面。
9、选择当时输出目录下的counter.v文件。
10、选择文件完成之后,点击Add,并点击Apply。
11、此时就可以在Files中看到我们所添加的counter.v文件了。
12、将counter.v设置为顶层,并分析与综合。
分析与综合之后的RTL:
📜可见通过IP核生成的RTL视图与通过自己编写计数器的RTL是存在差异的。通过IP核生成的电路 更接近于真实的电路结构,IP核做了很多结构上的优化,能够使性能大幅度提高。
生成的IP核内容如下:
// megafunction wizard: %LPM_COUNTER%
// GENERATION: STANDARD
// VERSION: WM1.0
// MODULE: LPM_COUNTER
// ============================================================
// File Name: counter.v
// Megafunction Name(s):
// LPM_COUNTER
//
// Simulation Library Files(s):
// lpm
// ============================================================
// ************************************************************
// THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE!
//
// 13.0.0 Build 156 04/24/2013 SJ Full Version
// ************************************************************
//Copyright (C) 1991-2013 Altera Corporation
//Your use of Altera Corporation's design tools, logic functions
//and other software and tools, and its AMPP partner logic
//functions, and any output files from any of the foregoing
//(including device programming or simulation files), and any
//associated documentation or information are expressly subject
//to the terms and conditions of the Altera Program License
//Subscription Agreement, Altera MegaCore Function License
//Agreement, or other applicable license agreement, including,
//without limitation, that your use is for the sole purpose of
//programming logic devices manufactured by Altera and sold by
//Altera or its authorized distributors. Please refer to the
//applicable agreement for further details.
// synopsys translate_off
`timescale 1 ps / 1 ps
// synopsys translate_on
module counter (
cin,
clock,
cout,
q);
input cin;
input clock;
output cout;
output [3:0] q;
wire sub_wire0;
wire [3:0] sub_wire1;
wire cout = sub_wire0;
wire [3:0] q = sub_wire1[3:0];
lpm_counter LPM_COUNTER_component (
.cin (cin),
.clock (clock),
.cout (sub_wire0),
.q (sub_wire1),
.aclr (1'b0),
.aload (1'b0),
.aset (1'b0),
.clk_en (1'b1),
.cnt_en (1'b1),
.data ({4{1'b0}}),
.eq (),
.sclr (1'b0),
.sload (1'b0),
.sset (1'b0),
.updown (1'b1));
defparam
LPM_COUNTER_component.lpm_direction = "UP",
LPM_COUNTER_component.lpm_modulus = 10,
LPM_COUNTER_component.lpm_port_updown = "PORT_UNUSED",
LPM_COUNTER_component.lpm_type = "LPM_COUNTER",
LPM_COUNTER_component.lpm_width = 4;
endmodule
// ============================================================
// CNX file retrieval info
// ============================================================
// Retrieval info: PRIVATE: ACLR NUMERIC "0"
// Retrieval info: PRIVATE: ALOAD NUMERIC "0"
// Retrieval info: PRIVATE: ASET NUMERIC "0"
// Retrieval info: PRIVATE: ASET_ALL1 NUMERIC "1"
// Retrieval info: PRIVATE: CLK_EN NUMERIC "0"
// Retrieval info: PRIVATE: CNT_EN NUMERIC "0"
// Retrieval info: PRIVATE: CarryIn NUMERIC "1"
// Retrieval info: PRIVATE: CarryOut NUMERIC "1"
// Retrieval info: PRIVATE: Direction NUMERIC "0"
// Retrieval info: PRIVATE: INTENDED_DEVICE_FAMILY STRING "Cyclone IV E"
// Retrieval info: PRIVATE: ModulusCounter NUMERIC "1"
// Retrieval info: PRIVATE: ModulusValue NUMERIC "10"
// Retrieval info: PRIVATE: SCLR NUMERIC "0"
// Retrieval info: PRIVATE: SLOAD NUMERIC "0"
// Retrieval info: PRIVATE: SSET NUMERIC "0"
// Retrieval info: PRIVATE: SSET_ALL1 NUMERIC "1"
// Retrieval info: PRIVATE: SYNTH_WRAPPER_GEN_POSTFIX STRING "0"
// Retrieval info: PRIVATE: nBit NUMERIC "4"
// Retrieval info: PRIVATE: new_diagram STRING "1"
// Retrieval info: LIBRARY: lpm lpm.lpm_components.all
// Retrieval info: CONSTANT: LPM_DIRECTION STRING "UP"
// Retrieval info: CONSTANT: LPM_MODULUS NUMERIC "10"
// Retrieval info: CONSTANT: LPM_PORT_UPDOWN STRING "PORT_UNUSED"
// Retrieval info: CONSTANT: LPM_TYPE STRING "LPM_COUNTER"
// Retrieval info: CONSTANT: LPM_WIDTH NUMERIC "4"
// Retrieval info: USED_PORT: cin 0 0 0 0 INPUT NODEFVAL "cin"
// Retrieval info: USED_PORT: clock 0 0 0 0 INPUT NODEFVAL "clock"
// Retrieval info: USED_PORT: cout 0 0 0 0 OUTPUT NODEFVAL "cout"
// Retrieval info: USED_PORT: q 0 0 4 0 OUTPUT NODEFVAL "q[3..0]"
// Retrieval info: CONNECT: @cin 0 0 0 0 cin 0 0 0 0
// Retrieval info: CONNECT: @clock 0 0 0 0 clock 0 0 0 0
// Retrieval info: CONNECT: cout 0 0 0 0 @cout 0 0 0 0
// Retrieval info: CONNECT: q 0 0 4 0 @q 0 0 4 0
// Retrieval info: GEN_FILE: TYPE_NORMAL counter.v TRUE
// Retrieval info: GEN_FILE: TYPE_NORMAL counter.inc FALSE
// Retrieval info: GEN_FILE: TYPE_NORMAL counter.cmp FALSE
// Retrieval info: GEN_FILE: TYPE_NORMAL counter.bsf FALSE
// Retrieval info: GEN_FILE: TYPE_NORMAL counter_inst.v FALSE
// Retrieval info: GEN_FILE: TYPE_NORMAL counter_bb.v TRUE
// Retrieval info: LIB_FILE: lpm
三、四位计数器仿真与分析
编写测试激励文件:
`timescale 1ns/1ns
`define clock_period 20
module counter_tb;
reg clk;//计数基准时钟
reg cin;//进位输入
wire cout;//进位输出
wire [3:0]q;
counter counter0(
.cin(cin),
.clock(clk),
.cout(cout),
.q(q)
);
initial clk = 1;
always #(`clock_period/2) clk = ~clk;
initial begin
repeat(20)begin
cin = 0;
#(`clock_period*5) cin = 1;
#(`clock_period) cin = 0;
end
#(`clock_period*200);
$stop;
end
endmodule
仿真结果:
可以观察到在仿真结果中出现了毛刺,在这里可以先理解为:由于IP核生成的计数器的电路更接近于真实的电路结构,且已经经过了布局布线的优化,所以会出现毛刺。对于更具体的原因,不需要深究。
当进位输入一个高电平之后,q计数1次;当进位输入10次高电平之后,q计数10次,同时产生一个进位输出高电平。
四、计数器级联与仿真
先上RTL视图:
通过创建顶层文件的方式,调用两次IP核生成的计数器,并实现级联。
其中,Ucounter0实现的是低四位的计数,Ucounter1实现高四位的计数。当低四位计算10次之后,Ucounter0的cout产生一个进位输出,传入给Ucounter1作为进位输入。
在顶层文件中实现级联:
module counter_top(
input cin,
input clk,
output [7:0]q,
output cout
);
wire cout0;
counter Ucounter0(
.cin(cin),
.clock(clk),
.cout(cout0),
.q(q[3:0])
);
counter Ucounter1(
.cin(cout0),
.clock(clk),
.cout(cout),
.q(q[7:4])
);
endmodule
在分析与综合之前,先把counter_top.v设置为顶层。
测试激励文件:
`timescale 1ns/1ns
`define clock_period 20
module counter_top_tb;
reg clk;//计数基准时钟
reg cin;//进位输入
wire cout;//进位输出
wire [7:0]q;
counter_top counter_top_0(
.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
为了便于观察计数效果,可以将计数值改为hex格式:
hex格式:
十六进制(简写为hex或下标16)在数学中是一种逢16进1的进位制。一般用数字0到9和字母A到F表示,其中A ~ F相当于十进制的10~15,这些称作十六进制数字。例如十进制数57,在二进制写作111001,在16进制写作39。
现在的16进制则普遍应用在计算机领域,这是因为将4个位元(Bit)化成单独的16进制数字不太困难。1个字节(Byte)可以表示成2个连续的16进制数字。
观察仿真结果,当计数值到达99,即计数了100次时,cout产生一个高电平脉冲:
🧸结尾
- ❤️ 感谢您的支持和鼓励! 😊🙏
- 📜您可能感兴趣的内容:
- 【stm32开发】stm32+oled最小系统板资料(原理图、PCB、示例代码)【六一】
- 【FPGA零基础学习之旅#5】产生非等占空比信号
- 【Arduino TinyGo】【最新】使用Go语言编写Arduino-环境搭建和点亮LED灯
- 【全网首发开源教程】【Labview机器人仿真与控制】Labview与Solidworks多路支配关系-四足爬行机器人仿真与控制