欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

SD-Host FIFO模块

程序员文章站 2021-12-30 07:17:39
SD-Host FIFO模块FIFO结构图:信号描述Verilog 实现fifo.vsync_two_stage》rd_empty.vwr_full.vfifo_mem.vFIFO模块作为整个系统中的数据缓存模块,其设计为异步FIFO连接AHB clock domain 和 SD clock domain。SD卡读出的数据写入FIFO,DMA通过AHB总线的命令从FIFO中搬移数据到目标地址;总线上需要写入SD card的数据通过DMA搬移到FIFO,再通过数据控制模块的控制将FIFO中的数据写入SD...


SD-Host FIFO模块
FIFO模块作为整个系统中的数据缓存模块,其设计为异步FIFO连接AHB clock domain 和 SD clock domain。SD卡读出的数据写入FIFO,DMA通过AHB总线的命令从FIFO中搬移数据到目标地址;总线上需要写入SD card的数据通过DMA搬移到FIFO,再通过数据控制模块的控制将FIFO中的数据写入SD card。

FIFO结构图:

下图为FIFO的示意图(由于时间关系没有自己再画一遍图),本设计的区别在于使用双口sram实现在两端都可以进行读写,于是增加了一组空满判断模块。
异步FIFO学习.
SD-Host FIFO模块

信号描述

Signals I/O Width form to Declaration
soft_rst input 1 sd_if 传输结束(写),或者DMA搬运数据结束(读)
ahb_soft_rst input 1 host_sd_syn_ahb 上一个信号同步到ahb domain下的信号
sd_fifo_rst_n input 1 sd_if 连接到 hrst_n
ahb_fifo_rst_n input 1 sd_if 连接到 hrst_n
sd_blk_len input [10:0] sd_if
hclk input 1 AHB bus
hwinc input 1
hrinc input 1
fifo_wdata input [31:0] DMA 总线上的数据通过DMA搬移到fifo准备写入sd card
hwfull output 1 host_ahb_syn_sd DMA 通过打拍后同步给sd_if
hrempty output 1 host_ahb_syn_sd DMA 通过打拍后同步给sd_if
fifo_rdata output [31:0] DMA
ahb_blk_len input [10:0] sd_if
sd_clk input 1 sd_clk sd card 工作时钟
sdwinc input 1 sd卡写fifo使能
sdrinc input 1 sd卡读fifo使能
sdwdata input [31:0]
sdwfull output 1 DMA
sdrempty output 1 DMA
sdrdata output [31:0] DMA

Verilog 实现

fifo.v

module fifo (
        //FIFO ctrl signals
        soft_rst,
        ahb_soft_rst,
        sd_fifo_rst_n,
        ahb_fifo_rst_n,
        sd_blk_len,		// block length,
        //ahb signal
        hclk,
        hwinc,          //write enable, wptr inc enable
        hrinc,
        fifo_wdata,
        hwfull,
        hrempty,
        fifo_rdata,
        ahb_blk_len,	//= sd_blk_len (sd_block_len)
        //sd signal
        sd_clk,
        sdwinc,
        sdrinc,
        sdwdata,
        sdwfull,
        sdrempty,
        sdrdata
);

//ahb signal
parameter ADDRSIZE = 8;
parameter DATASIZE = 32;
parameter SD_SLAVE_FIFO_DEPTH = 256;


//FIFO top ctrl signals
input        soft_rst;
input        ahb_soft_rst;
input        sd_fifo_rst_n;
input        ahb_fifo_rst_n;

//ahb signal
input                   hclk;
input                   hwinc;          //write enable; wptr inc enable
input                   hrinc;
input [DATASIZE-1:0]    fifo_wdata;

output                  hwfull;
output                  hrempty;
output [DATASIZE-1:0]   fifo_rdata;

//sd signal
input                   sd_clk;
input                   sdwinc;
input                   sdrinc;
input [DATASIZE-1:0]    sdwdata;
output                  sdwfull;
output                  sdrempty;
output [DATASIZE-1:0]   sdrdata;

input [10:0]    sd_blk_len;
input [10:0]    ahb_blk_len;

wire sd_clr;
wire ahb_clr;

//there are used foe generate the actual number of data in fifo
wire [ADDRSIZE:0]   ahb_rptr_bin_nxt;
wire [ADDRSIZE:0]   sd_rptr_bin_nxt;
wire [ADDRSIZE:0]   ahb_wptr_bin_next;
wire [ADDRSIZE:0]   sd_wptr_bin_next;

