草庐IT

vivado IP核:ILA、时钟、RAM、FIFO

ICtoddler_LY 2024-03-22 原文

ILA

vivado工具集成了逻辑分析仪,ILA IP核用于替换外部的逻辑分析仪,添加探针来监控内部信号波形变化。

1)IP Catalog

2)搜索栏可搜索IP核,如创建FIFO、RAM等。

3)搜索并选择。

4)设置ILA各项参数。 

 

5) 设置好IP核参数后点ok。

6)打开ila_0.evo。

7) 复制ila例化模板。

8)在设计文件中将IP核例化并连接,再生成比特流。

9)将比特流下载到板子中,点运行即可查看探针捕捉到的波形。

时钟

时钟IP核

RAM

Xilinx A7系列FPGA有140片block RAM每片内存为36k(bit),共4.9M。

双端口RAM可以写可以读(分别有读写时钟),但是要规定读写优先级。

单端口:只有一个端口,读写数据不能同时进行,共用数据通道。

伪双端口:拥有两个数据通道,一个用来写一个用来读。(常见)

真双端口:拥有两个数据通道,两个都可用来写/读。

创建RAM IP核

创建RAM IP核的主设计代码ip_ram.v(例化了ram_rw 模块和ram IP 核blk_mem_gen_0):

blk_mem_gen_0来自IP核的.veo文件,直接例化即可。代码结构图如下:

