SD-Host FIFO模块

2022-08-06,,,

SD-Host FIFO模块

    • FIFO结构图:
    • 信号描述
    • Verilog 实现
      • fifo.v
      • sync_two_stage.v
      • rd_empty.v
      • wr_full.v
      • fifo_mem.v

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

FIFO结构图:

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

《SD-Host FIFO模块.doc》

下载本文的Word格式文档,以方便收藏与打印。