wire [ADDRSIZE:0]   ahb_rptr_reg;
wire [ADDRSIZE:0]   ahb_wpter_reg;
wire [ADDRSIZE:0]   ahb_rptr_s2_reg;
wire [ADDRSIZE:0]   ahb_wpter_s2_reg;
wire [ADDRSIZE:0]   sd_rptr_reg;
wire [ADDRSIZE:0]   sd_wpter_reg;
wire [ADDRSIZE:0]   sd_rptr_s2_reg;
wire [ADDRSIZE:0]   sd_wpter_s2_reg;

wire [ADDRSIZE-1:0] hwaddr;
wire [ADDRSIZE-1:0] headdr;
wire [ADDRSIZE-1:0] sdwaddr;
wire [ADDRSIZE-1:0] sdraddr;

wire [8:0]  blk_len_sd;
wire [8:0]  blk_len_ahb;

wire    fifo_clr;
wire    ahb_fifo_clr;


assign sd_clr = soft_rst;
assign ahb_clr = ahb_soft_rst;

assign blk_len_sd = sd_blk_len[10:2];
assign blk_len_ahb = ahb_blk_len[10:0];

//synchronine ahb read pointer to sd clk domian
sync_two_stage U_AHB_RPT_SD (
            .clk(sdclk),
            .rst_n(sd_fifo_rst_n),
            .clr(sd_clr),
            .ptr_reg(ahb_rptr_reg),
            .ptr_s2_reg(ahb_rptr_s2_reg)
);

//synchronine ahb write pointer to sd clk domian
sync_two_stage U_AHB_WPT_SD (
            .clk(sdclk),
            .rst_n(sd_fifo_rst_n),
            .clr(sd_clr),
            .ptr_reg(ahb_wptr_reg),
            .ptr_s2_reg(ahb_wptr_s2_reg)
);

//synchronine sd read pointer to AHB clk domian
sync_two_stage U_SD_RPT_AHB (
            .clk(hclk),
            .rst_n(ahb_fifo_rst_n),
            .clr(ahb_clr),
            .ptr_reg(sd_rptr_reg),
            .ptr_s2_reg(sd_rptr_s2_reg)
);

//synchronine sd read pointer to AHB clk domian
sync_two_stage U_SD_RPT_AHB (
            .clk(hclk),
            .rst_n(ahb_fifo_rst_n),
            .clr(ahb_clr),
            .ptr_reg(sd_wptr_reg),
            .ptr_s2_reg(sd_wptr_s2_reg)
);

//AHB read empty module
rd_empty    U_AHB_EMPTY (
            .clk(hclk),
            .rst_n(ahb_fifo_rst_n),
            .clr(ahb_clr),
            .rinc(hrinc),
            .raddr(hraddr),
            .rptr_reg(ahb_rptr_reg),
            .wptr_s2_reg(sd_wptr_s2_reg),
            .rd_empty(hrempty)
            //.blk_len(blk_len_ahb)
);

//SD read empty module
rd_empty    U_SD_EMPTY (
            .clk(sdclk),
            .rst_n(sd_fifo_rst_n),
            .clr(sd_clr),
            .rinc(sdrinc),
            .raddr(sdraddr),
            .rptr_reg(sd_rptr_reg),
            .wptr_s2_reg(ahb_wptr_s2_reg),
            .rd_empty(sdrempty)
           // .blk_len(blk_len_sd)
);


//AHB write full module
wr_full    U_AHB_FULL (
            .clk(hclk),
            .rst_n(ahb_fifo_rst_n),
            .clr(ahb_clr),
            .winc(hwinc),
            .waddr(hwaddr),
            .wptr_reg(ahb_wptr_reg),
            .rptr_s2_reg(sd_rptr_s2_reg),
            .wr_full(hwfull),
            .blk_len(blk_len_ahb)
);

//SD read empty module
wr_full    U_SD_FULL (
            .clk(sdclk),
            .rst_n(sd_fifo_rst_n),
            .clr(sd_clr),
            .winc(sdwinc),
            .waddr(sdwaddr),
            .wptr_reg(sd_wptr_reg),
            .rptr_s2_reg(ahb_rptr_s2_reg),
            .wr_full(sdwfull),
            .blk_len(blk_len_sd)
);

