草庐IT

Quartus基本IP核调用及仿真

机智的橙子 2023-08-07 原文

文章目录

一.PLL

PLL介绍

PLL全称Phase Locked Loop,也就是锁相环,是一种反馈控制电路。PLL对时钟网络进行系统级的时钟管理和偏移控制,具有时钟倍频、分频、相位偏移和可编程占空比的功能。PLL一般由模拟电路所实现。

PLL是FPGA重要的资源,不同FPGA的PLL 是不一样。以我们开发板的Cyclone IV为例,它有两个PLL,每个PLL可以提供5路输出。
PLL 的时钟输入可以是PLL 所在的 Bank 的时钟输入管脚或者其他 PLL 的输出,FPGA 内部产生的信号不能驱动PLL。Cyclone IV PLL 产生的时钟可以为单端时钟信号或差分时钟信号, 可以通过GCLK 网络直接驱动 FPGA 外部的 IO 口。

PLL的IP核调用

打开Quartus软件,新建一个项目后(命名为test_IP),在界面的最右侧,可以看见一个IP Catalog的栏目,在这里有很多的IP核可以供我们选择使用
我们在这里需要选择PLL

资源比较多,可以在搜索栏搜索,双击选择ALTPLL后出现如下弹窗

点击…选择文件保存路径,这里使用我们创建工程文件夹里面的ip文件夹,将文件命名为pll.v,点击OK

我使用的是Cyclone IV系列的EP4CE6F17C8,只有一个50MHZ的晶振,时钟频率选择50MHZ就可以了,选择正常模式就可以了

选择创建一个’areset’输入异步重置锁相环

这一步默认就好了

Next

Next

原时钟频率为50MHZ,这里选择100MHZ,相当于把时钟倍频,占空比50%


第二个时钟,25MHZ,选择分频,且相位偏移90°,占空比50%

第三个时钟,5MHZ,占空比为25%

第四个时钟,先分频再倍频,75MHZ,占空比50%
这里只使用了4个时钟,第五个时钟不勾选

Next

选择生成pll_inst.v和pll_bb.v文件,点击Finish
现在PLL的相关资源已经添加到项目中了,在Quartus软件左侧选择IP Components就可以看见我们添加的pll了(其他IP核在后面介绍)

PLL仿真

我们可以自己编写例化
例如我们编写test_IP.v文件例化PLL模块

module test_IP(
    input           clk     ,//时钟信号
    input           rst_n   ,//上电复位低有效
    output          c0      ,
    output          c1      ,
    output          c2      ,
    output          c3      ,
    output          locked  ,
);
// //PLL
    pll	pll_inst (
    	.areset ( ~rst_n ),//IP复位高有效
    	.inclk0 ( clk    ),//输入时钟
    	.c0     ( c0     ),//输出时钟
    	.c1     ( c1     ),//输出时钟
    	.c2     ( c2     ),//输出时钟
    	.c3     ( c3     ),//输出时钟
    	.locked ( locked ) //时钟输出锁--锁定不稳定时钟输出
    	);
endmodule

再编写一个测试文件

`timescale 1ns/1ps
module test_tb();

    reg             clk         ;
    reg             rst_n       ;
    wire            c0          ;
    wire            c1          ;
    wire            c2          ;
    wire            c3          ;
    
//例化要仿真的文件
test_IP u_test_IP(
    .clk        (clk        ),//时钟信号
    .rst_n      (rst_n      ),//上电复位低有效
    .c0         (c0         ),
    .c1         (c1         ),
    .c2         (c2         ),
    .c3         (c3         ),
    .locked     (locked     )
);

always  #10     clk = ~clk;//产生50M仿真时钟

integer i = 0,j = 0;//用于产生地址,写入数据

initial begin
    clk = 1'b1;
    rst_n = 1'b1;
    #200.1;
    rst_n = 1'b0;//主动产生上电复位
    #200;
    rst_n = 1'b1;

    #20000;
    $stop;
end

endmodule

编译仿真:

二.RAM

RAM介绍

RAM的英文全称是Random Access Memory,即随机存取存储器,它可以随时把数据写入任一指定地址的存储单元,也可以随时从任一指定地址中读出数据。其读写速度是由时钟频率决定的。RAM主要用来存放程序及程序执行过程中产生的中间数据、运算结果等。其特点适合双向交换数据。

其他类型的寄存器:

  • ROM(Read-Only Memory):只读存储器,系统上电后数据就被写入ROM,运行过程中智能从ROM中读取数据,而不能改变ROM中的数值。
  • FIFO(不寻址,操作简单)适合数据缓冲或跨时钟域数据同步处理;

总结:RAM、ROM、FIFO都是FPGA提供的存储单元

RAM的IP核调用(单时钟)

同样在IP Catalog中搜索RAM

双击选择RAM:1-PORT,同样保存在ip文件夹下,命名为RAM_1port.v

选择数据位大小,以及数据深度


Next

Next

同样勾选RAM_1port_inst.v和RAM_1port_bb.v文件

RAM仿真(单时钟)

同样,先例化
test_IP.v

module test_IP(
    input           clk     ,//时钟信号
    input           rst_n   ,//上电复位低有效
    input           rden    ,
    input           wren    ,
    input   [7:0]   address ,
    input   [7:0]   data    ,

    output  [7:0]   q
);

//RAM_1port
    RAM_1port	RAM_1port_inst (
        .aclr       ( ~rst_n    ),
     	.address    ( address   ),
     	.clock      ( clk       ),
     	.data       ( data      ),
     	.rden       ( rden      ),
     	.wren       ( wren      ),
     	.q          ( q         )
     	);
endmodule

编写测试文件test_tb.v

`timescale 1ns/1ps
module test_tb();

    reg             clk         ;
    reg             rst_n       ;
    reg             rden        ;
    reg             wren        ;
    reg    [7:0]    address     ;
    reg    [7:0]    data        ;
    wire   [7:0]    q           ;
    