`timescale 1ns / 1ps
module ip_ram(
input sys_clk,
input sys_rst_n
);
    wire ram_en;
    wire rw;
    wire [4:0] ram_addr;
    wire [7:0] ram_wr_data;
    wire [7:0] douta;
    ram_rw ram_rw_u(    
        .clk(sys_clk),       
        .rst_n(sys_rst_n),     
        .ram_en(ram_en),    
        .rw(rw),        
        .ram_addr(ram_addr),  
        .ram_wr_data(ram_wr_data)
    );
    blk_mem_gen_0 your_instance_name (
        .clka(sys_clk),	// input wire clka
        .ena(ram_en),		// input wire ena
        .wea(rw),		// input wire [0 : 0] wea
        .addra(ram_addr),	// input wire [4 : 0] addra
        .dina(ram_wr_data),	// input wire [7 : 0] dina
        .douta(douta)  	// output wire [7 : 0] douta
    );
endmodule

ram_rw.v作为读写模块驱动IP核,负责产生对ram IP核读/写所需的所有数据总线、地址总线以及控制信号,同时从ram IP读出的数据也被送进ram_rw 模块。

`timescale 1ns / 1ps
module ram_rw(
    input               clk,
    input               rst_n,
    output  reg         ram_en,
    output  reg         rw,
    output  reg[4:0]    ram_addr,
    output  reg[7:0]    ram_wr_data
    );
    reg [5:0] rw_cnt;   //define a counter,write in [0:31],read in [32:63].
    
    always @ (posedge clk or negedge rst_n) begin
        if(~rst_n) begin
            ram_en <= 1'b0;
        end
        else begin
            ram_en <= 1'b1;
        end
    end
    always @ (posedge clk or negedge rst_n) begin
        if(~rst_n)
            rw_cnt <= 6'd0;
        else if(rw == 6'd63)
            rw_cnt <= 6'd0;
        else
            rw_cnt <= rw_cnt +6'd1;
    end
    always @ (posedge clk or negedge rst_n) begin
        if(~rst_n)
            ram_wr_data <= 8'd0;
        else if((rw_cnt <= 6'd31) && ram_en)// rw_cnt:0-31写操作。
            ram_wr_data <= ram_wr_data + 8'd1;
        else
            ram_wr_data <= ram_wr_data;
    end
//读写选择信号
always @(posedge clk or negedge rst_n) begin
        if(~rst_n)
            rw <= 1'b1;
        else if(rw_cnt <= 6'd31)//rw_cnt:0-31写操作
            rw <= 1'b1;
        else
            rw <= 1'b0;
    end
    always @(posedge clk or negedge rst_n) begin
        if(~rst_n)
            ram_addr <= 5'd0;
        else
            ram_addr <= rw_cnt[4:0];
    end
endmodule

FIFO

搭建FIFO一般用Block Ram或Dram,Bram允许读写位宽不同。FIFO与FPGA内部RAM相比无外部读写地址线,采取顺序写入/读出数据方式。不能像RAM那样可由地址线决定读/写某个指定的地址。

1)创建工程后打开.v设计文件,并通过IP Catalog搜索FIFO,选择FIFO Generator。

2)要选择构成FIFO的适当RAM类型。 

 FIFO写操作

`timescale 1ns / 1ps
//write->read->empty->write......
module fifo_wr(
    input       clk,
    input       rst_n,
    input       almost_empty,
    input       almost_full,
    
    output reg  fifo_wr_en,
    output reg  [7:0] fifo_wr_data
    );
    reg almost_empty_d0;
    reg almost_empty_syn;
    reg [3:0] dly_cnt;
    reg [1:0] state;
    wire syn;
assign syn = ~almost_empty_syn & almost_empty_d0;
// almost_empty拉高后的下一个周期syn拉高。
    always @ (posedge clk or negedge rst_n) begin
        if(~rst_n) begin
            almost_empty_d0 <= 1'b0;
            almost_empty_syn <= 1'b0;
        end
        else begin
            almost_empty_d0 <= almost_empty;
// almost_empty延迟一个上升沿赋值给almost_empty_d0
            almost_empty_syn <= almost_empty_d0;            
// almost_empty_d0延迟一个上升沿赋值给almost_empty_syn
        end
end
    always @ (posedge clk or negedge rst_n) begin
        if(~rst_n) begin
            fifo_wr_en <= 1'b0;
            fifo_wr_data <= 8'd0;
            state <= 2'd0;
            dly_cnt <= 4'b0;
//FIFO IP核不能立即就写入,所以要有一个延时,一般10拍就够。
        end
        else begin
//构造一个状态机,state有3个状态。
            case(state)
//状态0:如果syn拉高,说明FIFO即将空了,该写了,于是跳到状态1;syn不拉高,则FIFO还未空,则不写。
                2'd0:begin
                    if(syn) state <= 2'd1;
                    else state <= state;
                end
//状态1:dly_cnt计满10个数后开始写。dly_cnt<10时一直+1;dly_cnt到10后,dly_cnt清零,跳到状态2,写使能fifo_wr_en拉高。
                2'd1:begin
                    if(dly_cnt == 4'd10) begin
                        dly_cnt <= 4'b0;
                        state <= 2'd2;
                        fifo_wr_en <= 1'b1;
                    end
                    else begin
                        dly_cnt <= dly_cnt +1'b1;
                    end
                end
//状态2:真正开始写了,FIFO一直写。如果写满almost_full拉高:写使能fifo_wr_en拉低,写数据fifo_wr_data归零,转向状态0。如果没写满:写使能继续拉高,写数据+1。(这里写数据根据项目自己确定写入的内容,可以是采集数据)
                2'd2:begin
                    if(almost_full) begin
                        fifo_wr_en <= 1'b0;
                        fifo_wr_data <= 8'd0;
                        state <= 2'd0;
                    end
                    else begin
                        fifo_wr_en <= 1'b1;
                        fifo_wr_data <= fifo_wr_data + 1'b1;
                    end
                end
                default:state <= 2'd0;
            endcase
        end
    end
endmodule

FIFO读操作

`timescale 1ns / 1ps
//write->read->empty->write......
module fifo_rd(
    input       clk,
    input       rst_n,
    input       almost_empty,
    input       almost_full,
    
    output reg  fifo_rd_en
    );
    reg almost_full_d0;
    reg almost_full_syn;
    reg [3:0] dly_cnt;
    reg [1:0] state;
    wire syn;
    assign syn = ~almost_full_syn & almost_full_d0;
    always @ (posedge clk or negedge rst_n) begin
        if(~rst_n) begin
            almost_full_d0 <= 1'b0;
            almost_full_syn <= 1'b0;
        end
        else begin
            almost_full_d0 <= almost_full;
            almost_full_syn <= almost_full_d0;        
        end
    end
    always @ (posedge clk or negedge rst_n) begin
        if(~rst_n) begin
            fifo_rd_en <= 1'b0;
            state <= 2'd0;
            dly_cnt <= 4'b0;
        end
        else begin
            case(state)
                2'd0:begin
                    if(syn) state <= 2'd1;
                    else state <= state;
                end
                2'd1:begin
                    if(dly_cnt == 4'd10) begin
                        dly_cnt <= 4'b0;
                        state <= 2'd2;
                    end
                    else begin
                        dly_cnt <= dly_cnt +1'b1;
                    end
                end
                2'd2:begin
                    if(almost_empty) begin
                        fifo_rd_en <= 1'b0;
                        state <= 2'd0;
                    end
                    else begin
                        fifo_rd_en <= 1'b1;
                    end
                end
                default:state <= 2'd0;
            endcase
        end
    end
endmodule

完成管脚约束(IO Planning直接操作)

由于FIFO的读写操作无法通过板子看出来,所以添加ila探针:

ila_0 your_instance_name (
	.clk(sys_clk), // input wire clk
	.probe0(fifo_wr_en), // input wire [0:0]  probe0  
	.probe1(fifo_rd_en), // input wire [0:0]  probe1 
	.probe2(empty), // input wire [0:0]  probe2 
	.probe3(almost_empty), // input wire [0:0]  probe3 
	.probe4(fifo_wr_data), // input wire [7:0]  probe4 
	.probe5(dout), // input wire [7:0]  probe5 
	.probe6(rd_data_count), // input wire [7:0]  probe6 
	.probe7(wr_data_count), // input wire [7:0]  probe7 
	.probe8(full), // input wire [0:0]  probe8 
	.probe9(almost_full) // input wire [0:0]  probe9
);

有关vivado IP核:ILA、时钟、RAM、FIFO的更多相关文章

  1. FPGA 之 时钟,时钟域, 以及复位系统的设计 - 2

    FPGA时钟和时钟域时钟树所谓时钟树为FPGA内部资源,分:全局时钟树,区域时钟树,IO时钟树原则上优先使用全局时钟树,在GT接口上使用IO时钟树,一般工具也会对GT时钟加以限制;时钟树使用方式正确的物理连接FPGA会由物理管脚专门用于全局时钟设置,通过查询数据手册可以在PCB设计阶段进行确认,当外部时钟接入此管脚时,工具会自动占有全局时钟树资源,当接入普通信号时不会分配时钟树资源;恰当的代码描述原语的使用,即BUFG的使用,可以将PLL的输出等内部时钟进行全局时钟资源的分配;IO时钟资源需要参考相应接口手册,以ultrascale的GTH为例,其JESD204的时钟方案针对不同的子类会由不同

  2. FIFO实战学习-同步FIFO/异步FIFO-格雷码 - 2

    目录FIFO一.自定义同步FIFO1.1代码设计1.2Testbech1.3行为仿真***学习位宽计算函数$clog2()***$clog2()系统函数使用,可以不关注***分布式资源或者BLOCKBRAM二.异步FIFO2.1在FIFO判满的时候有两种方式:2.2异步FIFO为什么要使用格雷码2.2.1介绍格雷码2.2.2格雷码在异步FIFO中的应用2.2.2格雷码判满2.4二进制与格雷码之间的转换2.4.1二进制码转换为格雷码的方法2.4.2格雷码转换为二进制码的方法2.3实现框图2.5实现及仿真代码2.6仿真图验证2.7结论FIFO  这篇更多的是记录FIFO学习,参考了众多优秀的文章,

  3. ruby - 使用 Ruby 作为脚本语言,使用 4gb RAM 的计算机对 30gb 的字符串进行排序的最佳方法是什么? - 2

    您好,我将其视为一个面试问题,并认为这是一个有趣的问题,但我不确定答案。最好的方法是什么? 最佳答案 假设*nix:system("sortoutput_file")“排序”可以使用临时文件来处理大于内存的输入文件。如果需要,它有开关来调整主内存的数量和它将使用的临时文件的数量。如果不是*nix,或者面试官因为斜着回答皱眉,那我就编码一个外部mergesort.请参阅@psyho的回答以获得外部排序算法的良好总结。 关于ruby-使用Ruby作为脚本语言,使用4gbRAM的计算机对30g

  4. 基于51单片机、DS1302时钟模块的电子闹钟设计 - 2

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档文章目录一、设计原理1.DS1302介绍2.闹钟音乐播放原理二、程序设计1.DS1302.h2.ds1302.c3.music.h4.main.c三、电路图四、运行结果1.proteus仿真2.开发板实验五、总结六、附件提示:以下是本篇文章正文内容,下面案例可供参考一、设计原理1.DS1302介绍DS1302是美国DALLAS公司推出的一种高性能、低功耗、带RAM的实时时钟电路,它可以对年、月、日、周、时、分、秒进行计时,具有闰年补偿功能,工作电压为2.0V~5.5V。该芯片采用普通32.768kHz晶振,DS1302工作时功耗很

  5. ESP32学习笔记(七) 复位和时钟 - 2

    ESP32学习笔记(七)复位和时钟目录:ESP32学习笔记(一)芯片型号介绍ESP32学习笔记(二)开发环境搭建VSCode+platformioESP32学习笔记(三)硬件资源介绍ESP32学习笔记(四)串口通信ESP32学习笔记(五)外部中断ESP32学习笔记(六)定时器ESP32学习笔记(七)复位和时钟1.复位2.系统时钟2.1时钟树2.2时钟源从时钟树可以看出时钟源共七种ESP32的时钟源分别来自外部晶振、内部PLL或振荡电路具体地说,这些时钟源为:2.2.1快速时钟PLL_CLK320MHz或480MHz内部PLL时钟XTL_CLK2~40MHz外部晶振时钟,模组板载的是40MHz晶

  6. ruby-on-rails - Unicorn 内存使用几乎填满了所有 RAM - 2

    这里基本上有3个问题:1)Unicorn似乎在稳定地填满所有RAM,导致我手动移除worker。2)Unicorn似乎出于某种原因正在产生更多的worker,尽管我指定了固定数量的worker(其中7个)。这在一定程度上导致了RAM堆积,这也导致我手动删除工作人员。3)零停机部署在我的案例中是不可靠的。有时它会接受更改,有时我会收到网关超时。每次部署都会成为压力很大的情况。我不太喜欢使用Monit,因为它会在不等待工作人员完成请求处理的情况下杀死工作人员。那么,这正常吗?其他使用Unicorn部署的人是否有同样的问题,即RAM不受控制地增长?还有,生成的worker数量与定义的work

  7. ruby-on-rails - 在不更改系统时钟的情况下在 rspec 测试中设置系统时间 - 2

    我正在努力让Rails3应用程序准备好使用时区。我的开发机器在美国东部时间,我托管的服务器在UTC。在我的rspec测试中有没有一种方法可以更改ruby​​使用的系统时区,这样我就可以使用相同的系统时区运行测试,而不必更改我计算机上的系统时钟?我研究过Delorean和Timecop,它们不是我要找的。我正在寻找类似的东西Time.system_time_zone="UTC"...然后Time.now将返回UTC时间,而不是我的系统时区设置的时间。 最佳答案 before{Time.stub(:now){Time.now.utc}}

  8. 基于本地时钟的 Javascript 事件触发器 - 2

    我有一个场景,其中一台客户端PC将驱动多个LCD显示器,每个显示器显示一个浏览器窗口。这些浏览器窗口使用jquery显示动画循环中的不同数据。我需要确保两个浏览器可以同步旋转以完全同时旋转,否则它们将在不同时间显示动画。所以我的问题是-我可以触发jquery以根据本地PC时钟交替显示内容吗?例如每次时钟秒==0,显示版本1,每次时钟秒==30,显示版本2等等? 最佳答案 这是(根据我的经验)让计时器尽可能接近时钟时间触发的最精确方法://getcurrenttimeinmsecstonearest30secondsvarmsecs=

  9. javascript - 如何重置 three.js 时钟? - 2

    我想重置时钟,以便clock.getElapsedTime()给我一个新的时间,从我重置时钟开始(例如,在第二次重新启动游戏关卡/场景时很有用).我在init()和我的游戏循环update()中启动clock=newTHREE.Clock();,我正在使用这个时钟。但是当游戏结束时,我想重置时钟(我不会再次启动关卡,只是将玩家定位回起点,所以我不会启动新时钟)。我怎样才能做到这一点? 最佳答案 坏消息:从r73开始,不可能将THREE.Clock重置为零时间,2015年10月发布。解释如下,唯一可能的解决方法在此答案的末尾。深入研究

  10. javascript - Javascript 事件队列是否是一个简单的 FIFO? - 2

    看看这个例子:functionA(){console.log('A');}functionB(){console.log('B');}//andthenisetTimeout(fn,0)bothofthemsetTimeout(A,0);setTimeout(B,0);是否保证B会在A之后立即运行?浏览器是否可能在A和B之间的队列中添加另一个任务?注意:A或B函数都没有向事件循环添加任何新任务。varcallbacks=[];//thenaddabunchofcallbacks...(noneaddseventstoeventqueue)//case1:callbacks.forEac

随机推荐