引言
仲裁器的应用场景非常多,特别是在一些多主多从的应用场景中,同时有多个设备有请求时,优先响应哪一个呢?比如总线的使用、内存的访问。仲裁器系列本文先开个头说一下固定优先级仲裁器的设计。
既然讲到设计,那么就先说一下设计的要求。
1、仲裁模块的请求数量在模块例化时可配置;
2、仲裁的优先级bit0 > bit1 >……>bit N-1;
3、发起请求的一方,在总线使用完毕后发送done信号(一个时钟高电平)给仲裁器告知。
4、请求获得仲裁后需要在下个时钟周期拉低req信号。
CBB设计
固定优先级仲裁器设计的关键在于,确定诸多请求中,优先级最高的那一个。比如req = 4'b1011,此时grant=4'b0001,即确定req信号中最低位的1。按照这个思路将req与其补码按位相与即可。
grant = req & (~req + 1'b1) 或者 grant = req & ~(req - 1'b1)
还有一种思路,grant[i]可以拉高的条件是,req[i]为高并且req[i-1:0]为低。但是i=0时比较特殊,grant[0] = req[0],所以grant的逻辑是这样的:
grant[0] = req[0];
grant[i] = req[i] & ~(|req[i-1:0]);
两种思路都可以。
参数P_LOGIC_SEL:配置CASE1时,为思路1的逻辑;CASE2时为思路2的逻辑。
// ==================-------------------------------------------------------=====================
// 在路上-正出发
// Common Building Block
// ==================-------------------------------------------------------=====================
// ________ ________ ________
// |\ ____\ |\ __ \ |\ __ \
// \ \ \___| \ \ \|\ /_ \ \ \|\ /_
// \ \ \ \ \ __ \ \ \ __ \
// \ \ \____ \ \ \|\ \ \ \ \|\ \
// \ \_______\ \ \_______\ \ \_______\
// \|_______| \|_______| \|_______|
// ==================-------------------------------------------------------=====================
// 在路上-正出发
// Common Building Block
// ==================-------------------------------------------------------=====================
// CBB Module Name :CBB_FIXED_ARBITER
// CBB Created Date :2024-08-18
// CBB Module Function:固定优先级仲裁器
// Usage Limitation :
// Author :在路上-正出发
// -----------------------------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------
`timescale 1ns/1ps
module CBB_FIXED_ARBITER#(
// ---- parameter define
parameter P_LOGIC_SEL = "CASE2", // "CASE1" "CASE2"
parameter P_REQ_NUM = 8
)(
// ---- port define
input i_clk,
input i_rstn,
input [P_REQ_NUM-1:0] i_req,
output[P_REQ_NUM-1:0] o_grant,//one-hot
input[P_REQ_NUM-1:0] i_done //持续1个时钟周期的脉冲 one-hot
);
wire w_req_or = |i_req;
reg [1:0] r_req_or;
always @(posedge i_clk or negedge i_rstn) begin : proc_req
if(~i_rstn) begin
r_req_or <= 2'b0;
end else begin
r_req_or <= {r_req_or[0],w_req_or};
end
end
wire w_req_or_pos = r_req_or[0] & (~r_req_or[1]);
reg [P_REQ_NUM-1:0] r_grant;
generate
genvar i;
if(P_LOGIC_SEL == "CASE1") begin
always @(posedge i_clk or negedge i_rstn) begin : proc_grant
if(~i_rstn) begin
r_grant <= {P_REQ_NUM{1'b0}};
end else if(w_req_or_pos | |i_done)begin
r_grant <= i_req & (~(i_req-1));
end
end
end
else begin
for(i=0;i<P_REQ_NUM;i=i+1) begin
if(i==0) begin
always @(posedge i_clk or negedge i_rstn) begin : proc_grant_0
if(~i_rstn) begin
r_grant[i] <= 1'b0;
end else if(w_req_or_pos | |i_done)begin
r_grant[i] <= i_req[i];
end
end
end
else begin
always @(posedge i_clk or negedge i_rstn) begin : proc_grant_other
if(~i_rstn) begin
r_grant[i] <= 1'b0;
end else if(w_req_or_pos | |i_done)begin
r_grant[i] <= i_req[i] & ~(|i_req[i-1:0]);
end
end
end
end
end
endgenerate
assign o_grant = r_grant;
endmodule
CBB验证
验证源码
// ==================-------------------------------------------------------=====================
// 在路上-正出发
// Common Building Block
// ==================-------------------------------------------------------=====================
// ________ ________ ________
// |\ ____\ |\ __ \ |\ __ \
// \ \ \___| \ \ \|\ /_ \ \ \|\ /_
// \ \ \ \ \ __ \ \ \ __ \
// \ \ \____ \ \ \|\ \ \ \ \|\ \
// \ \_______\ \ \_______\ \ \_______\
// \|_______| \|_______| \|_______|
// ==================-------------------------------------------------------=====================
// 在路上-正出发
// Common Building Block
// ==================-------------------------------------------------------=====================
// CBB Module Name :TB_FIXED_ARBITER
// CBB Created Date :
// CBB Module Function:
// Usage Limitation :
// Author :在路上-正出发
// -----------------------------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------
`timescale 1ns/1ps
module TB_FIXED_ARBITER();
// ---- parameter define
parameter P_LOGIC_SEL = "CASE1"; // "CASE1" "CASE2"
parameter P_REQ_NUM = 8;
// ---- port define
reg i_clk;
reg i_rstn;
reg [P_REQ_NUM-1:0] i_req;
wire[P_REQ_NUM-1:0] o_grant;//one-hot
reg [P_REQ_NUM-1:0] i_done; //持续1个时钟周期的脉冲 one-hot
initial i_clk = 1'b0;
always #5 i_clk = ~i_clk;
integer time_dly1 ,sim_cnt;
initial
begin
i_rstn = 1'b0;
i_req = 0;
i_done = 0;
sim_cnt = 0;
#100;
i_rstn = 1'b1;
#200;
while((sim_cnt < 60) || (|i_req))
begin
@(posedge i_clk)
if(|i_req == 0) begin i_req <= $random() % 2**P_REQ_NUM; sim_cnt = sim_cnt + 1;end
while(~(|o_grant)) @(posedge i_clk);
i_req <= i_req & (~o_grant);
time_dly1 = $urandom_range(40,50);
repeat(time_dly1) @(posedge i_clk);
i_done <= {P_REQ_NUM{1'b1}}& o_grant;
@(posedge i_clk)
i_done <= {P_REQ_NUM{1'b0}};
end
#200;
$finish;
end
CBB_FIXED_ARBITER #(
.P_LOGIC_SEL(P_LOGIC_SEL),
.P_REQ_NUM(P_REQ_NUM)
) U_CBB_FIXED_ARBITER (
.i_clk (i_clk),
.i_rstn (i_rstn),
.i_req (i_req),
.o_grant (o_grant),
.i_done (i_done)
);
endmodule
波形
CBB综合
CASE1
CASE2