//例化要仿真的文件
test_IP u_test_IP(
    .clk        (clk        ),//时钟信号
    .rst_n      (rst_n      ),//上电复位低有效
    .rden       (rden       ),
    .wren       (wren       ),
    .address    (address    ),
    .data       (data       ),

    .q          (q          )
);

always  #10     clk = ~clk;//产生50M仿真时钟

integer i = 0,j = 0;//用于产生地址,写入数据

initial begin
    clk = 1'b1;
    rst_n = 1'b1;
    #200.1;
    rst_n = 1'b0;//主动产生上电复位
//RAM_1PORT
    wren = 1'b0;//复位有效,赋初值
    rden = 1'b0;
    data = 0;
    address = 0;
    #200;
    rst_n = 1'b1;
    #200;
    //wren  50M
    for(i=0;i<256;i=i+1)begin
        wren = 1'b1;//高电平有效
        address = i;
        data = i+1;
        #20;
    end
    wren = 1'b0;//写完拉低
    #100;
    //rden  100M
    for(j=0;j<256;j=j+1)begin
        rden = 1'b1;
        address = j;
        #20;
    end
    rden = 1'b0;//读完拉低
    #200;
    $stop;
end

endmodule

编译仿真:

RAM的IP核调用(双时钟)

选择RAM:2-PORT


选择一个读模块一个写模块

默认就好了

选择读写时钟分开,也就是读写是两个单独的时钟

读出数据设置为q,同样选择复位清零

Next

RAM仿真(双时钟)

例化

module test_IP(
    input           clk     ,//时钟信号
    input           rst_n   ,//上电复位低有效
    input   [7:0]   data        ,
    input   [7:0]   rdaddress   ,
    input           rden        ,
    input   [7:0]   wraddress   ,
    input           wrclock     ,
    input           wren        ,
    output  [7:0]   q

);

// //RAM_2port
    RAM_2port	RAM_2port_inst (
    .data       ( data      ),
    .rd_aclr    ( ~rst_n    ),
    .rdaddress  ( rdaddress ),
    .rdclock    ( clk       ),
    .rden       ( rden      ),
    .wraddress  ( wraddress ),
    .wrclock    ( wrclock   ),
    .wren       ( wren      ),
    .q          ( q         )
    );

endmodule

测试文件:

