FPGA常用IP核

前言:

芯片行业中的IP,一般称为IP(Intellectual Property)核,是具有知识产权核的集成电路芯核的总称。说白了就是厂家实现的具有特定功能工具,然后我们可以直接调用,就相当于是函数库吧,如果要定制IP核的化是需要氪金的,对于学习来说,免费的就够用啦。

在FPGA里,我用的是zynq-7000系列,有一个时钟管理器,包括MMCM与PLL,两者功能类似,PLL可以看作是MMCM的的子集,网上说MMCM相对于PLL的优势就是相位可以动态调整。

这篇随笔就写一些最基本的IP的功能用法吧,省得以后自己忘了,高级功能可以看官网文档学习。

一、PLL锁相环

作用:产生高质量,低抖动的时钟信号,可以调频,调相,调占空比的功能。

具体原理不写了先,等以后再看,是一个反馈电路

使用方法:
1 选择IP Catalog,找到自己想要使用的IP核,然后双击需要的IP核,进行配置即可。
image
2 配置界面。
(1)基本设置
image
(2)配置输出
image
其他的没有配置,暂时用不到。
3 生成IP核。
配置好后点击OK,generate即可,生成后的IP在源文件目录中的样子如下:
image

点击源文件下的IP Sources,找到例化模板。
image

然后复制模板就行例化即可。
image

4 使用IP核。
在需要的位置直接例化IP核即可。

module pll(
    input sys_clk,
    output clk_100m,
    output clk_25m,
    output clk_s_90,
    output clk_d_20,
    output locked
);
    
    pll_ip pll_ip_inst
    (
        // Clock out ports
        .clk_100m(clk_100m),     // output clk_100m
        .clk_25m(clk_25m),     // output clk_25m
        .clk_s_90(clk_s_90),     // output clk_s_90
        .clk_d_20(clk_d_20),     // output clk_d_20
        // Status and control signals
        .locked(locked),       // output locked
       // Clock in ports
        .pll_clk(sys_clk)
     );      // input pll_clk
    
endmodule

5 测试IP核。
Testbench代码如下:

