握手协议(pvld/prdy或者valid-ready或AXI)中ready打拍技巧
内容提要
- ready打拍的问题
- 用FIFO的思路去解决
- 用Buffer的思路去解决
问题提出:ready时序如何优化?
在valid/ready 握手协议中,valid 与 data的时序优化比较容易理解,(不熟悉valid/ready协议或者valid打拍方法的)大家可以参考上次推送(握手协议(pvld/prdy或者valid-ready或AXI)中Valid及data打拍技巧)。
但是有时候,关键路径是在ready信号上,如何对ready信号打拍呢?
首先将把目标设计想象成一个黑盒子,如图1所示,我们的目标是将READY_DOWN通过打拍的方法获得时序优化。
(图1)
尝试直接对ready打一拍
READY_UP <= READY_DOWN;
VALID_DOWN = valid_up;
(仅示例,非verilog代码。下同)
这样是行不通的。
一个简单的例子(case 1)就是你让READY_DOWN像一个时钟一个,间隔一个cycle起来一次,那么VALID_UP && READY_UP 与 VALID_DOWN && READY_DOWN无法同步,数据无法传输下去。
思路:将其分解成两个interfaces
将ready打拍的逻辑想象成一个黑盒子,去分析这个黑盒子的设计,分为up interface 和down interface将问题细化:
- up interface 有VALID_UP, DATA_UP, READY_UP
- down interface 有VALID_DOWN, DATA_DOWN, READY_DOWN
可以总结成下面的样子:
READY_UP <= READY_DOWN; //or READY_UP = function(READY_DOWN_next);
transfer_up = VALID_UP && READY_UP;
transfer_down = VALID_DOWN && READY_DOWN;
如果去解决刚才例子(case 1),那么这个黑盒子:
当READY_UP为高的时候,可以接受数据;
当READY_DOWN为高的时候,如果我们有数据可发的话,我们可以向downstream发送数据;
是不是很像一个FIFO?
用FIFO去解决
将一个FIFO插在黑盒子这里,那么就会变成这样子:
(图2)
VALID_UP/READ_YUP ==> FIFO ==> VALID_DOWN/READY_DOWN
也就是:
VALID_UP = fifo_push_valid;
READY_UP = fifo_push_ready;
VALID_DOWN = fifo_pop_valid;READY_DOWN = fifo_pop_ready;
现在问题变成了:如何设计这个FIFO呢?
- 这个FIFO深度多少?
- 怎么设计,能够保证READY_UP是READY_DOWN打过一拍的呢?
FIFO设计多深?
因为本身valid/ready协议是反压协议(也就是READY_UP为0的时候,不会写FIFO,而不会导致FIFO溢出)而且此处的读写时钟是同一个时钟,是一个同步FIFO,所以FIFO深度是1或者2就足够了。
深度是1还是2要看极端情况下需要存储几笔数据。
简单分析可以知道,只有一种情况会去向FIFO中存储数据:
- READY_UP是1,可以从upstream接收数据
- 同时READY_DOWN是0,不可以向downstream发送数据
这种情况在极端情况下最多维持多久呢?
答案是:一个周期
因为如果cycle a 时:READY_DOWN=0,那么cycle a+1时,READY_UP变为0了,开始反压,所以只用存一个数就够了。
所以设计为一个深度为1的FIFO就可以了。
深度为1的FIFO有很多特点,设计起来比较简单。比如:wr_ptr/rd_ptr始终指向地址0,所以我们可以删掉wr_ptr和rd_ptr,因为是一个常值0。
简单的depth-1 FIFO实现
使用depth-1 FIFO传输数据,可以这样设计:
// Depth 1 FIFO.
always @(posedge CLK)beginif(RESET) begin fifo_line_valid <= 0; fifo_push_ready <= 1'b0; fifo_data <= {WIDTH{1'b0}}; endelse beginfifo_push_ready <= fifo_pop_ready;if (fifo_push_ready) beginfifo_line_valid <= fifo_push_valid;fifo_data <= DATA_UP;endelse beginif (fifo_pop_valid && fifo_pop_ready)fifo_line_valid <= 1'b0;else fifo_line_valid <= fifo_line_valid;endend
end
assign fifo_push_valid = VALID_UP;
assign fifo_pop_valid = fifo_line_valid;
assign fifo_pop_ready = READY_DOWN;
assign READY_UP = fifo_push_ready;
assign VALID_DOWN = fifo_line_valid;
assign DATA_DOWN = fifo_data;
这解决了READY打拍的问题。但是这里有一些可以改进的地方,比如:
- 是不是可以挤掉多于的气泡?
- 在FIFO为空的时候,数据是不是可以直接bypass FIFO?
无气泡传输
关于无气泡传输,可以参考上一篇推送(握手协议(pvld/prdy或者valid-ready或AXI)中Valid及data打拍技巧)。具体的说,就是既然你这里有个深度为1的FIFO了,那么我是不是可以利用起来,放点数据啊……
当READY_DOWN持续是0的时候,READY_UP依然可以有一个cycle去接收一笔数据,把FIFO资源利用起来:
fifo_no_push = ~(fifo_push_valid && fifo_push_ready);
fifo_push_ready <= (fifo_pop_ready||(fifo_no_push && ~fifo_line_valid));
同样的原因,在RESET情况下,READY_UP可以为1,可以将复位值修改。
那么FIFO穿越呢?
FIFO穿越
考虑一个特殊情况(case 2):
假设READY_DOWN在复位之后始终为1,
然后某个时刻开始VALID_UP为1了。
是不是每个周期,数据都可以直接传下来而不用进入FIFO,即使READY_DOWN打过一拍?
换句话说:如果READY_UP=1, READY_DOWN=1, FIFO是空的这种情况下,数据可以直通。
- 上文特殊情况(case 2),READY_DOWN/READY_UP一直是1,显然可以。
- READY_UP从0到1的跳变:READY_DOWN也会在前一周期有一个从0到1的跳变。在READY_DOWN为0时,有一笔数据存到FIFO里边(无气泡传输);当READY_DOWN在时刻a从0变到1时,READY_UP在时刻a+1也会从0变为1。如果此时READY_DOWN也为1,可以直通,不用进入FIFO。也就是:
assign pass_through = READY_UP && READY_DOWN && ~fifo_line_valid;
assign VALID_DOWN = pass_through ? VALID_UP : fifo_line_valid;
assign DATA_DOWN = pass_through ? DATA_UP : fifo_data;
注意在直通时,我们不希望数据进入FIFO:
assign fifo_push_valid = ~pass_through && VALID_UP;
将所有这些结合起来:
//---------------------------------------
// File Name : ready_flop.v
// Author : Xiangzhi Meng
// Date : 2020-06-06
// Version : 0.1
// Description :
// 1. ready_flop using one depth-1 FIFO to hold data.
//
// All rights reserved.
`timescale 1ns/1ns
module ready_flop(CLK,RESET,VALID_UP,READY_UP,DATA_UP,VALID_DOWN,READY_DOWN,DATA_DOWN);
//---------------------------------------
parameter WIDTH = 32;
//---------------------------------------
input CLK;
input RESET;
//Up stream
input VALID_UP;
output READY_UP;
input [0:WIDTH-1] DATA_UP;
//Down Stream
output VALID_DOWN;
input READY_DOWN;
output [0:WIDTH-1] DATA_DOWN;
//---------------------------------------
wire CLK;
wire RESET;
//Up stream
wire VALID_UP;
wire READY_UP;
wire [0:WIDTH-1] DATA_UP;
//Down Stream
wire VALID_DOWN;
wire READY_DOWN;
wire [0:WIDTH-1] DATA_DOWN;
reg fifo_line_valid;
wire fifo_push_valid;
reg fifo_push_ready;
wire fifo_pop_ready;
wire fifo_no_push;
wire pass_through;
wire fifo_pop_valid;
reg [0:WIDTH-1] fifo_data;
// Depth 1 FIFO.
always @(posedge CLK) begin if(RESET) begin fifo_line_valid <= 0;fifo_push_ready <= 1'b1; fifo_data <= {WIDTH{1'b0}}; end else beginfifo_push_ready <= (fifo_pop_ready||(fifo_no_push && ~fifo_line_valid));//Bubble clampping: If last cycle there's no FIFO push and//fifo_line is empty,it can be ready.if (fifo_push_ready) begin fifo_line_valid <= fifo_push_valid; fifo_data <= DATA_UP; endelse begin if (fifo_pop_valid && fifo_pop_ready)fifo_line_valid <= 1'b0; elsefifo_line_valid <= fifo_line_valid; end end
end
assign fifo_no_push = ~(fifo_push_valid && fifo_push_ready);
assign pass_through = READY_UP && READY_DOWN && ~fifo_line_valid;
assign fifo_push_valid = ~pass_through && VALID_UP;
assign fifo_pop_valid = fifo_line_valid;
assign fifo_pop_ready = READY_DOWN;
assign READY_UP = fifo_push_ready;//bypass
assign VALID_DOWN = pass_through ? VALID_UP : fifo_line_valid;
assign DATA_DOWN = pass_through ? DATA_UP : fifo_data;
endmodule
(注:代码未经详细验证)
换一种思路
经过上面对FIFO的分析,我们可以总结起来,主要是以下几点:
- 加入一个深度为1的同步FIFO,这个FIFO在READY_DOWN为0,且READY_UP为1时暂存一个数据;
- 在READY_DOWN从0->1时,FIFO里边的数据先输出到下级;
- 如果READY_DOWN继续为1,数据可以绕过FIFO直通;
深度为1的FIFO(不管是同步还是异步FIFO),都是一个特殊的逻辑单元。
对于深度为1的同步FIFO,其实就是一拍寄存器打拍。
所以,我们可以这样重新设计:
- 加一级寄存器作为buffer(实际上就是深度为1的FIFO)
- 当以下条件满足,这一级寄存器会暂存一级数据:
2.1 READY_DOWN是0,并且
2.2 READY_UP是1,并且
2.3 VALID_UP是1;
也就是:
assign store_data = VALID_UP && READY_UP && ~READY_DOWN;
- 当READY_UP是1时,数据可以直接暴露在下级接口:READY_UP为1时,BUFFER中一定是空的,因为上一个时钟周期数据已经排空了。也就是:
assign VALID_DOWN = READY_UP ? VALID_UP : buffer_valid;
这其实就是上面的FIFO直通模式。同样我们可以挤掉气泡:
READY_UP <= READY_DOWN || ((~buffer_valid) && (~store_data));
把这所有的总结起来:
//---------------------------------------
// File Name : ready_flop.v
// Author : Xiangzhi Meng
// Date : 2020-06-06
// Version : 0.1
// Description :
// 1. ready_flop using one buffer to hold data.
//
// All rights reserved.
`timescale 1ns/1ns
module ready_flop (CLK,RESET,VALID_UP,READY_UP,DATA_UP,VALID_DOWN,READY_DOWN,DATA_DOWN);
//---------------------------------------
parameter WIDTH = 32;
//---------------------------------------
input CLK;
input RESET;
//Up stream
input VALID_UP;
output READY_UP;
input [0:WIDTH-1] DATA_UP;
//Down Stream
output VALID_DOWN;
input READY_DOWN;
output [0:WIDTH-1] DATA_DOWN;
//---------------------------------------
wire CLK;
wire RESET;
//Up stream
wire VALID_UP;
reg READY_UP;
wire [0:WIDTH-1] DATA_UP;
//Down Stream
wire VALID_DOWN;
wire READY_DOWN;
wire [0:WIDTH-1] DATA_DOWN;
wire store_data;
reg [0:WIDTH-1] buffered_data;
reg buffer_valid;
//---------------------------------------
//buffer.
assign store_data = VALID_UP && READY_UP && ~READY_DOWN;
always @(posedge CLK)if (RESET) buffer_valid <= 1'b0;else buffer_valid <= buffer_valid ? ~READY_DOWN: store_data;
//Note: If now buffer has data, then next valid would be ~READY_DOWN:
//If downstream is ready, next cycle will be un-valid.
//If downstream is not ready, keeping high.
// If now buffer has no data, then next valid would be store_data, 1 for store;
always @(posedge CLK)if (RESET) buffered_data <= {WIDTH{1'b0}};else buffered_data <= store_data ? DATA_UP : buffered_data;always @(posedge CLK) beginif (RESET) READY_UP <= 1'b1; //Reset can be 1.else READY_UP <= READY_DOWN || ((~buffer_valid) && (~store_data)); //Bubule clamppingend
//Downstream valid and data.
//Bypass
assign VALID_DOWN = READY_UP? VALID_UP : buffer_valid;
assign DATA_DOWN = READY_UP? DATA_UP : buffered_data;
endmodule
(注:代码未经详细验证)
其他
- 我在电脑上简单跑了两个波形,FIFO方法和Buffer方法结果是一样的。
- 用FIFO去隔离开上下两个interface思考,比较容易想明白。
- 无气泡传输、FIFO直通这两个小feature拿掉,也可以工作、也是能实现READY_DOWN时序优化的设计目标的。
---------
电路设计心得,欢迎关注“数字逻辑电路小站”
握手协议(pvld/prdy或者valid-ready或AXI)中ready打拍技巧相关推荐
- AXI中READY与VALID之间握手关系
读通道 单箭头为可以,双箭头为必须满足. 1.主机在发起ARVALID之前必须不等待从机发起ARREADY,即主机发起ARVALID不依赖ARREADY: 2.从机可以等待(也可以不等待)主机发起AR ...
- 数字IC设计verilog编写——4流水线握手协议
1 流水线与握手协议 流水线在电路设计过程中,是必不可少的一种实现方式,其可以提高电路的性能,当我们需要设计高速电路的时候,就需要用到流水线: 流水线的设计,就是指对延时较大的组合逻辑插入寄存器,把较 ...
- 数字IC验证:总线握手协议(VALID/READY握手机制)
写在前面: 最近学习总线协议,涉及握手,因此整理本文.若内容有疑惑或错误之处,请在评论区指出,感谢! 文章目录 1 什么是"握手"? 2 VALID/READY握手机制 3 Cas ...
- 数字芯片设计中常见的三个握手协议
本篇文章转载自一道Nvidia的面试题 Valid-Ready Handshake Valid-Ready是非常常见的握手协议,我们熟悉的AXI总线的核心就是Valid-Ready协议.Valid-R ...
- ESP32与STM32的SPI半双工通信与握手协议讲解(附代码)
说在最前:下面把主要代码都已经附上,如果有人想要完整的工程文件(包括ESP-IDF和KEIL5和STM32CUBEMX的工程)请移步下载链接: 完整资源下载 如果你自己写的,有bug无法解决,请参考 ...
- FPGA中简单的握手协议
握手协议一种解决总线同步问题的方法是使用一个保持寄存器和握手信号",这也就是"先异步暂存,后同步写入"的方法握手协议一种解决总线同步问题的方法是使用一个保持寄存器和握手信 ...
- 转:SSL 握手协议详解
SSL 握手协议详解 RSA作为身份认证,ECDHE来交换加密密钥,AES/DES等作为加密. 如果RSA来加解密,那么身份认证后,直接用认证后的RSA公钥解密.不需要再额外交换加密密钥了. 相关报文 ...
- SSL 握手协议详解
这里重点介绍一下服务端的验证和密钥交换.这个阶段的前面的(a)证书 和(b)服务器密钥交换是基于密钥交换方法的.而在SSL中密钥交换算法有6种:无效(没有密钥交换).RSA.匿名Diffie-Hell ...
- ssl双向认证_SSL握手协议不清楚?vTrus为你讲解其详细流程
SSL(Secure Socket Layer)安全套接字协议是运行在应用层和TCP层之间的安全机制.保证上层应用数据传输的保密性.完整性以及传输双发身份的合法性. 传输加密性:握手协议定义会话密钥后 ...
最新文章
- TensorFlow超级指南 | 你能想到的TF教程和资源都在这里(附链接视频)
- 【风险管理】风控决策系统
- Java技术依然备受追捧,主要学习内容有哪些?
- html表单php连接mysql数据库_使用HTML表单和PHP更新MySQL
- golang字符串转数字
- css叠层_CSS 中重要的层叠概念
- objective-c教程_Objective-C Hello世界教程
- Network | parity bit
- cad2017插入电气符号_电气电气CAD图形符号大全.pdf
- message计算机英语,计算机英语词汇解释汇总
- wps云文档 word文档发送错误报告怎么办?
- 【delete用法 与 object(对象)的创建】
- 获取input输入值和获取form表单中的组件输入值区别
- 使用Workrave帮助防止腕管问题
- 软件测试-Mysql数据库3
- 转载-解释路由包ping的情况
- fastJson深拷贝
- python上网_西电免流量限制上网攻略!Python实现PPPOE攻击工具,秒杀拨号上网
- Mac 如何修改hosts文件
- (调色软件)DaVinci Resolve 17 达芬奇新版调色系统软件
热门文章
- Windows Server 2012远程默认端口3389的修改
- 1660 super安装tensorflow1.15
- matlab的死区环节,基于SIMULINK对非线性系统死区环节进行仿真
- flyingsaucer进行html文件转图片和pdf
- 曾经懵懂少年,曾经年少轻狂
- 【渝粤题库】广东开放大学 风险投资 形成性考核
- Praat脚本-004 | 替换标注内容
- 《中国程序化广告技术生态图》2015年三月号更新发布
- 2019最新升级全能版vbox硬件级虚拟机系统 vm去虚拟化修改信息工具 批量启动克隆 virtualbox CPA网赚挂机电商
- 用Notepad++实现文本比较