手把手Verilog循环优先级仲裁器

一级目录

二级目录

三级目录

1、仲裁Arbiter简介

多个信号同时请求一个处理时,需要一个名为仲裁器的模块来选择优先级高的信号处理。通常输入一个多信号优先级请求i_req[:0],经过处理后输出一个处理结果信号o_result[:0],来表明谁被许可处理。常见有固定优先级仲裁器和循环优先级仲裁器。

2、固定优先级仲裁器原理实现

顾名思义,即优先级固定,每一次都以同一优先级判断,前后仲裁不影响。代码用if-else/case语句就可简单实现。即:

module fixed_arbiter4(
	input            clk,
	input            rst_n,
	input      [3:0] i_req,
	output reg [3:0] o_result
);
always@(posedge clk or negedge rst_n)
begin
	if(!rst_n)
	    o_result <= 4'b0001;               //默认i_req第0位优先
/*
//一次只允许一位请求,不太合理				
				else begin	
					case(i_req)
					4'b0001 : o_result <= 4'b0001;
					4'b0010 : o_result <= 4'b0010;
					4'b0100 : o_result <= 4'b0100;
					4'b1000 : o_result <= 4'b1000;
                    default	:o_result <= 4'b0001;			
				end
*/				
//一次允许多位请求,优先顺序位i_req[0]>i_req[1]i_req[2]>i_req[3]		
				else begin	
					case(1'b1)
					i_req[0] :o_result <= 4'b0001;
					i_req[1] :o_result <= 4'b0010;
					i_req[2] :o_result <= 4'b0100;
					i_req[3] :o_result <= 4'b1000;
                    default:o_result <= 4'b0001;	
                    endcase					
				end					
end
endmodule

测试代码也很简单,这里不赘述。

3、循环优先级仲裁器原理

每一次仲裁的优先级都是根据上一次仲裁结果而定的,即本次的仲裁结果会影响下一次仲裁的优先级。
因为这样仲裁的优先级会改变,所以理论上每个请求的几率基本平等。实现上可用一个优先级状态寄存器来完成。
基本原理思想:
1、请求信号i_req[3:0],则默认规定最低位优先级最高,往左依次递减。
2、一次仲裁中,某一位获得请求后,则下一次仲裁时,其左侧优先级变为最高,依次递减,循环回到自己优先级最低。

例如:
请求信号i_req[3:0],优先级 i_req[0]>i_req[1]>i_req[2]>i_req[3]。
第一次发起仲裁请求的输入为i_req[3:0] = 4’b 0 1 1 0,
根据规则判断i_req[1]获得允许,输出o_result[4:0] = 4’b 0 0 1 0。
与此同时,下一次仲裁的优先级即变成了:
i_req[2]>i_req[3]>i_req[0]>i_req[1],即上一次的优先在本级最后。

4、实现方法

一个仲裁器通常包含两部分组成,即一个优先级状态寄存器阵列和一个请求计算模块

4.1、优先级状态寄存器阵列

优先级状态寄存器阵列,用于保存每个请求和其他请求之间的关系。如果一个仲裁电路有N个请求,那么需要一个(N-1)*N的寄存器阵列,阵列设置不同则代表含义不同,下面以其4个请求仲裁的一种阵列说明。
总共有4个请求,则每个请求需要3个寄存器来表示其他外部请求优先级是否高于本请求优先级。本例中,优先级关系规定为:本请求比另一个高则赋0,低则赋1。

在这里插入图片描述

其中req0_1,req0_2,req0_3就表示R[0]相对于R[1]、R[2]、R[3]的优先级。
假设初始优先级顺序:i_req[0]>i_req[1]>i_req[2]>i_req[3]
初始矩阵如下左图,此时R[0]获得允许,下一次R[1]优先级最高,往左依次递减,R[0]优先级最低,
此时优先级顺序为:i_req[0]>i_req[1]>i_req[2]>i_req[3],矩阵变为下右图

在这里插入图片描述上述的改变过程可用状态机实现,值得注意的是,状态机是根据本次输出的结果o_result[4:0]来修改阵列的值,而不是输入的i_req[0],这里怎么理解呢?

因为输入可能有两位同时有效,即输入i_req[3:0] = 4’b 0 1 0 1,这样不符合状态机运行规则,而经过计算模块o_result[4:0]每次只会有1位有效(下个部分介绍怎样计算才能保证无论输入几位有效,输出有且只有一位有效),这样才可以用状态机来实现。至于第一次输出,第一次输出不过状态机,根据初始矩阵数据和输入实现第一次输出,然后过状态机修改矩阵。

4.2、请求计算模块

根据上述优先状态寄存器的描述可知,本次输出的结果和两个值有关,分别是上一次仲裁后修改的阵列本次输入来判断本次输出。

即某个请求响应的条件是:1、本请求对应的输入有效;2、本次有效的请求优先级顺位最高。
计算包含两部分:第一级“与非”,三次与非依据优先级状态寄存器阵列中保存的请求优先级别仲裁;第二级“与”,四次与完成当前请求是否有效。

例如:o_result[0] = 
i_req[0] & //
(~(req0_1&i_req[1]))&
(~(req0_2&i_req[2]))&
(~(req0_3&i_req[3]));
o_result[0]输出有效的条件是:
1、请求输入0位有效,即:i_req[0];第0位优先级比第1位高,比第2位高,比第3位高。

5、Verilog HDL代码

模块代码:

module arbiter4(
    input              clk,
	input              rst_n,
	input      [3:0]   i_req,
	output reg [3:0]   o_result
);
//优先级状态寄存器
reg  req0_1,req0_2,req0_3;//第0位3个优先级状态
reg  req1_0,req1_2,req1_3;//第1位3个优先级状态
reg  req2_0,req2_1,req2_3;//第2位3个优先级状态
reg  req3_0,req3_1,req3_2;//第3位3个优先级状态

//优先级状态阵列

always@(posedge clk or negedge rst_n)
begin
	if(!rst_n)
	begin//默认情况下req[0]优先级最高,三位分别000;优先级往左依次递减,req[4]优先级最低,三位分别111
	        req0_1 <= 1'b0; req1_0 <= 1'b1; req2_0 <= 1'b1; req3_0 <= 1'b1;
            req0_2 <= 1'b0; req1_2 <= 1'b0; req2_1 <= 1'b1; req3_1 <= 1'b1;
            req0_3 <= 1'b0; req1_3 <= 1'b0; req2_3 <= 1'b0; req3_2 <= 1'b1;
	end
    else begin                                                    //本次输出决定下次优先级
	    case(o_result)
		4'b0001:begin                                             //上次req[0]优先,本次最后
		    req0_1 <= 1'b1; 
			req0_2 <= 1'b1; 
			req0_3 <= 1'b1;                                       //req[0]本次最后
			req1_0 <= 1'b0;
			req2_0 <= 1'b0;
			req3_0 <= 1'b0;                                       //修改其余3位优先级
		end
		4'b0010:begin                                             //上次req[1]优先,本次最后
		    req1_0 <= 1'b1; 
			req1_2 <= 1'b1; 
			req1_3 <= 1'b1;                                       //req[1]本次最后
			req0_1 <= 1'b0;
			req2_1 <= 1'b0;
			req3_1 <= 1'b0;                                       //修改其余3位优先级
		end
		4'b0100:begin                                             //上次req[2]优先,本次最后
		    req2_0 <= 1'b1; 
			req2_1 <= 1'b1; 
			req2_3 <= 1'b1;                                       //req[2]本次最后
			req0_2 <= 1'b0;
			req1_2 <= 1'b0;
			req3_2 <= 1'b0;                                       //修改其余3位优先级
		end
		4'b1000:begin                                             //上次req[3]优先,本次最后
		    req3_0 <= 1'b1; 
			req3_1 <= 1'b1; 
			req3_2 <= 1'b1;                                       //req[3]本次最后
			req0_3 <= 1'b0;
			req1_3 <= 1'b0;
			req2_3 <= 1'b0;                                       //修改其余3位优先级
		end
		endcase
	end
end	
//请求响应计算
always@(*)
begin
	o_result[0] = i_req[0] &
	                (~(req0_1 & i_req[1])) & 
					(~(req0_2 & i_req[2])) & 
					(~(req0_3 & i_req[3]));
    o_result[1] = i_req[1] &
	                (~(req1_0 & i_req[0])) &
					(~(req1_2 & i_req[2])) & 
					(~(req1_3 & i_req[3]));
	o_result[2] = i_req[2] &
	                (~(req2_0 & i_req[0])) &
					(~(req2_1 & i_req[1])) &
					(~(req2_3 & i_req[3]));
	o_result[3] = i_req[3] &
	                (~(req3_0 & i_req[0])) &
					(~(req3_1 & i_req[1])) &
					(~(req3_2 & i_req[2]));
end
endmodule

Testbench:

`timescale 1ns/1ns
module tb_arbiter4;

reg          clk;
reg          rst_n;
reg  [3:0]   i_req;
wire [3:0]   o_result;


arbiter4 arbiter4_u0(
        .clk        (clk),
        .rst_n      (rst_n),
        .i_req      (i_req),
        .o_result   (o_result)
);

initial begin
        clk     = 1'b0;
        rst_n   = 1'b0;
        i_req   = 4'b0000;

#20     rst_n   = 1'b1;

#10     i_req   = 4'b0101;

#20     i_req   = 4'b1111;
#20     i_req   = 4'b0110;
#20     i_req   = 4'b1100;
end

always #10 clk = ~clk;

endmodule

6、仿真分析

在第一次写测试时是这样写的,导致的波形有一个输入数据4’b1111无效,
以为是哪里有问题,反复检查才发现问题,代码没错。
只是这个数据恰好处在时钟下降沿,所以没处理。简单修改testbench即可。

错误数据输入:在这里插入图片描述错误仿真波形:,中间有一个数据被漏掉了。在这里插入图片描述正确数据输入:
在这里插入图片描述正确波形:,每个输入数据都处理。
在这里插入图片描述

  • 2
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值