前言
Round Robin (RR) 仲裁器 是一种常见的硬件仲裁算法,广泛应用于多通道系统、总线仲裁和多处理器系统中,目的是在多个请求中公平地分配资源。Round Robin 算法的基本思想是,按照固定的顺序逐一服务每个请求,每次选择下一个请求,而不偏向任何特定请求。这种方法确保了所有请求获得均等的机会,从而避免了长时间的饥饿问题。
Round Robin 仲裁器的工作原理
- 请求队列:有多个请求线(Request Lines),每一条请求线表示一个模块或实体对资源的请求。例如,多个 CPU 核心请求访问共享的内存或总线。
- 轮转方式:当仲裁器选择一个请求时,它按照固定的顺序依次轮流选择请求信号。每次选择后,仲裁器会将选择的指针“轮换”到下一个请求信号。
- 优先级:Round Robin 仲裁器没有优先级偏向,它会按顺序选择一个请求,并在下次选择时轮流选择下一个请求。这意味着每个请求都有公平的机会。
- 请求和应答:在 Round Robin 仲裁器中,首先会有请求信号(Request)。如果请求被选择,仲裁器会通过分配信号(Grant)来通知相应模块资源已被分配。
- 轮转过程:例如,假设有三个请求 R1、R2 和 R3,在每个周期内,仲裁器会根据当前的指针依次选择这三个请求中的一个并分配资源。
Round Robin 仲裁器的基本结构
- 输入:多个请求信号,例如 R1, R2, R3, …
- 输出:一个选定的“授予”信号(G1, G2, G3…),表示哪个请求被选中并被授予资源。
- 内部状态:一个指示当前选择位置的计数器,通常是一个指针或循环计数器。
- 控制逻辑:用于判断哪个请求信号当前可用并分配相应的资源。它通过轮换顺序在请求之间切换。
Round Robin 仲裁器的工作流程
- 初始化:首先将指针指向第一个请求(例如 R1)。
- 轮询:在每个时钟周期,仲裁器检查当前的请求状态。它优先选择当前指针所指向的请求,并通过 Grant 信号通知资源分配。
- 轮换:当资源分配完后,指针会移到下一个请求信号。
- 重复:该过程会持续进行,直到所有的请求都得到服务。
代码示例
本实例代码,实现了一级优先级的round Robin的仲裁器。
仲裁器有两种工作模式,分别为periodic和valid,可通过参数ARB_MODE定义。
periodic的仲裁器为周期性 RR 仲裁器,每个valid为高的请求,周期性地按照固定的顺序轮流获得资源。
valid的仲裁器为有效请求 RR 仲裁器,当仲裁器选中当前通道后,会一直保持直到valid无效,然后按照固定的顺序选择下一个valid有效的通道。
// ######################################################################
// Filename : prr_arbiter.v
// Description : prior round robin arbiter
// There are two working modes, divided into:
// when the input parameter "ARB_MODE=periodic",the arbiter is periodic switching arbitration
// when the input parameter "ARB_MODE=valid",the arbiter is arbitration based on Valid signal
// Author :
// Created On :
// Last Modified By:
// Last Modified On:
// Update Count :
// Status : Verified
// verilog-filelist: None
// verilog-file : None
// ######################################################################
`timescale 1ns/1ps
module prr_arbiter#(
parameter ARB_MODE = "periodic" ,//periodic , valid
parameter REQ_NUM = 8
)(
input wire clk_in ,
input wire rst_n ,
//----------------------------------------------------//
input wire [REQ_NUM-1:0] req ,
input wire [REQ_NUM-1:0] prior ,
output wire [REQ_NUM-1:0] grant
);
//==============================================================================================//
//====== define signal ========//
//==============================================================================================//
wire [REQ_NUM-1:0] req_prior;
wire [REQ_NUM-1:0] req_masked;
wire [REQ_NUM-1:0] mask_higher_req;
wire [REQ_NUM-1:0] grant_masked;
wire [REQ_NUM-1:0] req_unmasked;
wire [REQ_NUM-1:0] unmask_higher_req;
wire [REQ_NUM-1:0] grant_unmask;
reg [REQ_NUM-1:0] pointer_reg;
wire [REQ_NUM-1:0] pointer;
reg [REQ_NUM-1:0] grant_reg;
//==============================================================================================//
//====== behave of RTL ========//
//==============================================================================================//
assign req_prior = req & prior;
//--------------------------------------------------------------------
//------simple priority arbitration for masked portion ------
//--------------------------------------------------------------------
assign req_masked = (|req_prior) ? (req_prior & pointer) : (req & pointer);
assign mask_higher_req = (mask_higher_req|req_masked)<<1;
assign grant_masked = (~mask_higher_req)&req_masked;
//--------------------------------------------------------------------
//------simple priority arbitration for unmasked portion ------
//--------------------------------------------------------------------
assign req_unmasked = (|req_prior) ? req_prior : req ;
assign unmask_higher_req = (unmask_higher_req|req_unmasked)<<1;
assign grant_unmask = (~unmask_higher_req)&req_unmasked;
//--------------------------------------------------------------------
//------ ------
//--------------------------------------------------------------------
assign grant = (|req_masked) ? grant_masked : grant_unmask ;
//******************************************************************//
//------arbitration based on Valid signal ------
//******************************************************************//
generate if(ARB_MODE == "valid")begin:gen_valid_arbiter
always@(posedge clk_in or negedge rst_n)begin
if(!rst_n)begin
grant_reg <= {REQ_NUM{1'b0}};
end else begin
grant_reg <= grant;
end
end
//--------------------------------------------------------------------
//------pointer update ------
//--------------------------------------------------------------------
always@(posedge clk_in or negedge rst_n)begin
if(!rst_n)begin
pointer_reg <= {REQ_NUM{1'b1}};
end else if((|req_masked == 1'b1) && (|(grant_reg&req) == 1'b0 ))begin
pointer_reg <= mask_higher_req;
end else if((|req == 1'b1) && (|(grant_reg&req) == 1'b0 ))begin
pointer_reg <= unmask_higher_req;
end else begin
pointer_reg <= pointer_reg;
end
end
assign pointer = |(grant_reg&req) ? pointer : pointer_reg ;
//******************************************************************//
//------periodic switching arbitration ------
//******************************************************************//
end else begin:gen_periodic_arbiter
//--------------------------------------------------------------------
//------pointer update ------
//--------------------------------------------------------------------
always@(posedge clk_in or negedge rst_n)begin
if(!rst_n)begin
pointer_reg <= {REQ_NUM{1'b1}};
end else if(|req_masked == 1'b1)begin
pointer_reg <= mask_higher_req;
end else if(|req == 1'b1)begin
pointer_reg <= unmask_higher_req;
end else begin
pointer_reg <= pointer_reg;
end
end
assign pointer = pointer_reg ;
end endgenerate
endmodule