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学习.
信号描述
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