본문 바로가기
Digital Design/SoC

[SoC] Round-Robin Arbiter_Fixed History (Design with Verilog)

by 스테고사우르스 2023. 4. 25.

안녕하세요.

지난 시간에 LRG Arbiter에 대해 학습하였습니다.

오늘은 LRG Arbiter에 사용되는 Round-Robin 알고리즘을 사용해

Arbiter를 Verilog로 설계해보겠습니다.

 

Least Recent Granted 기반의 아비터를 만들기 전에,

먼저 Fixed History 기반의 RR 아비터를 설계해볼게요.

(Fixed History는 제가 그냥 지어낸 것입니다..

가장 기본적인, 돌아가면서 Grant하는 RR 알고리즘으로 생각해주세요)

 

History queue에 이전의 결과를 저장하지 않고,

M0 -> M1 -> M2 -> M3 -> M0 -> M1 ... 순서대로 돌아가면서 처리해보겠습니다.

 


Verilog Code

DUT

module round_robin_arbiter(
input clk,
input rst_n,
input [3:0] REQ,
output reg [3:0] GNT
);

reg [2:0] present_state;
reg [2:0] next_state;

parameter [2:0] s_ideal = 3'b000;
parameter [2:0] s_0 = 3'b001;
parameter [2:0] s_1 = 3'b010;
parameter [2:0] s_2 = 3'b011;
parameter [2:0] s_3 = 3'b100;

always @ (posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        present_state <= s_ideal;
    end
    else begin
        present_state <= next_state;
    end
end

always @ (*) begin
    case (present_state)
        s_ideal: begin
		     if      (REQ[0]) next_state = s_0;
		     else if (REQ[1]) next_state = s_1;
		     else if (REQ[2]) next_state = s_2;
		     else if (REQ[3]) next_state = s_3;
		     else             next_state = s_ideal;
		 end
	s_0:     begin
		     if      (REQ[1]) next_state = s_1;
		     else if (REQ[2]) next_state = s_2;
		     else if (REQ[3]) next_state = s_3;
		     else if (REQ[0]) next_state = s_0;
		     else             next_state = s_ideal;
	         end
	s_1:     begin
		     if      (REQ[2]) next_state = s_2;
		     else if (REQ[3]) next_state = s_3;
		     else if (REQ[0]) next_state = s_0;
		     else if (REQ[1]) next_state = s_1;
		     else             next_state = s_ideal;
	         end
	s_2:     begin
		     if      (REQ[3]) next_state = s_3;
		     else if (REQ[0]) next_state = s_0;
		     else if (REQ[1]) next_state = s_1;
		     else if (REQ[2]) next_state = s_2;
		     else             next_state = s_ideal;
	         end
	s_3:     begin
		     if      (REQ[0]) next_state = s_0;
		     else if (REQ[1]) next_state = s_1;
		     else if (REQ[2]) next_state = s_2;
		     else if (REQ[3]) next_state = s_3;
		     else             next_state = s_ideal;
	         end
	default: begin
		     if      (REQ[0]) next_state = s_0;
		     else if (REQ[1]) next_state = s_1;
		     else if (REQ[2]) next_state = s_2;
		     else if (REQ[3]) next_state = s_3;
		     else             next_state = s_ideal;
	         end
    endcase
end

always @ (*) begin
    case (present_state)
        s_0: GNT = 4'b0001;
	s_1: GNT = 4'b0010;
	s_2: GNT = 4'b0100;
	s_3: GNT = 4'b1000;
	default: GNT = 4'b0000;
    endcase
end
	
endmodule

always 문을 현재 상태에 따라 값을 선택하는 MUX로 구성하였습니다.

그리고 그 내부는 if문을 사용하였기 때문에 우선순위가 생겨서,

MUX 여러개가 나열된 상태로 합성됩니다. 

순서는 M0 -> M1 -> M2 -> M3 -> M0... 으로 설정하였습니다.

 

Testbench

`timescale 1ns / 1ps
module tb_round_robin_arbiter();

reg clk;
reg rst_n;
reg [3:0] REQ;
wire [3:0] GNT;

round_robin_arbiter rra (.clk   (clk),
	             .rst_n (rst_n),
		     .REQ   (REQ),
		     .GNT   (GNT) );

always #5 clk = ~clk;

initial begin
    clk = 1'b0; rst_n = 1'b1; REQ = 4'b0000;  #1
    rst_n = 1'b0;   #1
    rst_n = 1'd1;   #8
    REQ = 4'b1111;  #40
    REQ = 4'b1011;  #20
    REQ = 4'b0101;  #20
    REQ = 4'b0011;  #30
    $finish;
end

initial begin
    $dumpfile ("dump.vcd");
    $dumpvars();
end

endmodule

 

Simulation

10ns에 1111, 즉 모든 Master가 REQ를 보냈습니다.

따라서 앞서 정한 순서대로 0001(M0), 0010(M1), 0100(M2), 1000(M3) 번째 Master에게 승인을 내줬습니다.

 

50ns에 1011이 다시 들어왔습니다.

역시 0001(M0), 0010(M1)을 GRANT 하였습니다.

 

이때 70ns에서 0101로 REQ이 바뀌었습니다.

Fixed Priority라면 0001(M0)부터 처리했겠죠?

하지만 Round-Robin 이기 때문에 시간 순서대로 승인합니다.

이전에 M1까지 승인했기 때문에 M0가 아닌 M2를 먼저 GRANT해주는 것을 볼 수 있습니다.

이후 M0를 GRANT 해주었습니다.

 


지금까지 시간 순서대로 GRANT하는 Round-Robin Arbiter에 대해 알아보았습니다.

이 방식을 사용하면 Master들에게 공평하게 기회를 줄 수 있지만

빨리 처리해야 하는 Master에게는 좋지 않을 수 있습니다.

 

다음 게시글에서는 장점을 높이고 단점을 줄인

Fixed Priority + LRG Round-Robin Arbiter를 설계해서 돌아오겠습니다!


댓글