1. 概述
在多主机的通讯结构中(如AXI、AHB),仲裁器往往是不可或缺的一个模块。其用于通过一定的策略,处理【多个主机同时请求获取总线权限】时的仲裁任务。
模块输入为一定宽度的请求信号,每一位代表一个主机的请求与否,输出则为同位宽的独热码。 因此模块接口可以描述为(以4个主机为例): 常见的仲裁策略有三种:
循环优先级仲裁器(Round Robin arbiter)是一种【尽量均匀的将总线分配给不同主机】的策略。其基本思想如下:
在初始情况下,最低位代表的主机有着最高的优先级,且向左优先级依次递减。 以A为最高优先级,D为最低优先级,则可以表示为 DCBA 。
若在一次仲裁中,某一位代表的主机获取了总线权限,则在下一次仲裁中,其左侧相邻位优先级变为最高,并向左优先级依次降低。
如下例:
初始仲裁优先级:DCBA,第一次发起仲裁请求的输入为4’b1010,则优先级为B的端口获得权限,仲裁器输出为4‘b0010。与此同时,下一次仲裁的优先级即变成了BADC,即刚刚获得权限的主机在下一次仲裁中的优先级最低。 2. verilog的实现原理上述描述显得算法并不复杂,但是在实际的verilog可综合实现中却并不是那么直白。网上看到不少帖子里用了非常暴力的case分支,但是显然极其浪费资源。
几篇帖子中,有一个【数字IC手撕代码】Verilog轮询仲裁器|题目|原理|设计|仿真很有新意,但是通篇看下来发现并未对原理深入分析,代码也存在一定的问题,所以自己琢磨了一番。
原理
接下来是代码实现:
module round_robin_arb( input clk , input rst_n , input [3:0] request, output [3:0] grant ); // 存储移位后上一次仲裁结果 reg [3:0] last_state; always@(posedge clk or negedge rst_n) begin if(!rst_n) last_state <= 4'b0001; // 默认值,表示最低位的优先级最高 else if(|request) last_state <= {grant[2],grant[1],grant[0],grant[3]}; // 有仲裁请求,根据上一次的仲裁结果,左移1bit后用于控制新的优先级 else last_state <= last_state; // 无仲裁请求时,pre_state不更新 end // 如果最左侧几个高优先级主机都为发起仲裁请求,需要从最低位开始轮询。 // 此处通过两个request拼接,将右侧低位拼接到左侧,即可实现对低位的判断。 wire [7:0] grant_ext; assign grant_ext = {request,request} & ~({request,request} - last_state); // 得到的grant_ext必定为一个独热码,但是置高位可能在代表低位的高4bit中,因此进行求或运算 assign grant = grant_ext[3:0] | grant_ext[7:4]; endmodule仿真代码:
`timescale 1ns / 1ps module dut_top(); bit clk ; bit rst_n ; bit [3:0] request; bit [3:0] grant ; initial forever #5 clk = !clk; initial begin rst_n= 0; request = 4'h0; #15 rst_n = 1; @(posedge clk) #0 request = 4'b1101; #50; @(posedge clk) #0 request = 4'b0101; @(posedge clk) #0 request = 4'b0010; @(posedge clk) #0 request = 4'b0000; #100; $stop; end round_robin_arb u0_round_robin_arb_inst ( .clk ( clk ) , .rst_n ( rst_n ) , .request ( request ) , .grant ( grant ) ); endmodule仿真结果如下图:
综合得到的RTL为:
1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,会注明原创字样,如未注明都非原创,如有侵权请联系删除!;3.作者投稿可能会经我们编辑修改或补充;4.本站不提供任何储存功能只提供收集或者投稿人的网盘链接。 |
标签: #Round #Robin #verilog #轮询仲裁器的verilog实现