/**
******************************************************************************
* @file fifo_usv2.v
* @author 西殿源
* @version V2
* @date 08/05/2012
* @brief 自己的fifo
* @info 1. 相对于V1版,响应更及时:当前时刻检测到写fifo请求,即在之后的一个clk内完成写sram操作
当前时刻检测到读fifo请求,即在之后的半个clk内完成读sram操作
2. 当同时有读写fifo请求时,写优先,并自动在延后一个clk后执行读操作
3. 当读写在相邻的clk的上时,是否有潜在的亚稳态,尚需思之;但经硬件验证,能达到与quartus自带IP相同的效果
******************************************************************************
*/
module fifo_usv2
#(parameter WIDH = 10)
(
input clk, //输入时钟
input rst_n, //异步复位,低电平有效
input wr_ff, //fifo写使能
input rd_ff, //fifo读使能
input [15:0] dat_in, //fifo写入数据
output reg [15:0] dat_ro_ff, //fifo输出数据
output reg [WIDH-1:0] num_ff, //fifo缓冲计数
output reg emp_ff, //fifo空信号
output reg ful_ff, //fifo满信号
output reg [17:0] addr_sram, //sram地址总线
inout [15:0] data_sram, //sram数据总线
output cs_sram, //sram片选信号
output [1:0] byte_sram, //sram高低字节使能
output reg oe_sram, //sram读出使能
output reg wr_sram //sram写入使能
);
parameter FIFO_DEP = 2^WIDH; //FIFO缓存深度
parameter SRAM_STA = 18'd0; //外部sram起始地址
parameter YES = 1'b1;
parameter NO = 1'b0;
parameter HI = 1'b1;
parameter LO = 1'b0;
reg [WIDH-1:0] wr_pit; //写指针,指向下一次要写sram的地址
reg [WIDH-1:0] rd_pit; //读指针,指向下一次要读sram的地址
reg wr_r; //写fifo内部寄存器
reg rd_r; //读fifo内部寄存器
reg rd_exe; //执行读操作
reg rd_sim; //=1时表明同时有fifo读写操作,暂存读信号
wire rd_p; //当前时刻有读fifo请求,或由于前一时刻fifo读写冲突时,此时执行读操作
reg [15:0] data_sram_r; //sram数据端口双向,作为输出寄存器
reg sram_dir; //sram数据端口方向控制
reg d2_en;
reg [1:0] d2_cnt;
assign byte_sram = 2'b10; //高低字节使能,8位工作方式
assign cs_sram = 1'b0; //片选sram
assign data_sram = sram_dir? data_sram_r : 16'bz; //sram_dir = 1时作为输出端口;= 0时 作为输入
assign rd_p = rd_sim || rd_ff; //两者满足其一即可执行读操作
//检测读写fifo的请求,并协调对应的sram读写操作
always @(posedge clk,negedge rst_n) begin
if(!rst_n) begin
addr_sram <= 18'd0;
wr_pit <= 10'd0;
rd_pit <= 10'd0;
wr_sram <= HI; //
oe_sram <= HI;
rd_sim <= NO; //复位后,无读写fifo冲突
sram_dir <= NO; //复位后,外接sram的数据总线高阻,作为输入
end
else if(wr_ff) begin //写fifo请求优先于读fifo请求
if(rd_ff) rd_sim <= YES; //如果检测到同时有读fifo请求,记录此请求,并延后1个clk再执行读fifo
else ;
addr_sram <= wr_pit; //sram地址,写fifo即写外部sram
wr_pit <= wr_pit + 1; //更新sram写指针
sram_dir <= YES; //sram总线方向位输出
data_sram_r <= dat_in; //将fifo的入口数据写入输出寄存器
wr_sram <= LO; //
end
else if(rd_p) begin
wr_sram <= HI;
rd_sim <= NO; //如果上一个clk同时出现读写fifo请求,则本时刻是延时一个clk周期的读fifo操作,清除之前的读fifo记录
addr_sram <= rd_pit; //sram地址,读fifo即读外部的sram
rd_pit <= rd_pit + 1; //更新sram读指针
sram_dir <= NO;
oe_sram <= LO;
end
else begin //无读写fifo请求,清楚读写标志
wr_sram <= HI;
oe_sram <= HI;
end
end
//计算fifo的缓存状态,空?已占用资源?
always @(posedge clk,negedge rst_n) begin
if(!rst_n) begin
num_ff <= 0;
emp_ff <= YES;
end
else if (wr_pit == rd_pit) begin
emp_ff <= YES;
num_ff <= 0;
end
else if (wr_pit > rd_pit) begin
emp_ff <= NO;
num_ff <= wr_pit - rd_pit;
end
else begin
emp_ff <= NO;
num_ff <= wr_pit + 1024 - rd_pit;
end
end
//计算fifo的缓存状态,满?
always @(posedge clk,negedge rst_n) begin
if(!rst_n) begin
ful_ff <= NO;
end
else if(num_ff == 1023) begin
ful_ff <= YES;
end
else begin
ful_ff <= NO;
end
end
//检测到fifo读请求时,从sram读出数据至fifo的出口端
always @(negedge clk,negedge rst_n) begin
if(!rst_n) dat_ro_ff <= 16'dz;
else if(!oe_sram) dat_ro_ff <= data_sram; //将数据从总线读到fifo的出口端
else ;
end
endmodule
用户1752181 2014-6-13 15:48
用户377235 2012-8-15 21:16
用户1629256 2012-8-5 20:05
再次说明一下,真心希望热心网友在代码风格,代码优化上,大胆斧正,不吝赐教