【芯片前端】根据数据有效选择输出的握手型FIFO结构探究

news/2024/5/18 23:43:38/文章来源:https://blog.csdn.net/moon9999/article/details/126692866

前言

之前要做一个一读多写的fifo,也就是master写入数据到fifo中,多个slave读取数据,结构如下图所示:

由于slave需要的数据一致,fifo内只需要例化一个ram以节约空间。这个fifo的具体结构下次博客中再来讨论。在这个fifo之后,又衍生出一个新的需求,就是master写入的数据并非每个slave都需要读取,而是需要甄选,比如trc0是slave0/1/2均需要读取,trc1只有slave1/2需要slave0将知丢弃即可。这个需求也不难,在fifo的出口根据每个slave_en对握手进行处理即可。

而后,叒衍生了一个需求,就是如果某一slave连续不需要数据,那么需要直接读出下一个需要的数据,中间不要有空泡,对于某一个slave来说简单的示意图如下:

归结一下需求(不考虑一对多的场景,一对多只需要在一对一的外面裹一些逻辑,暂不展开), 就是fifo写入的数据不是每一个都需要输出,只需要输出需要的数据(令power=1为需要的数据),那么我们由需求得到了下面的接口:

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

代码实现

这个结构的难点在于,读指针不是连续加1,而是需要跳跃性的去找下一个有效的点:

因此我最开始的做法是写一个for-if结构,if找到了下一个power就停止否则一直找到wr_ptr所在的位置,而确实我也完成了RTL代码并确认了这个写法可以综合。但是后来我进一步的思考,发现这就是一个”找首1”的的结构:

 而“找首1”的结构是有固定套路的因此又往前推进了一点点。接下来还是继续思考这个问题,我记起来为什么我会写“找首1”呢?因为之前写了一个rr调度的代码,里面需要有这个逻辑:

【芯片前端】与RR调度的相爱相杀——verilog实现RR调度器

 因此我突然灵光乍现,这东西不就是个RR调度吗?再仔细看这个结构,实际上每个power为1对应的项就是需要被调度的一路,为0的项等价于没有调度请求。rd_ptr从0 -> 2的过程,实际就是使第1项被丢弃的过程。

 那么有一个关键问题需要解决,是用keep型的rr调度还是非keep型的呢?keep型与非keep型主要的差别在于ack返回前调度逻辑看到的req是否会改变。在这个场景下个人认为都可以的,因为fifo本身读写指针的控制机智(读指针不能跨越写指针,写指针也不能跨越读指针)以及数据输入的顺序,应该是不用专门使用keep型的调度器。因此我选择了非keep型的调度器。rr调度的接口与行为就不赘述了,直接分析下如何组织外部的逻辑:

