【芯片前端】延迟一拍出数的握手型ram结构的第二次探索

前言

【芯片前端】延迟一拍出数的握手型ram结构的一次探索_尼德兰的喵的博客-CSDN博客

 上一次尝试对握手型的ram控制器进行了一次尝试,最后尝试给出的结构如下图所示:

 之后呢我们会再拉出来这个结构来讨论他的优缺点,这篇文章呢是写一个更普遍更简单的结构,开始的起因是上一篇文章中的讨论:

当时我暂时把第三种思路放在了一边而研究了下第二种思路因此搞了上面的结构,这次呢来根据第三种思路规划代码。

预备代码

双端口ram代码和之前一样:

module dual_port_RAM #(parameter DEPTH = 16,
					   parameter WIDTH = 8)(
	 input wclk	,
	 input wenc	,
	 input [$clog2(DEPTH)-1:0] waddr	,
	 input [WIDTH-1:0] wdata	,
	 input rclk	,
	 input renc	,
	 input [$clog2(DEPTH)-1:0] raddr	,
	 output reg [WIDTH-1:0] rdata
);
 
reg [WIDTH-1:0] RAM_MEM [0:DEPTH-1];
 
always @(posedge wclk) begin
	if(wenc)
		RAM_MEM[waddr] <= wdata;
end 
 
always @(posedge rclk) begin
	if(renc)
		rdata <= RAM_MEM[raddr];
end 
 
endmodule  

握手型双端口ram的接口以及写通路也和之前一样:

module hand_dp_ram #(
	parameter DEPTH = 16,
	parameter WIDTH = 8
)(
	input clk,
	input rst_n,
	
	input  					   wvalid,
	output 					   wready,
	input  [$clog2(DEPTH) -1:0]waddr,
	input  [WIDTH         -1:0]wdata,
	
	input  					   arvalid,
	output 					   arready,
	input  [$clog2(DEPTH) -1:0]araddr,
	
	output					   rvalid,
	input					   rready,
	output [WIDTH         -1:0]rdata	
);

//***********************************************
// ram inst
//***********************************************
wire 					 ram_wenc;
wire [$clog2(DEPTH) -1:0]ram_waddr;
wire [WIDTH         -1:0]ram_wdata;
wire 					 ram_renc;
wire [$clog2(DEPTH) -1:0]ram_raddr;
wire [WIDTH         -1:0]ram_rdata;
 
dual_port_RAM #(
	.DEPTH(DEPTH),
	.WIDTH(WIDTH))
u_ram(
	 .wclk(clk),
	 .wenc(ram_wenc),
	 .waddr(ram_waddr),
	 .wdata(ram_wdata),
	 .rclk(clk),
	 .renc(ram_renc),
	 .raddr(ram_raddr),
	 .rdata(ram_rdata)
);
 
//***********************************************
// write path
//***********************************************
assign ram_wenc  = wvalid && wready;
assign ram_waddr = waddr;
assign ram_wdata = wdata;


endmodule

读通路逻辑

再来确定一下我们的思路:当数据没有被取出时,连续发起同一地址的renc,直到该地址的数据被读取。而有一个关键点,在renc的下一拍我们才能知道读出的数据是否取走,才能确定是要读取新的地址(假设又有新的读请求到来了)还是读取旧的地址。因此必须要有两个寄存器分别寄存旧的读使能和读地址。

//***********************************************
// read path
//***********************************************
reg                    arvalid_ff;
reg[$clog2(DEPTH) -1:0]araddr_ff;

arvalid_ff应当有两种情况需要跳变:第一种,当拍arvalid和arready握手向ram发出来读请求,因为不确定下一拍ram_data能否被取用,所以此时arvalid_ff应当在下一拍跳变为1表示当拍发起过ram读请求;第二种,rready置起为1时,这表示上一拍读的ram_data必然在此拍被取用,此时代表着上一拍发起读请求的标志arvalid_ff也就可以跳变为0了,当然这种情况的优先级是要低于场景一的。

always @(posedge clk or negedge rst_n)begin
    if(!rst_n)
        arvalid_ff <= 1'b0;
    else if(arvalid && arready)begin
        arvalid_ff <= 1'b1;
    end
    else if(rready)begin
        arvalid_ff <= 1'b0;
    end
end

相对而言,araddr_ff不会参与控制逻辑,那么逻辑就简单了很多:

always @(posedge clk)begin
    if(arvalid && arready)begin
        araddr_ff <= araddr;
    end
end

而后呢再做一个renc的打拍来标记数据读出的使能(给rvalid用):

reg                    ram_renc_ff;
always @(posedge clk or negedge rst_n)begin
    if(!rst_n)
        ram_renc_ff <= 1'b0;
    else begin
        ram_renc_ff <= ram_renc;
    end
end

万事俱备,接下来做关键的端口逻辑!

先看arready吧:

assign arready   = !arvalid_ff || rready;

如果rready为1则代表着这一笔读请求之前的请求在当拍必然可以取走,那么下一拍即使ready跳变为0,至少arvalid_ff/araddr_ff是可以将当拍的读取信息锁存并且持续读取当前地址的。!arvalid_ff的情况也一样,哪怕当前ready已经为0,arvalid_ff/araddr_ff可以寄存当前拍的信息。

之后是给ram的信号:

//to ram
assign ram_renc  = arvalid || (arvalid_ff && rready == 1'b0);
assign ram_raddr = (rready == 1'b0 && arvalid_ff) ? araddr_ff : araddr;

理论上说,ram_renc应该用(arvalid && arready) || (arvalid_ff && rready == 1'b0),但是通过观察逻辑可以发现,当后面的逻辑不成立时,arready的值必然为1,所以前面的arready删除即可。ram_renc发起读的场景也是两个:第一种,ar接口握手成功,发起当前ar接口对应的读;第二种,前一拍的有请求(arvalid_ff == 1'b1)且这一拍读出的值没有被接收(rready == 1'b0)。进而,ram_addr的选择也就顺理成章。

最后是输出的信号:

//to r-port
assign rvalid    = ram_renc_ff;
assign rdata     = ram_rdata;

这个没啥好解释的。

测试波形

在测试波形中,我在initial块中把ram的每一个地址都赋值为地址号,然后进行顺序的读取和随机的反压,rhand_en = rvalid && rready:

目测功能是没有问题的。

在之后的博文中我想要分析下这两种结构的优劣和时序优化的方向,今天太晚了先睡了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

尼德兰的喵

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

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

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

打赏作者

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

抵扣说明:

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

余额充值