例化了两个fifo,写fifo,读fifo。对数据进行缓存完成跨时钟域处理。
系统主板工作频率50MHZ,SDRAM工作频率100MHZ,所以需要用fifo实现跨时钟域处理。
fifo控制模块
波形绘制
sdram 时钟100mhz,sys_clk为100MHZ 串口外部传入数据,写fifo进行缓存。 串口时钟频率50mhz。
写部分
写fifo信号
写fifo信号wr_fifo_wr_clk 写请求信号wr_fifo_wr_data.
写sdram地址
数据需要写入sdram中,sdram_wr_b_addr,sdram_wr_e_addr.24位宽,bank地址 行地址 列地址组合在一起。开始到结束。 看上去是11个地址我们只用了10个地址。
突发长度wr_brust_len
写复位信号 wr_rst:
综上完成写部分波形图绘制
再加上复位信号,复位结束信号
数据读出,写入sdram
现在进行数据读出,写入sdram中突发存储,所以fifo必须满足一次突发长度,利用写fifo的计数信号,由写fifo传出,对写入个数进行计数,满足一次突发长度,此时sdram而且完成了一次初始化,可以进行数据写入。 请求信号会被传入仲裁模块,仲裁模块判断,可以进行写,发出写使能信号。 完成写入后,传出sdram_wr_ack响应信号。
数据作为sdram_data_in,此时信号时钟为100mhz,因为sdram工作时钟为100mhz,fifo读取数据会滞后一个时钟周期,所以此处数据也需要滞后一个时钟周期。
sdram_wr_addr
wr_ack_dly 响应信号大一拍。利用下降沿完成写地址bank的更新。
读部分 读fifo
由sdram读取数据
外部传入读有效信号,read_vaild,sdram_rd_req读请求信号。
读请求响应信号延迟一拍,根据下降沿,控制地址更新。sdram读出的数据会写入fifo控制模块,读fifo中。
读fifo进行计数10字节的数据,从读fifo中读出数据传入串口,查看数据。
读fifo读时钟等信号,
读fifo读请求信号,读fifo的读数据传出,读fifo的读时钟,请求信号完成后拉低。 读FIFO的计数信号也要完成更新。读出来数据通过串口传到上位机。
16位宽 1024 字节,读时钟和写时钟分开。
默认:
空信号不要,选择异步清零信号
生成例化模板:
.aclr ( aclr_sig ),
.data ( data_sig ),
.rdclk ( rdclk_sig ),
.rdreq ( rdreq_sig ),
.wrclk ( wrclk_sig ),
.wrreq ( wrreq_sig ),
.q ( q_sig ),
.rdusedw ( rdusedw_sig ),
.wrusedw ( wrusedw_sig )
);
程序
(
input wire sys_clk,
input wire sys_rst_n,
//写fifo信号
input wire wr_fifo_wr_clk,
input wire wr_fifo_wr_req,
input wire [15:0]wr_fifo_wr_data,
input wire [23:0]sdram_wr_b_addr,
input wire [23:0]sdram_wr_e_addr,
input wire [9:0]wr_brust_len,
input wire wr_rst,
//读fifo信号
input wire rd_fifo_rd_clk,
input wire rd_fifo_rd_req,
input wire [23:0]sdram_rd_e_addr,
input wire [23:0]sdram_rd_b_addr,
input wire [9:0]rd_brust_len,
input wire rd_rst,
input wire init_end,
input wire read_vaild,
output wire [15:0]rd_fifo_rd_data,
output wire [9:0]rd_fifo_num,
//sdram 写信号
input wire sdram_wr_ack,
output reg sdram_wr_req,
output reg [23:0]sdram_wr_addr,
output wire [15:0]sdram_data_in,
//sdram 读信号
input wire sdram_rd_ack,
output reg sdram_rd_req,
input wire [15:0]sdram_data_out,
output reg [23:0]sdram_rd_addr
);
wire [9:0]wr_fifo;
wire wr_ack_fall;
wire rd_ack_fall;
reg wr_ack_dly;
reg rd_ack_dly;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
rd_ack_dly <= 1'b0;
else
rd_ack_dly <= sdram_rd_ack;
//提取下降沿
assign wr_ack_fall = (wr_ack_dly&~sdram_wr_ack);
assign rd_ack_fall = (rd_ack_dly&~sdram_rd_ack);
//写地址进行赋值
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
sdram_wr_addr <= 24'd0;
else if(wr_rst==1'b1)
sdram_wr_addr <= sdram_wr_b_addr;
else if(wr_ack_fall == 1'b1)
begin
if(sdram_wr_addr<(sdram_wr_e_addr-wr_brust_len))
sdram_wr_addr <= sdram_wr_addr + wr_brust_len;
else
sdram_wr_addr <= sdram_wr_b_addr;
end
//读地址赋值
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
sdram_rd_addr <= 24'd0;
else if(rd_rst==1'b1)
sdram_rd_addr <= sdram_rd_b_addr;
else if(rd_ack_fall == 1'b1)
begin
if(sdram_rd_addr<(sdram_rd_e_addr-rd_brust_len))
sdram_rd_addr <= sdram_rd_addr + rd_brust_len;
else
sdram_rd_addr <= sdram_rd_b_addr;
end
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
begin
sdram_wr_req <= 1'b0;
sdram_rd_req <= 1'b0;
end
else if(init_end == 1'b1)
begin
if(wr_fifo_num >= wr_brust_len)
begin
sdram_wr_req <= 1'b1;
sdram_rd_req <= 1'b0;
end
else
if((rd_fifo_num<rd_brust_len)&&(read_vaild ==1'b1 ))
begin
sdram_wr_req <= 1'b0;
sdram_rd_req <= 1'b1;
end
else
begin
sdram_wr_req <= 1'b0;
sdram_rd_req <= 1'b0;
end
end
else
begin
sdram_wr_req <= 1'b0;
sdram_rd_req <= 1'b0;
end
//声明fifo
fifo_data wr_fifo_data_inst1 (
//用户接口
.wrclk ( wr_fifo_wr_clk ),
.wrreq ( wr_fifo_wr_req),
.data (wr_fifo_wr_data ),
//sdram接口
.rdclk ( sys_clk ),
.rdreq ( sdram_wr_ack ),
.q ( sdram_data_in ),
.aclr ( wr_rst||~sys_rst_n ),
.rdusedw ( wr_fifo_num ),
.wrusedw ( )
);
fifo_data rd_fifo_data_inst1 (
//sdram接口
.wrclk ( sys_clk ),
.wrreq (sdram_rd_ack ),
.data (sdram_data_out ),
//用户接口
.rdclk ( rd_fifo_rd_clk ),
.rdreq ( rd_fifo_rd_req ),
.q (rd_fifo_rd_data ),
.aclr ( wr_rst||~sys_rst_n ),
.rdusedw ( ),
.wrusedw (rd_fifo_num )
);
endmodule