2023.5.16 天气炎热 最近实验推进一大步
当有多个主设备时,一般同一时刻只有一个主设备可以控制总线,这时候就需要对多个主设备发出的请求进行仲裁。
固定优先级:意味着优先级是固定的,不管有几个主设备同时发出请求,只会响应优先级最高的那一个主设备。例如优先级A>B>C>D,那么如果请求为0011的话,响应的就是C。
该电路是一个组合逻辑电路。
module fixed_arb(
input [3:0] request,
output [3:0] grant_reg
);
//case语句会被综合成串行结构
always@(*)begin
case(1'b1) //第一次见case1这种写法
request[3] : grant_reg = 4'b1000;
request[2] : grant_reg = 4'b0100;
request[1] : grant_reg = 4'b0010;
request[0] : grant_reg = 4'b0001;
default: grant_reg = 4'b0000;
endcase
end
//此处也可以使用if-else结构
always@(*)begin
if(request[3])
grant_reg = 4'b1000;
else if(request[2])
grant_reg = 4'b0100;
else if(request[1])
grant_reg = 4'b0010;
else if(request[1])
grant_reg = 4'b0001;
else
grant_reg = 4'b0000;
end
endmodule
固定优先级仲裁器可以用if或case语句实现,case语句实现起来更为简单,假如要实现参数化的固定优先级仲裁器的话,case语句就不行了,就必须使用for循环。
下面代码:最低位的优先级最高
module fixed_pri_arb#(parameter REQ_WIDTH = 16)(
input [REQ_WIDTH-1:0] req,
output reg [REQ_WIDTH-1:0] grant
);
reg [REQ_WIDTH-1] pre_req;//为了记录低位是否已经有了request
always@(*)begin
grant[0] = req[0];
pre_req[0] = req[0];
for(i = 1; i<REQ_WIDTH; i=i+1)begin
grant[i] = req[i] & ~pre_req[i-1];
pre_req[i] = req[i] | pre_req[i-1];
end
end
endmodule
轮询算法:当一个request得到了grant许可之后,它的优先级在接下来的仲裁中就变成了最低。每次响应完一个设备后,会对优先级进行更新。
这是一种比较公平的算法,每个设备都可以成为最高优先级。
该电路是时序电路。
最简单的方法是写case语句。直接对输出状态进行判断,输出是哪个主设备,那么它会变成优先级最低的,依次类推,但是这样代码写起来就比较复杂,且不容易进行移植。
module round_robin_bus_arbiter(
input clk,
input rst_n,
input [2:0] req, //假如需要给3个主机分配总线
output reg [1:0] grant_out //2'b00 A获得总线, 2‘b01 B获得总线 , 2'10 c获得总线
);
always @ (posedge clk or negedge rst_n)
begin
if (!rst_n)
grant_out <= 1'b11;
else
case(grant_out) //根据输出来进行判断
2'b00: //之前A获得总线
case (req)
3'b000: grant_out <= 2'b00;
3'b001: grant_out <= 2'b00;
3'b010: grant_out <= 2'b01;
3'b011: grant_out <= 2'b01;
3'b100: grant_out <= 2'b10;
3'b101: grant_out <= 2'b10;
3'b110: grant_out <= 2'b01;
3'b111: grant_out <= 2'b01;
default: grant_out <= 2'b00;
endcase
2'b01: //之前B获得总线
case (req)
3'b000: grant_out <= 2'b01;
3'b001: grant_out <= 2'b00;
3'b010: grant_out <= 2'b01;
3'b011: grant_out <= 2'b00;
3'b100: grant_out <= 2'b10;
3'b101: grant_out <= 2'b10;
3'b110: grant_out <= 2'b01;
3'b111: grant_out <= 2'b01;
default: grant_out <= 2'b01;
endcase
2'b10: //之前C获得总线
case (req)
3'b000: grant_out <= 2'b10;
3'b001: grant_out <= 2'b00;
3'b010: grant_out <= 2'b01;
3'b011: grant_out <= 2'b00;
3'b100: grant_out <= 2'b10;
3'b101: grant_out <= 2'b00;
3'b110: grant_out <= 2'b01;
3'b111: grant_out <= 2'b00;
default: grant_out <= 2'b10;
endcase
default: grant_out <= 2'b00;
endcase
end
endmodule
|request
:表示此刻有主设备请求,因而去更新
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
last_state <= (|request) ? {grant[2:0],grant[3]} : last_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