fifo_mem U_FIFO_MEN (
            .hclk(hclk),
            .ahb_fifo_rst_n(ahb_fifo_rst_n),
            .hwinc(hwinc),
            .hrinc(hrinc),
            .hwaddr(hwaddr),
            .hraddr(hraddr),
            .fifo_wdata(fifo_wdata),
            .hwfull(hwfull),
            .fifo_rdata(fifo_rdata),

            .sdclk(sdclk),
            .sdwinc(sdwinc),
            .sdrinc(sdrinc),
            .sdwaddr(sdwaddr),
            .sdraddr(sdraddr),
            .sdwdata(sdwdata),
            .sdwfull(sdwfull),
            .sdrdata(sdrdata),

            .fifo_en(1'b1)
        
);

endmodule

sync_two_stage.v

用于地址指针的跨时钟域同步。

module sync_twostage(
		clk,
		rst_n,
		clr,
		ptr_reg,
		ptr_s2_reg
);

parameter ADDRSIZE = 8;
parameter DATASIZE = 32;
parameter SD_SLAVE_FIFO_DEPTH = 256;

input	clk;
input	rst_n;
input	clr;
input [ADDRSIZE:0]	ptr_reg;

output [ADDRSIZE:0]	ptr_s2_reg;

reg [ADDRSIZE:0]	ptr_s1_reg;
reg [ADDRSIZE:0]	ptr_s2_reg;

awlways@(posedge clk or negedge rst_n)
if(!rst_n)
begin
	ptr_s1_reg <= 0;
	ptr_s2_reg <= 0;
end
else if (clr)
begin
	ptr_s1_reg <= 0;
	ptr_s2_reg <= 0;
end
else
begin
	ptr_s1_reg <= ptr_reg;
	ptr_s2_reg <= ptr_s1_reg;
end

endmodule

rd_empty.v

产生读地址和读空信号。

生成格雷码地址指针,与写地址指针进行读空的判断:
assign rptr_gray_nxt = (rptr_bin_nxt >>1) ^ rptr_bin_nxt;

module rd_empty (
        clk,
        rst_n,
        clr,
        rinc,
        raddr,
        rptr_reg,
        wptr_s2_reg,
        rd_empty,

);
parameter ADDRSIZE = 8;
parameter DATASIZE = 32;
parameter SD_SLAVE_FIFO_DEPTH = 32;

input               clk;
input               rst_n;
input               clr;
input               rinc;
input [ADDRSIZE:0]  wptr_s2_reg;

output [ADDRSIZE-1:0]   raddr;
output [ADDRSIZE:0] rptr_reg;
output  rd_empty;

reg [ADDRSIZE:0]    rptr_reg;
reg [ADDRSIZE:0]    rptr_bin;
reg     rd_empty;

wire    empty_val;
wire [ADDRSIZE:0]   rptr_bin_nxt;
wire [ADDRSIZE:0]   rptr_gray_nxt;
wire [ADDRSIZE:0]   rptr_gray_temp_nxt;


// binary code counter
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) 
        rptr_bin <= 0;
    else if (clr)
        rptr_bin <= 0;
    else
        rptr_bin <= rptr_bin_nxt;
end

assign rptr_bin_nxt = rptr_bin + {8'd0,(rinc && !rd_empty)};

//gray code counter
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        rptr_reg <= 0;
    else if (clr)
        rptr_reg <= 0;
    else 
        rptr_reg <= rptr_gray_nxt;
end

assign rptr_gray_nxt = (rptr_bin_nxt >>1) ^ rptr_bin_nxt;

//output the read address
assign raddr = rptr_bin[ADDRSIZE-1:0];

assign empty_val = (rptr_gray_nxt == wptr_s2_reg);
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        rd_empty <=0;
    else if (clr)
        rd_empty <=0;
    else 
        rd_empty <= empty_val;
end

endmodule

wr_full.v

产生地址写指针和写满信号。

注意:
assign wptr_temp = wptr_temp + (SD_SLAVE_FIFO_DEPTH - blk_len); assign wptr_gray_temp_nxt = (wptr_temp>>1) ^ wptr_temp;
和传输过来的读指针信号进行比较,判断是否写满。

比如FIFO深度256,一次传输的block深度128,那当读指针读到108时,其实写指针增加到236就写满1个blcok,需要进行数据搬移,而此时因为FIFO深度足够大,其最高位还没有翻转无法正常的判断,所以要再加上128.

module wr_full (
        clk,
        rst_n,
        clr,
        winc,
        waddr,
        wptr_reg,
        rptr_s2_reg,
        wr_full,
        blk_len

);
parameter ADDRSIZE = 8;
parameter DATASIZE = 32;
parameter SD_SLAVE_FIFO_DEPTH = 32;

input               clk;
input               rst_n;
input               clr;
input               winc;
input [ADDRSIZE:0]  rptr_s2_reg;
input [ADDRSIZE:0]  blk_len;

output [ADDRSIZE-1:0]   waddr;
output              wr_full;
output [ADDRSIZE:0] wptr_reg;

reg [ADDRSIZE:0]    wptr_reg;
reg [ADDRSIZE:0]    wptr_bin;
reg [ADDRSIZE:0]    rptr_s2_bin;
wire [ADDRSIZE:0]   wptr_bin_nxt;
wire [ADDRSIZE:0]   wptr_gray_nxt;
wire [ADDRSIZE:0]   wptr_gray_temp_nxt;
wire [ADDRSIZE:0]   wptr_temp;
wire wr_full;


// bin code counter
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) 
        wptr_bin <= 0;
    else if (clr)
        wptr_bin <= 0;
    else
        wptr_bin <= wptr_bin_nxt;
