数字IC前端学习笔记:仲裁轮询(五)

张开发
2026/4/12 10:27:40 15 分钟阅读

分享文章

数字IC前端学习笔记:仲裁轮询(五)
相关文章数字IC前端专栏https://blog.csdn.net/weixin_45791458/category_12173698.html?spm1001.2014.3001.5482七、分组轮询前面介绍的固定优先级仲裁、公平轮询等方法基本都建立在一个前提之上那就是仲裁器面对的请求源数量不会太多或者说所有主设备都可以直接挂在同一个仲裁器下面统一竞争同一条总线。但在实际 SoC 设计中主设备数量往往并不小而且不同主设备的访问频率、业务类型和实时性要求也并不一致如果仍然把所有请求都平铺到一个仲裁器中统一做轮询一方面会使仲裁逻辑规模增大、关键路径变长另一方面也会使局部高频访问和全局公平性之间变得比较难平衡。也正因为如此在请求源较多或者系统层次较复杂时通常会采用一种更适合扩展的仲裁方式即分组轮询。所谓分组轮询可以理解为把“大仲裁”拆成“组内仲裁 组间仲裁”两层来做。也就是说先将若干主设备按照功能、位置、业务类型或者连接关系划分成多个组在每一个组内部先决定“这一组中谁有资格代表本组出去竞争”然后再由上层仲裁器在各个组之间做一次更高层的轮询。这样系统从结构上就不再是一个完全扁平的仲裁网络而是变成了一个带层次的仲裁网络。它的基本思想和分治法很像如果一次性对所有请求做统一仲裁代价太高就先在局部收敛再在全局决策。例如快组有两个用户(A,B)慢组也有两个用户(C,D)。如果所有用户都发出请求那么轮询序列为A,B,C,A,B,D,A,B,C,A,B,D ......下图中给出的正是一个典型的分组轮询思想示意。上层椭圆可以看成总线级的全局仲裁范围其中某些节点本身并不是单独的主设备而是某个子组的“代表”下层椭圆则表示某个局部组组内的几个主设备先通过局部轮询选出一个当前有效请求再把这个组请求送到上层参与更大范围的仲裁。换句话说对总线仲裁器而言它看到的并不是“所有底层主设备同时发起请求”而是“各个组是否有请求以及当前由哪个组胜出”。这种方式的好处是非常直接的原本一个 N 路仲裁问题被分解成多个较小规模的仲裁问题和一个上层较小规模的仲裁问题从硬件实现角度看组合逻辑复杂度更容易控制从系统组织角度看也更贴近很多SoC的模块化层次。当然分组轮询并不是没有代价。最需要注意的一点就是它引入了“局部公平”和“全局公平”并不完全等价的问题。如果组A中有4个主设备长期争抢而组B中只有1个主设备那么在最简单的组间公平轮询下A组和B组可能仍然各拿到差不多的组级带宽但A组内部每个主设备实际分到的带宽会远小于B组中的唯一主设备。也就是说组间公平并不必然意味着系统中每一个最底层请求源都绝对公平。这个问题在工程上通常要靠合理分组来缓解例如尽量让每个组中的主设备数量和访问特征相对接近或者进一步引入加权轮询使某些组在上层拥有更高的组权重否则就可能出现“表面上各组轮询很公平实际上组内资源分布并不均衡”的情况。两组轮询的代码及仿真结果如下。module arbiter_twogroups(clk, resetb, req_vec_groupa, end_access_vec_groupa, req_vec_groupb, end_access_vec_groupb, gnt_vec_groupa, gnt_vec_groupb); input clk; input resetb; input [1:0] req_vec_groupa; input [1:0] end_access_vec_groupa; input [1:0] req_vec_groupb; input [1:0] end_access_vec_groupb; output [1:0] gnt_vec_groupa; output [1:0] gnt_vec_groupb; reg [1:0] arbiter_state, arbiter_state_nxt; reg [2:0] gnt_vec, gnt_vec_nxt; reg [2:0] relative_req_vec; wire any_req_asserted; reg [1:0] grant_posn, grant_posn_nxt; wire any_req_asserted_slow; wire [1:0] gnt_vec_groupa; wire [1:0] gnt_vec_groupb; reg [1:0] grant_posn_slow, grant_posn_slow_nxt; parameter IDLE 2b01; parameter END_ACCESS 2b10; assign any_req_asserted (req_vec_groupa ! 0) || (req_vec_groupb ! 0); assign any_req_asserted_slow (req_vec_groupb ! 0); assign gnt_vec_groupa gnt_vec[1:0]; assign gnt_vec_groupb[0] gnt_vec[2] grant_posn_slow[0]; assign gnt_vec_groupb[1] gnt_vec[2] grant_posn_slow[1]; always(*) begin relative_req_vec {any_req_asserted_slow, req_vec_groupa[1], req_vec_groupa[0]}; case(grant_posn) 2d0: relative_req_vec {req_vec_groupa[0], any_req_asserted_slow, req_vec_groupa[1]}; 2d1: relative_req_vec {req_vec_groupa[1], req_vec_groupa[0], any_req_asserted_slow}; 2d2: relative_req_vec {any_req_asserted_slow, req_vec_groupa[1], req_vec_groupa[0]}; endcase end always(*) begin arbiter_state_nxt arbiter_state; grant_posn_nxt grant_posn; gnt_vec_nxt gnt_vec; grant_posn_slow_nxt grant_posn_nxt; case(arbiter_state) IDLE: begin if(((gnt_vec_groupa 0) (gnt_vec_groupb 0))|| (end_access_vec_groupa[0] gnt_vec_groupa[0]) || (end_access_vec_groupa[1] gnt_vec_groupa[1]) || (end_access_vec_groupb[0] gnt_vec_groupb[0]) || (end_access_vec_groupb[1] gnt_vec_groupb[1])) begin if(any_req_asserted) arbiter_state_nxt END_ACCESS; if(relative_req_vec[0]) begin case(grant_posn) 2d0: gnt_vec_nxt 3b010; 2d1:begin gnt_vec_nxt 3b100; if(grant_posn_slow[0]) begin if(req_vec_groupb[1]) grant_posn_slow_nxt 2b10; else if(req_vec_groupb[0]) grant_posn_slow_nxt 2b01; end else if(grant_posn_slow[1]) begin if(req_vec_groupb[0]) grant_posn_slow_nxt 2b01; else if(req_vec_groupb[1]) grant_posn_slow_nxt 2b10; end end 2d2: gnt_vec_nxt 3b001; endcase case(grant_posn) 2d0: grant_posn_nxt 1; 2d1: grant_posn_nxt 2; 2d2: grant_posn_nxt 0; endcase end else if(relative_req_vec[1]) begin case(grant_posn) 2d0: begin gnt_vec_nxt 3b100; if(grant_posn_slow[0]) begin if(req_vec_groupb[1]) grant_posn_slow_nxt 2b10; else if(req_vec_groupb[0]) grant_posn_slow_nxt 2b01; end else if(grant_posn_slow[1]) begin if(req_vec_groupb[0]) grant_posn_slow_nxt 2b01; else if(req_vec_groupb[1]) grant_posn_slow_nxt 2b10; end end 2d1: gnt_vec_nxt 3b001; 2d2: gnt_vec_nxt 3b010; endcase case(grant_posn) 2d0: grant_posn_nxt 2; 2d1: grant_posn_nxt 0; 2d2: grant_posn_nxt 1; endcase end else if(relative_req_vec[2]) begin case(grant_posn) 2d2: begin gnt_vec_nxt 3b100; if(grant_posn_slow[0]) begin if(req_vec_groupb[1]) grant_posn_slow_nxt 2b10; else if(req_vec_groupb[0]) grant_posn_slow_nxt 2b01; end else if(grant_posn_slow[1]) begin if(req_vec_groupb[0]) grant_posn_slow_nxt 2b01; else if(req_vec_groupb[1]) grant_posn_slow_nxt 2b10; end end 2d0: gnt_vec_nxt 3b001; 2d1: gnt_vec_nxt 3b010; endcase case(grant_posn) 2d0: grant_posn_nxt 0; 2d1: grant_posn_nxt 1; 2d2: grant_posn_nxt 2; endcase end end end END_ACCESS: begin if((end_access_vec_groupa[0] gnt_vec_groupa[0]) || (end_access_vec_groupa[1] gnt_vec_groupa[1]) || (end_access_vec_groupb[0] gnt_vec_groupb[0]) || (end_access_vec_groupb[1] gnt_vec_groupb[1])) begin arbiter_state_nxt IDLE; if(relative_req_vec[0]) begin case(grant_posn) 2d0: gnt_vec_nxt 3b010; 2d1: begin gnt_vec_nxt 3b100; if(grant_posn_slow[0]) begin if(req_vec_groupb[1]) grant_posn_slow_nxt 2b10; else if(req_vec_groupb[0]) grant_posn_slow_nxt 2b01; end else if(grant_posn_slow[1]) begin if(req_vec_groupb[0]) grant_posn_slow_nxt 2b01; else if(req_vec_groupb[1]) grant_posn_slow_nxt 2b10; end end 2d2: gnt_vec_nxt 3b001; endcase case(grant_posn) 2d0: grant_posn_nxt 1; 2d1: grant_posn_nxt 2; 2d2: grant_posn_nxt 0; endcase end else if(relative_req_vec[1]) begin case(grant_posn) 2d0: begin gnt_vec_nxt 3b100; if(grant_posn_slow[0]) begin if(req_vec_groupb[1]) grant_posn_slow_nxt 2b10; else if(req_vec_groupb[0]) grant_posn_slow_nxt 2b01; end else if(grant_posn_slow[1]) begin if(req_vec_groupb[0]) grant_posn_slow_nxt 2b01; else if(req_vec_groupb[1]) grant_posn_slow_nxt 2b10; end end 2d1: gnt_vec_nxt 3b001; 2d2: gnt_vec_nxt 3b010; endcase case(grant_posn) 2d0: grant_posn_nxt 2; 2d1: grant_posn_nxt 0; 2d2: grant_posn_nxt 1; endcase end else if(relative_req_vec[2]) begin case(grant_posn) 2d2: begin gnt_vec_nxt 3b100; if(grant_posn_slow[0]) begin if(req_vec_groupb[1]) grant_posn_slow_nxt 2b10; else if(req_vec_groupb[0]) grant_posn_slow_nxt 2b01; end else if(grant_posn_slow[1]) begin if(req_vec_groupb[0]) grant_posn_slow_nxt 2b01; else if(req_vec_groupb[1]) grant_posn_slow_nxt 2b10; end end 2d0: gnt_vec_nxt 3b001; 2d1: gnt_vec_nxt 3b010; endcase case(grant_posn) 2d0: grant_posn_nxt 0; 2d1: grant_posn_nxt 1; 2d2: grant_posn_nxt 2; endcase end end end endcase end always(posedge clk, negedge resetb) begin if(!resetb) begin arbiter_state IDLE; gnt_vec 0; grant_posn 2; grant_posn_slow 2; end else begin arbiter_state arbiter_state_nxt; gnt_vec gnt_vec_nxt; grant_posn grant_posn_nxt; grant_posn_slow grant_posn_slow_nxt; end end endmodule以上内容来源于《Verilog高级数字系统设计技术和实例分析》

更多文章