【芯片前端】保持代码手感——握手型同步FIFO设计

前言

工作中做了太久方案,还是要继续对代码手感的保持,这次完成握手型同步FIFO的RTL设计,设计规格如下:

  • 写入与读出均采用握手型接口;
  • 支持2的整数次与非整数次深度;
  • 对外输出逻辑时序较优;

RTL设计

对外接口

握手型同步FIFO,接口如下:

module sync_fifo #(
	parameter DEPTH = 8,
	parameter WIDTH = 32
)(
	input 				clk,
	input 				rst_n,
	
	input  			    in_valid,
	input  [WIDTH -1:0] in_data,
	output 			    in_ready,
	
	output			    out_valid,
	output [WIDTH -1:0] out_data,
	input  			    out_ready
);

localparam DP_WD = $clog2(DEPTH);


endmodule

根据我的设计要求,对外输出的in_ready和out_valid必须为寄存器输出,以保证时序最优。out_data最好也要作为寄存器输出,但是out_data必然会有MUX逻辑,在深度较浅时时序会比较好,深度太深MUX逻辑带来的时序就不能忽略了。

逻辑设计

同步FIFO的设计思路在 【芯片前端】保持代码手感——同步FIFO 中已经盘过了,这次注重握手逻辑的规划,对于涉及过得设计思路不再赘述。

写入/读出ADDR逻辑

写入计数器主要调整了触发器en端的逻辑,把输入握手作为使能信号:

//==================================================================
//写入计数器
//==================================================================
reg  [DP_WD   :0]waddr;
wire             wenc;
wire             waddr_d_h;
wire [DP_WD -1:0]waddr_d_l;
assign wenc = in_valid && in_ready;
assign waddr_d_h = (waddr[DP_WD-1:0] == DEPTH-1) ? ~waddr[DP_WD] : waddr[DP_WD];
assign waddr_d_l = (waddr[DP_WD-1:0] == DEPTH-1) ? 0 : waddr[DP_WD-1:0] + 1;
always @(posedge clk or negedge rst_n)begin
	if(~rst_n)    waddr <= 0;
	else if(wenc) waddr <= {waddr_d_h, waddr_d_l};
end

读出计数器同理:

//==================================================================
//读出计数器
//==================================================================
reg  [DP_WD   :0]raddr;
wire             renc;
wire             raddr_d_h;
wire [DP_WD -1:0]raddr_d_l;
assign renc = out_valid && out_ready;
assign raddr_d_h = (raddr[DP_WD-1:0] == DEPTH-1) ? ~raddr[DP_WD] : raddr[DP_WD];
assign raddr_d_l = (raddr[DP_WD-1:0] == DEPTH-1) ? 0 : raddr[DP_WD-1:0] + 1;
always @(posedge clk or negedge rst_n)begin
	if(~rst_n)    raddr <= 0;
	else if(renc) raddr <= {raddr_d_h, raddr_d_l};
end

FIFO深度计数器

fifo深度的计算我做了一些调整,fifi_cnt也作为寄存器输出,主要是我需要用fifi_cnt_d这个变量,所以是在数据读写的当拍产生fifi_cnt_d这个逻辑:

//==================================================================
//深度计数器
//==================================================================
reg  [DP_WD :0]fifo_cnt_q;
wire [DP_WD :0]waddr_d = wenc ? {waddr_d_h, waddr_d_l} : waddr;
wire [DP_WD :0]raddr_d = renc ? {raddr_d_h, raddr_d_l} : raddr;
wire [DP_WD :0]fifo_cnt_d = (waddr_d[DP_WD] == raddr_d[DP_WD]) ? (waddr_d[DP_WD-1:0] - raddr_d[DP_WD-1:0]):
															     (waddr_d[DP_WD-1:0] + DEPTH - raddr_d[DP_WD-1:0]);
wire fifo_cnt_en = (wenc ^ renc);
always @(posedge clk or negedge rst_n)begin
	if(~rst_n)    fifo_cnt_q <= 0;
	else if(fifo_cnt_en) fifo_cnt_q <= fifo_cnt_d;
end

数据寄存

数据寄存,寄存器不复位降功耗,出口有一个多路的MUX,WIDTH*DEPTH越大,逻辑越深绕线越难:

//==================================================================
//数据寄存
//==================================================================
reg [WIDTH -1:0]data[DEPTH];
always @(posedge clk or negedge rst_n)begin
	if(wenc) data[waddr[DP_WD-1:0]] <= in_data;
end
assign out_data = data[raddr[DP_WD-1:0]];

对外逻辑的产生

in_ready实际就是常用FIFO的full信号取反,out_valid就是empty的取反,因此单纯做逻辑是不难的。但是为了实现寄存器输出,最后我选择了这样的逻辑:

//==================================================================
//对外逻辑
//==================================================================
//assign in_ready  = (fifo_cnt_q < DEPTH);
//assign out_valid = (fifo_cnt_q > {DP_WD{1'b0}});

wire in_ready_en;
wire in_ready_d;
reg  in_ready_q;
assign in_ready_en = (out_valid && out_ready) || in_ready;
assign in_ready_d  = (fifo_cnt_d < DEPTH);
always @(posedge clk or negedge rst_n)begin
	if(~rst_n)          in_ready_q <= 1;
	else if(in_ready_en)in_ready_q <= in_ready_d;
end


wire out_valid_en;
wire out_valid_d;
reg  out_valid_q;
assign out_valid_en = (in_valid && in_ready) || out_valid;
assign out_valid_d  = (fifo_cnt_d > {DP_WD{1'b0}});
always @(posedge clk or negedge rst_n)begin
	if(~rst_n)           out_valid_q <= 0;
	else if(out_valid_en)out_valid_q <= out_valid_d;
end

assign in_ready  = in_ready_q;
assign out_valid = out_valid_q;

仿真

使用auto_verification进行仿真,得到波形图:

  • 6
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 9
    评论
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

尼德兰的喵

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值