end

assign wptr_bin_nxt = wptr_bin + {8'd0,(winc && !wr_full)};
assign wptr_temp = wptr_temp + (SD_SLAVE_FIFO_DEPTH - blk_len);

//gray code counter
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        wptr_reg <= 0;
    else if (clr)
        wptr_reg <= 0;
    else 
        wptr_reg <= wptr_gray_nxt;
end

assign wptr_gray_temp_nxt = (wptr_temp>>1) ^ wptr_temp;
assign wptr_gray_nxt = (wptr_bin_nxt >>1) ^ wptr_bin_nxt;

//output the write address
assign waddr = wptr_bin[ADDRSIZE-1:0];

assign full_val = (wptr_gray_temp_nxt == {~rptr_s2_reg[ADDRSIZE:ADDRSIZE-1],rptr_s2_reg[ADDRSIZE-2:0]});
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        wr_full <=0;
    else if (clr)
        wr_full <=0;
    else 
        wr_full <= full_val;
end

endmodule

fifo_mem.v

module fifo_mem (
	//ahb_signal	
		hclk,
		ahb_fifo_rst_n,
		hwinc,
		hrinc,
		hwaddr,
		hraddr,
		fifo_wdata,
		hwfull,
		fifo_rdata,
	//sd signal
		sdclk,
		sdwinc,
		sdrinc,
		sdwaddr,
		sdraddr,
		sdwdata,
		sdwfull,
		sdrdata,
	//fifo enable
		fifo_en,

);
parameter ADDRSIZE = 8;
parameter DATASIZE = 32;
parameter SD_SLAVE_FIFO_DEPTH = 256;

	//ahb_signal	
input				   	hclk;
input   				ahb_fifo_rst_n;
input   				hwinc;
input   				hrinc;
input [ADDRSIZE-1:0]	hwaddr;
input [ADDRSIZE-1:0]	hraddr;
input [DATASIZE-1:0]    fifo_wdata;
input    				hwfull;
output [DATASIZE-1:0]   fifo_rdata;
    //sd signal
input   				sdclk;
input   				sdwinc;
input   				sdrinc;
input [ADDRSIZE-1:0]	sdwaddr;
input [ADDRSIZE-1:0]	sdraddr;
input [DATASIZE-1:0]    sdwdata;
input    				sdwfull;
output [DATASIZE-1:0]   sdrdata;
    //fifo enable
input    			fifo_en;

wire [ADDRSIZE-1:0]	addra,addrb;

wire 				wena,wenb;
wire 				cena,cenb;
wire [DATASIZE-1:0]	fifo_wdata_in;
wire [DATASIZE-1:0]	sdwdata_in;

assign	wena = !(sdwinc && !sdwfull);
assign	wenb = !(hwinc && !hwfull);
assign 	cena = !((sdwinc || sdrinc) && fifo_en);
assign 	cenb = !((hwinc || hrinc) && fifo_en);

assign addra = sdwinc ? sdwaddr : sdraddr;
assign addrb = hwinc ? hwaddr : hraddr;

assign sdwdata_in = wena ? 0 :sdwdata;
assign fifo_wdata_in = wenb ? 0 : fifo_wdata;

dp_sram_m4_1KB_weapper U_DP_SRAM_M4_1KB_WRAPPER(
		
		rst_n	(ahb_fifo_rst_n),
		clka	(sdclk),
		addr_a	(addra),
		wena_n	(wena),
		cena_n	(cena),
		oena_n	(1'b0),
		datain_a(sdwdata_in),
		datao_a	(sdrdata),

		clkb	(hclk),
		addr_b	(addrb),
		wenb_n	(wenb),
		cenb_n	(cenb),
		oenb_n	(1'b0),
		datain_b(fifo_wdata_in),
		datao_b	(fifo_rdata)


);
endmodule

本文地址:https://blog.csdn.net/zgezi/article/details/107296862