Systemverilog实现参数化的Round-Robin Arbiter Tree
本篇内容涉及的rtl代码为开源组织PLUP的common cell仓库中的源代码,本文只是对其进行些许解读。源码链接如下:[https://github.com/pulp-platform/common_cells/blob/dc555643226419b7a602f0aa39d449545ea4c1f2/src/rr_arb_tree.sv]
“想要快速提升编程能力的一个捷径是阅读优秀的源码” —— 忘记谁说的了
简介
- 首先Round Robin是考虑到公平性的一种仲裁算法。
- 基本思路:当一个req得到了grant许可之后,它的优先级在下一次仲裁时就会调整为最低
- 目的:每个req的优先级不固定,在被grant之后降至最低,保证所有req都能轮流被grant。
- 范例代码:PLUP开源仓库的common cell中的rr_arb_tree IP
功能
- 支持外部输入优先级
- 支持req锁存
- 内部优先级支持两种模式,一种是自动调整轮询顺序, 另一种是固定轮询顺序
代码分析
- 外部输入优先级:
if (ExtPrio) begin : gen_ext_rrassign rr_q = rr_i;assign req_d = req_i;end else begin : gen_int_rr...end
如果使能了ExtPrio参数,则最高优先级序号rr_q将由输入的rr_i指定。
这里的rr_q是最高优先级的index, 例如输入的req序列有8bit, 我们希望初始时第3个req源具有最高优先级,则只需要把ExtPrio宏打开,并给rr_i输入3’d2即可。
选择外部优先级时不支持输入锁存和调整轮询顺序,也就是说此时该模块需要依赖外部来调整优先级,模块只会根据输入的优先级输出仲裁结果。
- req锁存:
if (LockIn) begin : gen_locklogic lock_d, lock_q;logic [NumIn-1:0] req_q;assign lock_d = req_o & ~gnt_i;assign req_d = (lock_q) ? req_q : req_i;always_ff @(posedge clk_i or negedge rst_ni) begin : p_lock_regif (!rst_ni) beginlock_q <= '0;end else beginif (flush_i) beginlock_q <= '0;end else beginlock_q <= lock_d;endendend
- req_i中存在1,也就是有待仲裁的request时,如果仲裁开始信号gnt_i还没拉高,那么会锁存此时的request序列,所以仲裁结果也不会改变。
- 直到仲裁开始信号gnt_i拉高后,才开始输出当前的request输入序列的仲裁结果
- 简单来说就是gnt_i信号为低, 但是有req请求时锁存上一次的仲裁结果。
3. 自动调整轮询顺序:
if (FairArb) begin : gen_fair_arblogic [NumIn-1:0] upper_mask, lower_mask;idx_t upper_idx, lower_idx, next_idx;logic upper_empty, lower_empty;for (genvar i = 0; i < NumIn; i++) begin : gen_maskassign upper_mask[i] = (i > rr_q) ? req_d[i] : 1'b0;assign lower_mask[i] = (i <= rr_q) ? req_d[i] : 1'b0;endlzc #(.WIDTH ( NumIn ),.MODE ( 1'b0 )) i_lzc_upper (.in_i ( upper_mask ),.cnt_o ( upper_idx ),.empty_o ( upper_empty ));lzc #(.WIDTH ( NumIn ),.MODE ( 1'b0 )) i_lzc_lower (.in_i ( lower_mask ),.cnt_o ( lower_idx ),.empty_o ( /*unused*/ ));assign next_idx = upper_empty ? lower_idx : upper_idx;assign rr_d = (gnt_i && req_o) ? next_idx : rr_q;
- 通过FairArb参数使能自动调整轮询顺序。
- 如下图所示,假设此时rr=1, 也就是第2个req为最高优先级。构造两个mask,upper_mask过滤出第3-8个req, low_mask过滤出第1-2个req. 两组mask分别求第一个1所在的位置。如果upper mask中存在1,则下一个最高优先级就是upper mask中第一个1的index;如果upper mask中没有1, 则下一个最高优先级就是low mask组中的第一个1的index。
- 当仲裁开始信号gnt_i拉高并且req给出了结果后,本次的仲裁结束,就会将rr_d赋值为新的next_rr
Round-Robin Arbiter Tree-autorr
- 仲裁器的树型实现:
localparam int unsigned NumLevels = unsigned'($clog2(NumIn));
idx_t [2**NumLevels-2:0] index_nodes; // used to propagate the indices
DataType [2**NumLevels-2:0] data_nodes; // used to propagate the data
logic [2**NumLevels-2:0] gnt_nodes; // used to propagate the grant to masters
logic[2**Nu mLevels-2:0] req_nodes; // used to propagate the requests to slave
// the final arbitration decision can be taken from the root of the tree
assign req_o = req_nodes[0];
assign data_o = data_nodes[0];
assign idx_o = index_nodes[0];assign gnt_nodes[0] = gnt_i;
// arbiter tree
for (genvar level = 0; unsigned'(level) < NumLevels; level++) begin : gen_levelsfor (genvar l = 0; l < 2**level; l++) begin : gen_level// local select signallogic sel;// index calcslocalparam int unsigned Idx0 = 2**level-1+l;// current nodelocalparam int unsigned Idx1 = 2**(level+1)-1+l*2;//// uppermost level where data is fed in from the inputsif (unsigned'(level) == NumLevels-1) begin : gen_first_level// if two successive indices are still in the vector...if (unsigned'(l) * 2 < NumIn-1) begin : gen_reduceassign req_nodes[Idx0] = req_d[l*2] | req_d[l*2+1];// arbitration: round robinassign sel = ~req_d[l*2] | req_d[l*2+1] & rr_q[NumLevels-1-level];assign index_nodes[Idx0] = idx_t'(sel);assign data_nodes[Idx0] = (sel) ? data_i[l*2+1] : data_i[l*2];assign gnt_o[l*2] = gnt_nodes[Idx0] & (AxiVldRdy | req_d[l*2]) & ~sel;assign gnt_o[l*2+1] = gnt_nodes[Idx0] & (AxiVldRdy | req_d[l*2+1]) & sel;end// if only the first index is still in the vector...if (unsigned'(l) * 2 == NumIn-1) begin : gen_firstassign req_nodes[Idx0] = req_d[l*2];assign index_nodes[Idx0] = '0;// always zero in this caseassign data_nodes[Idx0] = data_i[l*2];assign gnt_o[l*2] = gnt_nodes[Idx0] & (AxiVldRdy | req_d[l*2]);end// if index is out of range, fill up with zeros (will get pruned)if (unsigned'(l) * 2 > NumIn-1) begin : gen_out_of_rangeassign req_nodes[Idx0] = 1'b0;assign index_nodes[Idx0] = idx_t'('0);assign data_nodes[Idx0] = DataType'('0);end//// general case for other levels within the treeend else begin : gen_other_levelsassign req_nodes[Idx0] = req_nodes[Idx1] | req_nodes[Idx1+1];// arbitration: round robinassign sel = ~req_nodes[Idx1] | req_nodes[Idx1+1] & rr_q[NumLevels-1-level];assign index_nodes[Idx0] = (sel) ?idx_t'({1'b1, index_nodes[Idx1+1][NumLevels-unsigned'(level)-2:0]}) :idx_t'({1'b0, index_nodes[Idx1][NumLevels-unsigned'(level)-2:0]});assign data_nodes[Idx0] = (sel) ? data_nodes[Idx1+1] : data_nodes[Idx1];assign gnt_nodes[Idx1] = gnt_nodes[Idx0] & ~sel;assign gnt_nodes[Idx1+1] = gnt_nodes[Idx0] & sel;endend
end
- 初看这段代码有点吓人,两层for genvar外加这么多if生成语句。但是实际上可以暂时先忽略第2和第3个if。
- 这段代码主要实现了几个功能:
- 根据输入的req_i输出req_o. req_o其实就是req_i按位或,只是用二叉树关键路径更短。
- 根据rr_q, 也就是当前最高优先级的index生成sel选择信号。sel信号表示每次二叉时选左边还是右边。下图就是生成req_node和sel信号的一个例子,其中当前的rr_q = ‘b001.
- 根据sel信号生成gnt_o仲裁信号,gnt_o是onehot格式的。根据每一层的sel信号,可以逐步将gnt_i信号顺着二叉树放到gnt_o中对应的bit位置,下图是一个实际例子:
- 在生成gnt_o中,实际也顺便根据sel信号生成了最终仲裁结果的index. 如果需要req源还附带数据通道,需要给出仲裁后的data,则也可以顺便逐级送出被仲裁的data到data_o。
- 在for genvar循环的第一个if,也就是gen_first_level逻辑中,除了主要代码段gen_reduce之外,还有两个if,分别是gen_first和gen_out_of_range两个生成器。
- gen_first:由于二叉树的输入需要是2N的格式,才能正常往下(上)生长,所以当输入req数不是2N时,就需要进行特殊处理。例如req个数为7时,则树有三层。最顶层有7个节点,二分后第七个一定会落单,所以gen_first判断当前的节点是否是这种情况,也就是if (unsigned’(l) * 2 == NumIn-1),如果匹配的话,这个落单的节点将单独向下生长节点。
- gen_out_of_range: gen_first是处理落单的节点,而gen_out_of_range就是处理多余的节点。例如req个数为5,NumLevels = unsigned’($clog2(NumIn))=3, 树仍然有三层,此时第一层除了有第五个落单节点之外,在for循环遍历时还会遍历到7,8两个不存在的节点,因此需要虚构出这两个节点并将其赋为0.
知乎:flappylyc - 知乎 (zhihu.com)
博客园: love小酒窝 - 博客园 (cnblogs.com)
CSDN:love小酒窝的CSDN博客-IC领域博主
公众号已开,了解更多相关内容可以扫一扫下方二维码~
Systemverilog实现参数化的Round-Robin Arbiter Tree相关推荐
- 仲裁器设计(二)-- Round Robin Arbiter 轮询调度算法
作者:李虹江 原文:https://mp.weixin.qq.com/s/r-nckE5nGz9mc5KqjPXKYg 本文授权转自IC加油站微信号,未经作者授权,严禁二次转载. 上一篇老李讲了固定优 ...
- 【数字IC/FPGA】仲裁器进阶--Round Robin Arbiter
Round Robin Arbiter 固定优先级的缺点是:每个模块的优先级自始至终是固定不变的,这在某种程度上来说是不公平的,Round Robin就是考虑到公平性的一种仲裁算法.其基本思路是,当一 ...
- Verilog权重轮询仲裁器设计——Weighted Round Robin Arbiter
前两篇讲了固定优先级仲裁器的设计.轮询仲裁器的设计 Verilog固定优先级仲裁器--Fixed Priority Arbiter_weixin_42330305的博客-CSDN博客 Verilog轮 ...
- Verilog轮询仲裁器设计——Round Robin Arbiter
上篇讲了固定优先级仲裁器的设计,并给出了指定最高优先级的实现方法 Verilog固定优先级仲裁器--Fixed Priority Arbiter_weixin_42330305的博客-CSDN博客 轮 ...
- 支持N个request 的 round robin arbiter
1. 传统方法 状态机如下(三个request) 显然随着request增加,状态机会变得异常复杂,难于管理. 针对这种情况,提出了一种改良的方法: 从定义开始: 在每个cycle,只有一个maste ...
- round robin arbiter 轮询仲裁器设计
前言 仲裁器Arbiter是数字设计中非常常见的模块,应用也非常广泛.定义就是当有两个或两个以上的模块需要占用同一个资源的时候,我们需要由仲裁器arbiter来决定哪一个模块来占有这个资源.一般来说, ...
- Round Robin 算法
什么是Round Robin? 先来看和他相近的名词,轮询调度算法(Round-Robin Scheduling) 轮询调度算法的原理是每一次把来自用户的请求轮流分配给内部中的服务器,从1开始,直到N ...
- round robin权重轮循算法实现
为什么80%的码农都做不了架构师?>>> 先上代码,采用php脚本语言 <?php/* * Copyright (C) FatHong*//* 数据初始化,weight: ...
- Educational Codeforces Round 25 G. Tree Queries
题目链接:Educational Codeforces Round 25 G. Tree Queries 题意: 给你一棵树,一开始所有的点全是黑色,有两种操作. 1 x 将x这个点变为黑色,保证第一 ...
最新文章
- 重写equals就必须重写hashCode的原理分析
- linux perf - 性能测试和优化工具
- boost::boyer_myrvold_params::kuratowski_subgraph用法的测试程序
- java没有打印mysql日志_0216 aop和打印数据库执行日志
- android开发环境的调研
- 一个简单的txt读取与导出
- VMware资源集合,分享一波
- 联想计算机phoenix award bios,phoenix-Award BIOS
- 微信小程序直播是怎么做的
- win10常用快捷键合集
- 【人工智能】AI竞赛,到底有什么价值?
- ContextCapture数据处理及电脑配置常见问题汇总
- MySQL基础 - 连接查询
- 阳春三月来几个python基础吧
- 【题解】【PTA里的Python题库】7-1 身份证校验_python
- 手Q支付(QQ钱包)
- 展望2020:游戏本地化
- [机器学习与数据分析] 数据分析常用方法
- 洛谷 P3426 [POI2005]SZA-Template
- Linux开发工具--(编辑器,编译器,调试器)