`timescale 1ns / 1ns
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2023/08/13 09:19:14
// Design Name: 
// Module Name: tb_pll
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module tb_pll();
    
    reg sys_clk;
    
    wire clk_100m;
    wire clk_25m;
    wire clk_s_90;
    wire clk_d_20;
    wire locked;
    
    initial sys_clk = 1'b1;
    
    always #10 sys_clk = ~sys_clk;
    
    
    pll pll_inst(
        .sys_clk    (sys_clk ),
        .clk_100m   (clk_100m),
        .clk_25m    (clk_25m ),
        .clk_s_90   (clk_s_90),
        .clk_d_20   (clk_d_20),
        .locked     (locked  )
    );
    
endmodule

5 结果。
image
从locked置1开始,就说明时钟信号稳定了,其他四路信号经过测试结果也正确。

二、ROM

作用:只读存储器,存储的信息在制造时由厂家一次写入。只可以读取不可以写入,断电后也不会丢失信息。在这里我们就是厂家,我们可以规定存储的信息。

简单的原理在这

使用方法:
1 选择IP Catalog,搜索block,双击Block Memory Generator,进行配置即可。
2 配置界面
image
其中ECC Options是纠错类型的选择,这里用不到。
(1) 配置端口
image
(2) 初始化ROM,最初的数据。
image
这个coe文件可以用python来写,python代码如下:

file_name = "data.coe"

with open(file_name, 'w') as f:
    f.write('memory_initialization_radix = 10;\n')
    f.write('memory_initialization_vector = \n')
    for i in range(256):
        if i != 255:
            f.write('{},\n'.format(i))
        else:
            f.write('{};'.format(i))

生成的文件内容格式:
image
生成好后放到 工程文件/工程名.srcs/sources_1/ip/rom_8x256,也就是生成的ip核目录下就行,然后在配置界面选择这个文件就ok,选择好后工程目录是这样的,出现了这个东西。
image
3 使用IP核
代码:

module rom
(
    input wire sys_clk,
    input wire [7:0]addr,
    
    output wire [7:0]dout 
);

    rom_8x256 rom_8x256_inst (
      .clka (sys_clk),    // input wire clka
      .addra(addr),  // input wire [7 : 0] addra
      .douta(dout)  // output wire [7 : 0] douta
    );

endmodule

4 测试IP核。

`timescale 1ns / 1ns
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2023/08/15 09:59:28
// Design Name: 
// Module Name: tb_rom
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module tb_rom(

    );
    
    reg sys_clk;
    reg sys_rst_n;
    reg [7:0]addr;
    
    wire [7:0]dout;
    
    initial begin
        sys_clk = 1'b1;
        sys_rst_n <= 1'b0;
        #20
        sys_rst_n <= 1'b1;
    end
    
    always #10 sys_clk = ~sys_clk;
    
    always @ (posedge sys_clk, negedge sys_rst_n)
        if (sys_rst_n == 1'b0)
            addr <= 8'd0;
        else if (addr == 8'd255)
            addr <= 8'd0;
        else
            addr <= addr + 1'b1;
    
    rom rom_inst
    (
        .sys_clk(sys_clk),
        .addr(addr),
        
        .dout(dout) 
    );
    
endmodule

5 波形
image
读取结果与输入地址差一个周期,没有问题。

三、FFT

折腾了好久的东西,今天终于差不多搞明白了。博客参考:
教程
教程代码
上面是博客参考。
因为要注意的东西过于多,不是三言两语能写清楚的,直接看视频,我愿称之为神的视频教程:
Vivado快速傅里叶变换FFT端口篇
Vivado快速傅里叶变换FFT端配置篇
Vivado快速傅里叶变换FFT端细节篇
视频挺长,按顺序耐心看完,收获一定会非常多。

几个比较重要地方,这些都是网上很多教程中忽视的点:
(1)一定要把Output Ordering改为Natural Order,这样输出顺序就是matlab中计算后输出的顺序。
(2)Optional Output Fields一定要把OVFLO打勾,这样使用的时候就会出现一个event_fft_overflow信号,能够监控你的fft ip运算过程是否发生了溢出,如果溢出就要一定要设置s_axis_config_tdata,对运算进行缩放,直到不发生溢出为止,然后输出结果乘相应的缩放倍数就是正确的结果。
(3)不要只关注输入输出,那几个event_...信号,也非常重要,上面视频里也都有讲各个信号的意义,用于监测异常的,可以帮助你快速锁定bug。

四、RAM

作用:随机存储器。

配置:
image
image
代码
示例代码就略了,很简单。

五、加法器Adder、乘法器Multiplier

这两个IP的用法很简单,甚至不用看教程。
image
image
主要的,乘法器的Pipeline Stages设置,加法器的Latency设置,就是延迟多少个时钟输出,一般根据需要设置即可。

代码
tb_adder.v

`timescale 1ns / 1ns
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2023/09/20 22:07:17
// Design Name: 
// Module Name: tb_adder
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module tb_adder();
    reg [31:0] a;
    reg [31:0] b;
    reg sys_clk;
    reg reset;
    wire [31:0] out;
    
    initial begin
        reset = 1'b1;
        #20
        a = 31'd6;
        b = 31'd0;
        sys_clk = 1'b0;
        reset = 1'b0;
    end
    
    always #10 sys_clk = ~sys_clk;
    
    always @ (posedge sys_clk, posedge reset) begin
        if (reset == 1'b1)
            b <= 31'd0;
        else
            b <= b + 31'd1;
    end
    
    adder adder_inst (
      .A(a),        // input wire [31 : 0] A
      .B(b),        // input wire [31 : 0] B
      .CLK(sys_clk),    // input wire CLK
      .SCLR(reset),  // input wire SCLR
      .S(out)        // output wire [31 : 0] S
    );
endmodule

tb_multiplier.v

`timescale 1ns / 1ns
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2023/09/20 21:49:42
// Design Name: 
// Module Name: tb_multiplier
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module tb_multiplier();
    reg [15:0] a;
    reg [15:0] b;
    reg sys_clk;
    reg reset;
    wire [15:0] out;
    
    initial begin
        reset = 1'b1;
        #20
        a = 15'd6;
        b = 15'd0;
        sys_clk = 1'b0;
        reset = 1'b0;
    end
    
    always #10 sys_clk = ~sys_clk;
    
    always @ (posedge sys_clk, posedge reset) begin
        if (reset == 1'b1)
            b <= 15'd0;
        else
            b <= b + 15'd1;
    end
    
    multiplier multiplier_inst (
      .CLK(sys_clk),    // input wire CLK
      .A(a),        // input wire [15 : 0] A
      .B(b),        // input wire [15 : 0] B
      .SCLR(reset),  // input wire SCLR
      .P(out)        // output wire [31 : 0] P
    );
    
endmodule
posted @ 2023-08-13 10:38  Xxaj5  阅读(1131)  评论(0编辑  收藏  举报