//==================================================================
//bitmap维护
//==================================================================
reg  [BM_WD -1:0]power_bitmap_q;
wire             power_bitmap_en = in_hand_en || out_inner_hand_en;
wire [BM_WD -1:0]power_bitmap_d;
wire [BM_WD -1:0]power_bitmap_in;
wire [BM_WD -1:0]power_bitmap_out;
wire [BM_WD -1:0]power_bitmap_waddr;
wire [BM_WD -1:0]power_bitmap;assign power_bitmap_in  =  ({{(BM_WD-1){1'b0}}, (in_hand_en & in_power & 1'b1)} << waddr);//0010
assign power_bitmap_out = ~({{(BM_WD-1){1'b0}}, (out_inner_hand_en & 1'b1)}              << raddr);//1011
assign power_bitmap_d   = (power_bitmap_q & power_bitmap_out) | power_bitmap_in;always @(posedge clk or negedge rst_n)beginif(~rst_n)    power_bitmap_q <= {BM_WD{1'b0}};else if(power_bitmap_en) power_bitmap_q <= power_bitmap_d;
endassign power_bitmap_waddr = ({{(BM_WD-1){1'b0}}, 1'b1} << waddr);
assign power_bitmap       = power_bitmap_q | power_bitmap_waddr;

说一下大概的一个思路:

  1. 有数据写入时(in_hand_en==1),把对应power根据rd_addr写到对应的req位置上去;
  2. 有数据被读出时(out_inner_hand_en),把对应req的位置清为0,因为握手型(我这个)fifo的不会发生同一拍对同一个位置进行读写,因此没有竞争;
  3. waddr所在的那个位置,req必须是1,要不raddr直接跨过去waddr索引到后面肯定是不行的,所以最终的bitmap(也就是req)必须要或一下;

因此进一步例化rr调度器就可以了:

wire [BM_WD -1:0]grant;
rr_dispatch #(.WD(BM_WD), .KEEP_MODE(0))
u_rr
(.clk(clk),.rst_n(rst_n),.req(power_bitmap),.ack(out_inner_hand_en),.grant(grant)
);

通过grant来获得raddr:

//==================================================================
//读出计数器
//==================================================================
reg  [DP_WD   :0]raddr_d;
wire             renc;always @* begin: RADDR_Dinteger i;for(i=0; i<BM_WD; i=i+1)beginif(grant[i] == 1'b1) beginraddr_d = i;endend
endassign raddr = raddr_d;

最后的输出逻辑要进一步组织下:

//==================================================================
//输出逻辑
//==================================================================
wire   inner_out_real  = power_bitmap[raddr];
assign inner_out_valid = (raddr != waddr);
assign inner_out_ready = out_ready || (~inner_out_real);
assign out_valid       = inner_out_valid && inner_out_real;
assign in_ready        = !((raddr[DP_WD -1:0] == waddr[DP_WD -1:0]) && (raddr[DP_WD] != waddr[DP_WD]));

什么时候才是真正有效的输出呢(out_valid = 1),必须是power_bitmap[raddr]==1(这里我认为用power_bitmap_q[raddr]更为准确,不过下面用raddr != waddr做了处理,逻辑上也是没有问题的),同时raddr != waddr。对于in_ready而言,和普通的握手型fifo没有区别。

仿真结果

截取了部分时间的仿真波形,可以看到如d/11/16/18这些数据并没有输出,且输出数据ready可接时没有空泡。

完整代码

module bypass_fifo_new #(parameter DEPTH = 8,parameter WIDTH = 128
)(input 				clk,input 				rst_n,input  			    in_valid,input  [WIDTH -1:0] in_data,input               in_power,output 			    in_ready,output			    out_valid,output [WIDTH -1:0] out_data,input  			    out_ready
);localparam DP_WD = DEPTH == 1 ? 1 : $clog2(DEPTH);
localparam BM_WD = DEPTH*2;//==================================================================
//公用信号
//==================================================================
wire inner_out_valid;
wire inner_out_ready;wire in_hand_en        = in_valid && in_ready;
wire out_hand_en       = out_valid && out_ready;
wire out_inner_hand_en = inner_out_valid && inner_out_ready;reg  [DP_WD   :0]waddr;
//reg  [DP_WD   :0]raddr;
wire [DP_WD   :0]raddr;//==================================================================
//写入计数器
//==================================================================
wire             wenc;
wire             waddr_d_h;
wire [DP_WD -1:0]waddr_d_l;
assign wenc = in_hand_en;
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)beginif(~rst_n)    waddr <= 0;else if(wenc) waddr <= {waddr_d_h, waddr_d_l};
end//==================================================================
//bitmap维护
//==================================================================
reg  [BM_WD -1:0]power_bitmap_q;
wire             power_bitmap_en = in_hand_en || out_inner_hand_en;
wire [BM_WD -1:0]power_bitmap_d;
wire [BM_WD -1:0]power_bitmap_in;
wire [BM_WD -1:0]power_bitmap_out;
wire [BM_WD -1:0]power_bitmap_waddr;
wire [BM_WD -1:0]power_bitmap;assign power_bitmap_in  =  ({{(BM_WD-1){1'b0}}, (in_hand_en & in_power & 1'b1)} << waddr);//0010
assign power_bitmap_out = ~({{(BM_WD-1){1'b0}}, (out_inner_hand_en & 1'b1)}              << raddr);//1011
assign power_bitmap_d   = (power_bitmap_q & power_bitmap_out) | power_bitmap_in;always @(posedge clk or negedge rst_n)beginif(~rst_n)    power_bitmap_q <= {BM_WD{1'b0}};else if(power_bitmap_en) power_bitmap_q <= power_bitmap_d;
endassign power_bitmap_waddr = ({{(BM_WD-1){1'b0}}, 1'b1} << waddr);
assign power_bitmap       = power_bitmap_q | power_bitmap_waddr;//==================================================================
//
//==================================================================
wire [BM_WD -1:0]grant;
rr_dispatch #(.WD(BM_WD), .KEEP_MODE(0))
u_rr
(.clk(clk),.rst_n(rst_n),.req(power_bitmap),.ack(out_inner_hand_en),.grant(grant)
);//==================================================================
//读出计数器
//==================================================================
reg  [DP_WD   :0]raddr_d;
wire             renc;always @* begin: RADDR_Dinteger i;for(i=0; i<BM_WD; i=i+1)beginif(grant[i] == 1'b1) beginraddr_d = i;endend
endassign raddr = raddr_d;//==================================================================
//输出逻辑
//==================================================================
wire   inner_out_real  = power_bitmap[raddr];
assign inner_out_valid = (raddr != waddr);
assign inner_out_ready = out_ready || (~inner_out_real);
assign out_valid       = inner_out_valid && inner_out_real;
assign in_ready        = !((raddr[DP_WD -1:0] == waddr[DP_WD -1:0]) && (raddr[DP_WD] != waddr[DP_WD]));//==================================================================
//数据寄存
//==================================================================
reg [WIDTH -1:0]data[DEPTH -1:0];
always @(posedge clk)beginif(wenc) data[waddr[DP_WD-1:0]] <= in_data;
end
assign out_data = data[raddr[DP_WD-1:0]];endmodule

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_5741.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Git 之 revert

转自: Git 之 revertrevert 可以撤销指定的提交内容,撤销后会生成一个新的commit。 1、两种commit: 当讨论 revert 时,需要分两种情况,因为 commit 分为两种:一种是常规的 commit,也就是使用 git commit 提交的 commit; 另一种是 merge commit,在使用 git merge 合并两…

mysql 主从备份原理

mysql 主从备份原理 1.1 用途及条件 mysql主从复制用途实时灾备,用于故障切换 读写分离,提供查询服务 备份,避免影响业务主从部署必要条件:主库开启binlog日志(设置log-bin参数) 主从server-id不同 从库服务器能连通主库2.1 主从原理在备库 B 上通过 change master 命令,…

服务端挂了,客户端的 TCP 连接还在吗?

作者:小林coding 计算机八股文网站:https://xiaolincoding.com大家好,我是小林。 如果「服务端挂掉」指的是「服务端进程崩溃」,服务端的进程在发生崩溃的时候,内核会发送 FIN 报文,与客户端进行四次挥手。 但是,如果「服务端挂掉」指的是「服务端主机宕机」,那么是不会…

[第二章 web进阶]XSS闯关-1

定义:跨站脚本(Cross_Site Scripting,简称为XSS或跨站脚本或跨站脚本攻击)是一种针对网站应用程序的安全漏洞攻击技术,是代码注入的一种。它允许恶意用户将代码注入网页,其他用户浏览网页时就会受到影响。恶意用户利用XSS代码攻击成功后,可能得到包括但不限于更高的权限、会…

K8s简介之什么是K8s

1.概述 欢迎来到K8s入门课程。Kubernetes,也被称为K8s或Kube,是谷歌推出的业界最受欢迎的容器编排器。本K8s教程由一系列关于K8s的文章组成。在第一部分,我们将讨论什么是K8s和K8s的基本概念。 本课程是专为初学者开设的,你可以零基础学习这项技术。我们将带你了解全部K8s的…

第2章 第一个Spring Boot项目

开发工具选择 工欲善其事必先利其器&#xff0c;我们进行Java项目开发&#xff0c;选择一个好的集成开发工具&#xff08;IDE&#xff09;对提高我们的开发调试效率有非常大的帮助。这里我们选择大名鼎鼎的IDEA &#xff0c;它全称 IntelliJ IDEA。 ​IntelliJ IDEA公认最好的J…

【云原生 | Kubernetes 系列】K8s 实战 如何给应用注入数据 II 将pod数据传递给容器

将pod数据传递给容器前言一、通过环境变量将 Pod 信息传递给容器1.1、用 Container 字段作为环境变量的值二、通过文件将 Pod 信息呈现给容器2.1、存储容器字段总结前言 在上一篇文章中&#xff0c;我们学习了针对容器设置启动时要执行的命令和参数、定义相互依赖的环境变量、为…

关于订单过期的监听和处理

订单过期监听和处理 业务需求 有些时候 用户发起订单 但是没有付款 这个时候一般来说 会设置一个订单过期时间 如果订单过期 则需要重新下单 问题来了 如果每过一段很小的时间就去盘一次数据库 那压力也太大了 demo 搭建 用到的 mysql mybatis plus redis rabbit mq 目录结…

【毕业设计】单片机远程wifi红外无接触体温测量系统 - 物联网 stm32

文章目录0 前言1 简介2 主要器件3 实现效果4 设计原理4.1 **MLX90614红外测温传感器**4.2 TOF10120激光测距传感器4.3 DS18B20传感器**DS18B20单总线协议**5 部分核心代码5 最后0 前言 &#x1f525; 这两年开始毕业设计和毕业答辩的要求和难度不断提升&#xff0c;传统的毕设…

精妙绝伦

精妙绝伦啊,精妙绝伦啊,大妙! 今天讨论到一个二级联动省和市在一个表中的情况, 这么一组数据,需要达成一个sql语句便能把省和市同时显示出来,愚绞尽脑汁思虑良久,未得有用之策,经同事提点,顿醍醐灌顶! 先来解释一下这串代码:Select * from TBSpace inner join TBPla…

three.js绘制地图(平面、曲面)

加载中国地图json数据 let loader = new THREE.FileLoader(); loader.load(model/chinaJson.json, function (data) {let jsonData = JSON.parse(data);initMap(jsonData); // 解析并绘制地图 });绘制曲面地图function initMap( chinaJson ) {//创建一个空对象存放对象map = ne…

Vue指令

Vue指令分为内置指令和自定义指令 内置指令 v-bind 单向绑定解析表达式&#xff0c; 简写&#xff1a; &#xff1a;xxx <div id"root">单项数据绑定&#xff1a;<input type"text" v-bind:value"name"><br></div> v…

2023秋招——快手数据研发一、二面面经

&#x1f33c;今天来总结一下快手数据研发的一、二面&#xff0c;在面试中进步&#xff0c;在总结中成长&#xff01;对往期内容感兴趣的小伙伴可以参考下面&#x1f447;&#xff1a; 链接: 2022暑期实习字节跳动数据研发面试经历-基础数仓.链接: 2022百度大数据开发工程师实…

three.js实现鼠标拾取例子

基本思路 <script> var renderer,scene,camera; var light; var raycaster,//相机->鼠标的射线mouse,//鼠标所在位置actionObject;//选中的物体 init(); animation();function init(){//渲染器//场景//相机//方向光//创建2000个立方体//创建射线//创建鼠标二维向量(圆…

epoll实现异步请求数据---以UDP为例

文章目录同步UDP请求数据的问题异步请求的模型具体的代码同步UDP请求数据的问题 不管是请求DNS资源还是其他资源。如果以串行的方式请求数据&#xff0c;也就是send以后recv阻塞等待获取数据&#xff0c;这样做的效率非常低效&#xff0c;网络延迟、服务器处理请求、再加上rec…

【C# 学习笔记 ②】C#基本语法(数组、判断和循环、字符串、枚举、结构体)

由于在自己的工作和学习过程中&#xff0c;只查看某个大佬的教程或文章无法满足自己的学习需求和解决遇到的问题&#xff0c;所以自己在追赶大佬们步伐的基础上&#xff0c;又自己总结、整理、汇总了一些资料&#xff0c;方便自己理解和后续回顾&#xff0c;同时也希望给大家带…

【我不熟悉的css】07. css命名,bem规范,跟着组件库element-ui学习组件命名

在去年&#xff0c;我总结了一篇文章&#xff0c;跟着element-ui学习css命名 【系统学习css】跟着element-ui学习css的命名_我有一棵树的博客-CSDN博客每日鸡汤&#xff0c;每一个你想要学习的念头都是未来的你向自己求救写css 最烦人的就是给class起名字了&#xff0c;这里不…

这一次,我们把AI自治数据库带到了世界人工智能大会上

9月3日,2022世界人工智能大会(WAIC)在上海圆满落幕。WAIC2022 秉持“智联世界”理念,通过线上线下联动的会展形式,汇聚顶级科学家、企业家、政府官员、专家学者、国际组织、投资人、创新团队一同探讨科技前沿话题,推动全球“共创、共建、共融、共治、共享、共赢”。WAIC …

【Python刷题篇】——Python入门 09 字典(上)

&#x1f935;‍♂️ 个人主页: 北极的三哈 个人主页 &#x1f468;‍&#x1f4bb; 作者简介&#xff1a;Python领域新星创作者。 &#x1f4d2; 系列专栏&#xff1a;《牛客题库-Python篇》 &#x1f310;推荐《牛客网》——找工作神器|笔试题库|面试经验|实习经验内推&am…

【数据结构与算法】之深入解析“乘法表中第K小的数”的求解思路与算法示例

一、题目要求 几乎每一个人都用乘法表,但是你能在乘法表中快速找到第 k 小的数字吗?乘法表是大小为 m x n 的一个整数矩阵,其中 mat[i][j] == i * j(下标从 1 开始)。给你三个整数 m、n 和 k,请你在大小为 m x n 的乘法表中,找出并返回第 k 小的数字。示例 1:输入:m =…