/*************FIFO IP的仿真测试*************************************** --版本号1.0 --FIFO通常用于异步数据传输、数据缓存、数据位宽转换,本使用基于XILINX FIFO IP实现数据的位宽转换实验 --通过FIFO实现数据缓存,以及数据位宽从32bits转为128btis --写状态机和读状态机分开运行 *********************************************************************/
`timescale 1ns / 1ns //仿真时间刻度/精度
module fifo_test1 ( input I_sysclk, //系统时钟输入 input I_rstn //系统复位 );
wire clk_100m,clk_200m,clk_locked;//MMCM/PLL 时钟信号 wire [127:0]rd_data; //读数据信号 wire fifo_rst; //fifo 复位,高电平有效 wire full; //FIFO满,这里没用到 wire empty; //FIFO空,这里没用到 wire almost_full; //FIFO将满,代表FIFO再写入1个数据就会满,这里没用到 wire almost_empty; //FIFO将空,代表FIFO再读出1个数据就会空,这里没用到 wire [7 : 0] rd_data_count;//读FIFO的计数器,这个计数器不精准,只是非常接近读FIFO中具有的数据个数 wire [9 : 0] wr_data_count;//写FIFO的计数器,这个计数器不精准,只是非常接近写FIFO中写入的数据个数
//写状态机信号 reg WR_REQ = 1'b0; //写请求信号 reg [0 :0]WR_S; //写状态机 reg [10:0]wr_cnt; //写数据计数器 reg wr_en; //写使能寄存器
// 读状态机 reg RD_REQ = 1'b0; //读请求信号 reg [0:0]RD_S; //读状态机 reg [7:0]rd_cnt; //读数据计数器 reg rd_en; //读使能寄存器
reg[9:0] rst_cnt = 10'd0; //复位计数器
assign fifo_rst = (rst_cnt[9:7] == 3'b010); //产生一个高脉冲复位
//MMCM/PLL 产生200M和100M时钟 clk_wiz_0 clk_inst(.clk_out1(clk_200m),.clk_out2(clk_100m),.resetn(I_rstn),.locked(clk_locked),.clk_in1(I_sysclk));
//复位计数器模块 always @(posedge clk_100m)begin if(!clk_locked) rst_cnt <= 10'd0; else if(rst_cnt[9] == 1'b0) rst_cnt <= rst_cnt + 1'b1; end
// FIFO写状态机 always @(posedge clk_200m)begin //写数据用200MHZ 时钟写 if(!rst_cnt[9])begin //复位,重置相关寄存器 WR_S <= 1'b0; wr_cnt <= 11'd0; wr_en <= 1'b0; end else begin case(WR_S) //状态机 0:begin wr_cnt <= 11'd0; if(WR_REQ) //当WR_REQ信号有效,代表了FIFO已经可以写入数据 WR_S <= 1'b1;//进入下一状态 end 1:begin if(wr_cnt < 512)begin //如果写入的数据小于512 wr_en <= 1'b1; //设置写使能 wr_cnt <= wr_cnt+1'b1;//写计数器累加 end else begin //否则,重置使能,并且回到状态0 wr_en <= 1'b0; WR_S <= 1'b0; end end endcase end end
always @(posedge clk_100m)begin//读使用100M时钟 if(!rst_cnt[9])begin //复位,重置相关寄存器 RD_S <= 1'b0; rd_cnt <= 8'd0; rd_en <= 1'b0; end else begin case(RD_S)//读状态机 0:begin rd_cnt <= 8'd0; if(RD_REQ) //RD_REQ代表FIFO中有足够的数据 RD_S <= 1'b1;//下一状态 end 1:begin if(rd_cnt < 128)begin //判断FIFO中读部分的数据,已经读的数量是否小于128个128bits rd_en <= 1'b1; //使能读信号 rd_cnt <= rd_cnt+1'b1;//每读一个数据,累加1 end else begin //否则重置读使能,状态机回到0 rd_en <= 1'b0; RD_S <= 1'b0; end end endcase end end
//判断写FIFO中是否有足够的空间存放下一次写的数据 always @(posedge clk_200m)begin WR_REQ <= (wr_data_count < 10'd511); end
//判断读FIFO中是否有足够的数据可以被读出 always @(posedge clk_100m)begin RD_REQ <= (rd_data_count > 8'd127); end
FIFO32_2_128 FIFO32_2_128_inst0 ( .rst(fifo_rst), //FIFO 复位,高电平有效 .wr_clk(clk_200m), //FIFO 写时钟输入 .rd_clk(clk_100m), //FIFO 读时钟输入 .din({24'd0,wr_cnt[7:0]}), //FIFO 写数据输入,测试数据用wr_cnt[7:0]计数器作为输入,其他高位为0 .wr_en(wr_en), //FIFO 写数据使能 .rd_en(rd_en), //FIFO 读数据使能 .dout(rd_data), //FIFO 读数据输出 .full(full), //FIFO 写通道满,该信号这里没使用 .almost_full(almost_full), //FIFO 写通道将满,该信号这里没使用 .empty(empty), //FIFO 读通道空,该信号这里没使用 .almost_empty(almost_empty), //FIFO 读通道将空,该信号这里没使用 .rd_data_count(rd_data_count), //FIFO 读FIFO的计数器,这个计数器不精准,只是非常接近读FIFO中具有的数据个数 .wr_data_count(wr_data_count) //FIFO 写FIFO的计数器,这个计数器不精准,只是非常接近写FIFO中写入的数据个数 ); endmodule |