`timescale 1ns/1ps
module test_tb();

    reg             clk         ;
    reg             rst_n       ;
    reg     [7:0]   data        ;
    reg     [7:0]   rdaddress   ;
    reg             rden        ;
    reg     [7:0]   wraddress   ;
    reg             wrclock     ;
    reg             wren        ;
    wire    [7:0]   q           ;

//例化要仿真的文件
test_IP u_test_IP(
    .clk        (clk        ),//时钟信号
    .rst_n      (rst_n      ),//上电复位低有效
    .data        (data      ),
    .rdaddress   (rdaddress ),
    .rden        (rden      ),
    .wraddress   (wraddress ),
    .wrclock     (clk       ),
    .wren        (wren      ),
    .q           (q         )
);

always  #10     clk = ~clk;//产生50M仿真时钟

integer i = 0,j = 0;//用于产生地址,写入数据

initial begin
    clk = 1'b1;
    rst_n = 1'b1;
    #200.1;
    rst_n = 1'b0;//主动产生上电复位
    wren = 1'b0;//复位有效,赋初值
    rden = 1'b0;
    rdaddress = 0;
    wraddress = 0;
    data = 0;
    #200;
    rst_n = 1'b1;
    #200;
    //wren  50M
    for(i=0;i<256;i=i+1)begin
        wren = 1'b1;//高电平有效
        wraddress = i;
        data = i+1;
        #20;
    end
    wren = 1'b0;//写完拉低
    #100;
    //rden  100M
    for(j=0;j<256;j=j+1)begin
        rden = 1'b1;
        rdaddress = j;
        #20;
    end
    rden = 1'b0;//读完拉低
    #200;
    $stop;
end

endmodule

编译仿真:

三.FIFO

FIFO介绍

FIFO的英文全称是First In First Out,即先进先出。FPGA使用的FIFO一般指的是对数据的存储具有先进先出特性的一个缓存器,常被用于数据的缓存或者高速异步数据的交互,也即所谓的跨时钟域信号传递。
它与FPGA内部的RAM和ROM的区别是没有外部读写地址线,采取顺序写入数据,顺序读出数据的方式,使用起来简单方便,由此带来的缺点就是不能像RAM和ROM那样可以由地址线决定读取或写入某个指定的地址。

FIFO的IP核调用(读写共用时钟)



选择读写使用同一个时钟

勾选如上信号

Next

Next

FIFO仿真(读写共用时钟)

例化:

module test_IP(
    input           clk     ,//时钟信号
    input           rst_n   ,//上电复位低有效
    input   [7:0]   data    ,
    input           rdreq   ,
    input           wrreq   ,

    output          empty   ,
    output          full    ,
    output  [7:0]   q       ,
    output  [7:0]   usedw   

);

// //FIFO
    fifo	fifo_inst (
    .aclr   ( ~rst_n    ),
    .clock  ( clk       ),
    .data   ( data      ),
    .rdreq  ( rdreq     ),
    .wrreq  ( wrreq     ),
    .empty  ( empty     ),
    .full   ( full      ),
    .q      ( q         ),
    .usedw  ( usedw     )
    );
endmodule

测试文件:

`timescale 1ns/1ps
module test_tb();

    reg             clk         ;
    reg             rst_n       ;
    reg             wrreq       ;
    reg             rdreq       ;
    reg     [7:0]   data        ;
    wire    [7:0]   q           ;
    wire            empty       ;
    wire            full        ;
    wire            usedw       ;

//例化要仿真的文件
test_IP u_test_IP(
    .clk        (clk        ),//时钟信号
    .rst_n      (rst_n      ),//上电复位低有效
    .data       (data   ),
    .rdreq      (rdreq  ),
    .wrreq      (wrreq  ),
    .empty      (empty  ),    
    .full       (full   ),    
    .q          (q      ),         
    .usedw      (usedw  ) 
);

always  #10     clk = ~clk;//产生50M仿真时钟

integer i = 0,j = 0;//用于产生地址,写入数据

initial begin
    clk = 1'b1;
    rst_n = 1'b1;
    #200.1;
    rst_n = 1'b0;//主动产生上电复位
    rdreq = 1'b0;
    wrreq = 1'b0;
    data = 0;
    #200;
    rst_n = 1'b1;
    #200;

    //wrreq  50M
    for(i=0;i<256;i=i+1)begin
        wrreq = 1'b1;//高电平有效
        data = {$random};
        #20;
    end
    wrreq = 1'b0;//写完拉低
    #100;

    //rdreq  100M
    for(j=0;j<256;j=j+1)begin
        rdreq = 1'b1;
        #20;
    end
    rdreq = 1'b0;
    #200;
    $stop;
end

endmodule

编译仿真:

FIFO的IP核调用(读50MHZ时钟,写时钟100MHZ时钟)

同样选择上面的FIFO

选择读写时钟分开


勾选以上信号


FIFO仿真(读50MHZ时钟,写时钟100MHZ时钟)

这里要使用100MHZ时钟,就需要使用上面的PLL模块
例化:

module test_IP(
    input           clk     ,//时钟信号
    input           rst_n   ,//上电复位低有效

PLL
    output          c0      ,
    output          c1      ,
    output          c2      ,
    output          c3      ,
    output          locked  ,
    
//FIFO2
    input   [7:0]     data     ,
    input             rdreq    ,
    input             wrreq    ,
    output  [7:0]     q        ,
    output            rdempty  ,
    output            rdfull   ,
    output  [7:0]     rdusedw  ,
    output            wrempty  ,
    output            wrfull   ,
    output  [7:0]     wrusedw  

);

