相关文章
数字IC前端学习笔记:LSFR(线性反馈移位寄存器)
数字IC前端学习笔记:跨时钟域信号同步
数字IC前端学习笔记:信号同步和边沿检测
数字IC前端学习笔记:锁存器Latch的综合
数字IC前端学习笔记:格雷码(含Verilog实现的二进制格雷码转换器)
数字IC前端学习笔记:FIFO的Verilog实现(一)
数字IC前端学习笔记:FIFO的Verilog实现(二)
数字IC前端学习笔记:仲裁轮询(一)
数字IC前端学习笔记:仲裁轮询(二)
数字IC前端学习笔记:仲裁轮询(四)
数字IC前端学习笔记:仲裁轮询(五)
数字IC前端学习笔记:仲裁轮询(六)
数字IC前端学习笔记:近期最少使用(LRU)算法
5.无死周期的公平轮询
在前面公平轮询仲裁器的Verilog RTL代码中,每个用户有三个信号:request(请求)、grant(授权)、end_access(结束访问)。在总线使用时,我们能观察到总线上存在不能进行数据传输的死周期。当传输的数据包较长或每个突发较长时,其对传输效率影响不大。然而,当数据包很短时,死周期会影响到总线的使用效率。如下图所示为没有间隔的公平轮询仲裁波形。下面给出了一些方法,用于减少甚至消除死周期。
第一种方案是当grant信号有效时,该用户的第一个数据已经准备好并且有效输出。原来的方案中,在用户的grant有效后,它在下一个周期输出数据,现在改为当grant采样为高时,在同一个周期就开始输出数据。此时需要用户提前从内部电路中读出第一个数据。采用这种方案时,仲裁器的设计不变,用户部分需要进行修改。
第二种方法是增加额外的信号start_access,它和end_access一起使用。一个用户获得总线使用权并开始操作后,仲裁器通过将start_access置为有效表示开始新的仲裁过程,而不是等待end_access信号变高来开始新的仲裁过程,这样就减少了转换期间的死周期。当下一个用户被授权时,当前用户仍在使用总线,此时新的用户不能立即使用总线。仲裁器在当前用户完成操作时会给出end_access_out信号,新的授权用户此后就可以开始操作了。仲裁器在没有用户使用公共资源时,将resource_idle置为1。当resource_idle为1时,获得授权的用户不需要查看end_access_out信号就可以开始数据操作。
没有死周期的公平轮询代码及仿真结果如下。
module arbiter_roundrobin(
clk,resetb,
req_vec,
end_access_vec,
gnt_vec,
end_access_out);
input clk, resetb;
input [2:0] req_vec, end_access_vec;
output [2:0] gnt_vec;
output end_access_out;
reg [1:0] arbiter_state, arbiter_state_nxt;
reg [2:0] gnt_vec, gnt_vec_nxt;
reg [2:0] relative_req_vec;
wire any_req_asserted;
reg [1:0] grant_posn, grant_posn_nxt;
reg resource_idle_nxt, resource_idle;
reg [2:0] start_access_vec, start_access_vec_nxt;
parameter IDLE = 2'b00;
parameter END_ACCESS = 2'b01;
assign any_req_asserted = (req_vec != 0);
assign end_access_out = |end_access_vec;
always@(*) begin
relative_req_vec = req_vec;
case(grant_posn)
2'd0: relative_req_vec = {req_vec[0], req_vec[2:1]};
2'd1: relative_req_vec = {req_vec[1:0], req_vec[2]};
2'd2: relative_req_vec = {req_vec[2:0]};
endcase
end
always@(*) begin
arbiter_state_nxt = arbiter_state;
grant_posn_nxt = grant_posn;
gnt_vec_nxt = gnt_vec;
resource_idle_nxt = 1'b0;
start_access_vec_nxt = 3'b0;
case(arbiter_state)
IDLE:begin
if(any_req_asserted)
arbiter_state_nxt = END_ACCESS;
resource_idle_nxt = 1'b1;
if(relative_req_vec[0])
case(grant_posn)
2'd0: begin gnt_vec_nxt = 3'b010; grant_posn_nxt = 3'd1; end
2'd1: begin gnt_vec_nxt = 3'b100; grant_posn_nxt = 3'd2; end
2'd2: begin gnt_vec_nxt = 3'b001; grant_posn_nxt = 3'd0; end
endcase
else if(relative_req_vec[1])
case(grant_posn)
2'd0: begin gnt_vec_nxt = 3'b100; grant_posn_nxt = 3'd2; end
2'd1: begin gnt_vec_nxt = 3'b001; grant_posn_nxt = 3'd0; end
2'd2: begin gnt_vec_nxt = 3'b010; grant_posn_nxt = 3'd1; end
endcase
else if(relative_req_vec[2])
case(grant_posn)
2'd0: begin gnt_vec_nxt = 3'b001; grant_posn_nxt = 3'd0; end
2'd1: begin gnt_vec_nxt = 3'b010; grant_posn_nxt = 3'd1; end
2'd2: begin gnt_vec_nxt = 3'b100; grant_posn_nxt = 3'd2; end
endcase
else
gnt_vec_nxt = 3'b000;
end
END_ACCESS:begin
if((resource_idle == 1'b1) || (end_access_out == 1'b1))
start_access_vec_nxt = gnt_vec;
if(start_access_vec != 0)begin
if(relative_req_vec[0])
case(grant_posn)
2'd0: begin gnt_vec_nxt = 3'b010; grant_posn_nxt = 3'd1; end
2'd1: begin gnt_vec_nxt = 3'b100; grant_posn_nxt = 3'd2; end
2'd2: begin gnt_vec_nxt = 3'b001; grant_posn_nxt = 3'd0; end
endcase
else if(relative_req_vec[1])
case(grant_posn)
2'd0: begin gnt_vec_nxt = 3'b100; grant_posn_nxt = 3'd2; end
2'd1: begin gnt_vec_nxt = 3'b001; grant_posn_nxt = 3'd0; end
2'd2: begin gnt_vec_nxt = 3'b010; grant_posn_nxt = 3'd1; end
endcase
else if(relative_req_vec[2])
case(grant_posn)
2'd0: begin gnt_vec_nxt = 3'b001; grant_posn_nxt = 3'd0; end
2'd1: begin gnt_vec_nxt = 3'b010; grant_posn_nxt = 3'd1; end
2'd2: begin gnt_vec_nxt = 3'b100; grant_posn_nxt = 3'd2; end
endcase
else begin
gnt_vec_nxt = 3'b000;
arbiter_state_nxt = IDLE;
end
end
end
endcase
end
always@(posedge clk or negedge resetb)begin
if(!resetb) begin
arbiter_state <= IDLE;
gnt_vec <= 0;
grant_posn <= 0;
resource_idle <= 0;
start_access_vec <= 0;
end
else begin
arbiter_state <= arbiter_state_nxt;
gnt_vec <= gnt_vec_nxt;
grant_posn <= grant_posn_nxt;
resource_idle <= resource_idle_nxt;
start_access_vec <= start_access_vec_nxt;
end
end
endmodule
在Verilog实现过程中,使用了两个状态IDLE和END_ACCESS,分别表示仲裁器处于无请求和仲裁器授权的状态。在IDLE状态时,任何请求信号能使状态转移至END_ACCESS状态,并将resource_idle信号置1(这是为了IDLE状态下start_access的置位而设计的信号),并根据请求信号给出相应授权。在END_ACCESS状态,会根据resource_idle或end_access_out信号使用gnt_vec对start_access置位。当start_access信号有效时,根据请求信号进行下一次授权。若此时没有请求信号,则状态回到IDLE等待。
以上内容来源于《Verilog高级数字系统设计技术和实例分析》,有删改
版权归原作者 日晨难再 所有, 如有侵权,请联系我们删除。