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

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
);

  • 1
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值