// //PLL
    pll	pll_inst (
    	.areset ( ~rst_n ),//IP复位高有效
    	.inclk0 ( clk    ),//输入时钟
    	.c0     ( c0     ),//输出时钟
    	.c1     ( c1     ),//输出时钟
    	.c2     ( c2     ),//输出时钟
    	.c3     ( c3     ),//输出时钟
    	.locked ( locked ) //时钟输出锁--锁定不稳定时钟输出
    	);
//FIFO2
    fifo2	fifo2_inst (
    	.aclr       ( ~rst_n    ),
    	.data       ( data      ),
    	.rdclk      ( clk       ),//50M
    	.rdreq      ( rdreq     ),
    	.wrclk      ( c0        ),//100M
    	.wrreq      ( wrreq     ),
    	.q          ( q         ),
    	.rdempty    ( rdempty   ),
    	.rdfull     ( rdfull    ),
    	.rdusedw    ( rdusedw   ),
    	.wrempty    ( wrempty   ),
    	.wrfull     ( wrfull    ),
    	.wrusedw    ( wrusedw   )
    	);
endmodule

仿真文件:

`timescale 1ns/1ps
module test_tb();

    reg             clk         ;
    reg             rst_n       ;

// //PLL
    wire            c0          ;
    wire            c1          ;
    wire            c2          ;
    wire            c3          ;

//FIFO2
    reg      [7:0]     data     ;
    reg                rdreq    ;
    reg                wrreq    ;
    wire     [7:0]     q        ;
    wire               rdempty  ;
    wire               rdfull   ;
    wire     [7:0]     rdusedw  ;
    wire               wrempty  ;
    wire               wrfull   ;
    wire     [7:0]     wrusedw  ;

//例化要仿真的文件
test_IP u_test_IP(
    .clk        (clk        ),//时钟信号
    .rst_n      (rst_n      ),//上电复位低有效

PLL   
    .c0         (c0         ),
    .c1         (c1         ),
    .c2         (c2         ),
    .c3         (c3         ),
    .locked     (locked     ),

//FIFO2
    .data       (data   ),
    .rdreq      (rdreq  ),
    .wrreq      (wrreq  ),
    .q          (q      ),
    .rdempty    (rdempty),
    .rdfull     (rdfull ),
    .rdusedw    (rdusedw),
    .wrempty    (wrempty),
    .wrfull     (wrfull ),
    .wrusedw    (wrusedw)

);

always  #10     clk = ~clk;//产生50M仿真时钟

integer i = 0,j = 0;//用于产生地址,写入数据

initial begin
    clk = 1'b1;
    rst_n = 1'b1;
    #200.1;
    rst_n = 1'b0;//主动产生上电复位
    
//FIFO2
    rdreq = 1'b0;
    wrreq = 1'b0;
    data = 0;
    #200;
    rst_n = 1'b1;
    #200;

    //wrreq  50M
    for(i=0;i<256;i=i+1)begin
        wrreq = {$random}%2;//高电平有效
        data = {$random};
        #20;
    end
    wrreq = 1'b0;//写完拉低
    #100;
    //rdreq  100M
    for(j=0;j<256;j=j+1)begin
        rdreq = {$random}%2;
        #20;
    end
    rdreq = 1'b0;
    #200;
    $stop;
end

endmodule

编译仿真:

有关Quartus基本IP核调用及仿真的更多相关文章

  1. 使用 ACL 调用 upload_file 时出现 Ruby S3 "Access Denied"错误 - 2

    我正在尝试编写一个将文件上传到AWS并公开该文件的Ruby脚本。我做了以下事情:s3=Aws::S3::Resource.new(credentials:Aws::Credentials.new(KEY,SECRET),region:'us-west-2')obj=s3.bucket('stg-db').object('key')obj.upload_file(filename)这似乎工作正常,除了该文件不是公开可用的,而且我无法获得它的公共(public)URL。但是当我登录到S3时,我可以正常查看我的文件。为了使其公开可用,我将最后一行更改为obj.upload_file(file

  2. ruby - 从 Ruby 中的主机名获取 IP 地址 - 2

    我有一个存储主机名的Ruby数组server_names。如果我打印出来,它看起来像这样:["hostname.abc.com","hostname2.abc.com","hostname3.abc.com"]相当标准。我想要做的是获取这些服务器的IP(可能将它们存储在另一个变量中)。看起来IPSocket类可以做到这一点,但我不确定如何使用IPSocket类遍历它。如果它只是尝试像这样打印出IP:server_names.eachdo|name|IPSocket::getaddress(name)pnameend它提示我没有提供服务器名称。这是语法问题还是我没有正确使用类?输出:ge

  3. c# - 如何在 ruby​​ 中调用 C# dll? - 2

    如何在ruby​​中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL

  4. java - 从 JRuby 调用 Java 类的问题 - 2

    我正在尝试使用boilerpipe来自JRuby。我看过guide从JRuby调用Java,并成功地将它与另一个Java包一起使用,但无法弄清楚为什么同样的东西不能用于boilerpipe。我正在尝试基本上从JRuby中执行与此Java等效的操作:URLurl=newURL("http://www.example.com/some-location/index.html");Stringtext=ArticleExtractor.INSTANCE.getText(url);在JRuby中试过这个:require'java'url=java.net.URL.new("http://www

  5. ruby - 调用其他方法的 TDD 方法的正确方法 - 2

    我需要一些关于TDD概念的帮助。假设我有以下代码defexecute(command)casecommandwhen"c"create_new_characterwhen"i"display_inventoryendenddefcreate_new_character#dostufftocreatenewcharacterenddefdisplay_inventory#dostufftodisplayinventoryend现在我不确定要为什么编写单元测试。如果我为execute方法编写单元测试,那不是几乎涵盖了我对create_new_character和display_invent

  6. 【鸿蒙应用开发系列】- 获取系统设备信息以及版本API兼容调用方式 - 2

    在应用开发中,有时候我们需要获取系统的设备信息,用于数据上报和行为分析。那在鸿蒙系统中,我们应该怎么去获取设备的系统信息呢,比如说获取手机的系统版本号、手机的制造商、手机型号等数据。1、获取方式这里分为两种情况,一种是设备信息的获取,一种是系统信息的获取。1.1、获取设备信息获取设备信息,鸿蒙的SDK包为我们提供了DeviceInfo类,通过该类的一些静态方法,可以获取设备信息,DeviceInfo类的包路径为:ohos.system.DeviceInfo.具体的方法如下:ModifierandTypeMethodDescriptionstatic StringgetAbiList​()Obt

  7. Unity 热更新技术 | (三) Lua语言基本介绍及下载安装 - 2

    ?博客主页:https://xiaoy.blog.csdn.net?本文由呆呆敲代码的小Y原创,首发于CSDN??学习专栏推荐:Unity系统学习专栏?游戏制作专栏推荐:游戏制作?Unity实战100例专栏推荐:Unity实战100例教程?欢迎点赞?收藏⭐留言?如有错误敬请指正!?未来很长,值得我们全力奔赴更美好的生活✨------------------❤️分割线❤️-------------------------

  8. C51单片机——实现用独立按键控制LED亮灭(调用函数篇) - 2

    说在前面这部分我本来是合为一篇来写的,因为目的是一样的,都是通过独立按键来控制LED闪灭本质上是起到开关的作用,即调用函数和中断函数。但是写一篇太累了,我还是决定分为两篇写,这篇是调用函数篇。在本篇中你主要看到这些东西!!!1.调用函数的方法(主要讲语法和格式)2.独立按键如何控制LED亮灭3.程序中的一些细节(软件消抖等)1.调用函数的方法思路还是比较清晰地,就是通过按下按键来控制LED闪灭,即每按下一次,LED取反一次。重要的是,把按键与LED联系在一起。我打算用K1来作为开关,看了一下开发板原理图,K1连接的是单片机的P31口,当按下K1时,P31是与GND相连的,也就是说,当我按下去时

  9. 计算机毕业设计ssm+vue基本微信小程序的小学生兴趣延时班预约小程序 - 2

    项目介绍随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱小学生兴趣延时班预约小程序的设计与开发被用户普遍使用,为方便用户能够可以随时进行小学生兴趣延时班预约小程序的设计与开发的数据信息管理,特开发了小程序的设计与开发的管理系统。小学生兴趣延时班预约小程序的设计与开发的开发利用现有的成熟技术参考,以源代码为模板,分析功能调整与小学生兴趣延时班预约小程序的设计与开发的实际需求相结合,讨论了小学生兴趣延时班预约小程序的设计与开发的使用。开发环境开发说明:前端使用微信微信小程序开发工具:后端使用ssm:VU

  10. ruby - 如何找到调用当前方法的方法 - 2

    如何找到调用此方法的位置?defto_xml(options={})binding.pryoptions=options.to_hifoptions&&options.respond_to?(:to_h)serializable_hash(options).to_xml(options)end 最佳答案 键入caller。这将返回当前调用堆栈。文档:Kernel#caller.例子[0]%rspecspec10/16|===================================================62=====

随机推荐