Ready-to-run snippets

Code Examples

Ready-to-run Verilog, SystemVerilog, and UVM examples. Click any to open it live in the IDE.

← All examples

Bus Arbitration: fixed priority vs round robin

Verilog Bus Protocols

Two masters share a bus. A fixed-priority arbiter starves one master; a round-robin arbiter shares the bus evenly.

Open in IDE
design.v
// Two masters share one bus. An arbiter grants the bus to one of them per transfer.
// Each master keeps req high while it has transfers to do; a grant lasts one cycle
// (one single-cycle transfer to a slave that is always ready).
module bus_arbiter #(
  parameter ROUND_ROBIN = 0              // 0 = fixed priority (master 0 wins), 1 = round robin
) (
  input            clk,
  input            rst,
  input      [1:0] req,
  output reg [1:0] gnt
);
  reg last;                              // the master granted last time

  always @(posedge clk) begin
    if (rst) begin
      gnt  <= 2'b00;
      last <= 1'b1;
    end
    else begin
      if (req == 2'b11) begin
        if (ROUND_ROBIN) begin
          gnt  <= last ? 2'b01 : 2'b10;  // the other master gets the next turn
          last <= ~last;
        end
        else begin
          gnt <= 2'b01;                  // master 0 always wins
        end
      end
      else begin
        gnt <= req;                      // only one or no request: grant it
        if (req == 2'b01)
          last <= 1'b0;
        else if (req == 2'b10)
          last <= 1'b1;
      end
    end
  end
endmodule

// The shared bus: the granted master's address and data go to the slave
module shared_bus #(
  parameter ROUND_ROBIN = 0
) (
  input            clk,
  input            rst,
  input      [1:0] req,
  input      [7:0] addr0,
  input      [7:0] addr1,
  input      [7:0] wdata0,
  input      [7:0] wdata1,
  output     [1:0] gnt,
  output     [7:0] bus_addr,
  output     [7:0] bus_wdata,
  output           bus_sel
);
  bus_arbiter #(.ROUND_ROBIN(ROUND_ROBIN)) u_arb (
    .clk (clk),
    .rst (rst),
    .req (req),
    .gnt (gnt)
  );

  assign bus_sel   = |gnt;
  assign bus_addr  = gnt[1] ? addr1  : addr0;
  assign bus_wdata = gnt[1] ? wdata1 : wdata0;
endmodule
testbench.v
// Both masters want the bus for eight transfers each. Count who gets it.
module tb;
  reg        clk = 0;
  reg        rst = 1;
  reg  [1:0] req = 2'b00;
  reg  [7:0] addr0 = 8'h00;
  reg  [7:0] addr1 = 8'h80;
  wire [1:0] gnt_fp, gnt_rr;
  wire [7:0] a_fp, a_rr, d_fp, d_rr;
  wire       s_fp, s_rr;
  integer    n0_fp = 0, n1_fp = 0, n0_rr = 0, n1_rr = 0;

  shared_bus #(.ROUND_ROBIN(0)) u_fp (
    .clk       (clk),
    .rst       (rst),
    .req       (req),
    .addr0     (addr0),
    .addr1     (addr1),
    .wdata0    (8'h00),
    .wdata1    (8'h11),
    .gnt       (gnt_fp),
    .bus_addr  (a_fp),
    .bus_wdata (d_fp),
    .bus_sel   (s_fp)
  );

  shared_bus #(.ROUND_ROBIN(1)) u_rr (
    .clk       (clk),
    .rst       (rst),
    .req       (req),
    .addr0     (addr0),
    .addr1     (addr1),
    .wdata0    (8'h00),
    .wdata1    (8'h11),
    .gnt       (gnt_rr),
    .bus_addr  (a_rr),
    .bus_wdata (d_rr),
    .bus_sel   (s_rr)
  );

  always #5 clk = ~clk;

  always @(posedge clk) begin
    if (gnt_fp[0])
      n0_fp = n0_fp + 1;
    if (gnt_fp[1])
      n1_fp = n1_fp + 1;
    if (gnt_rr[0])
      n0_rr = n0_rr + 1;
    if (gnt_rr[1])
      n1_rr = n1_rr + 1;
  end

  initial begin
    $dumpfile("dump.vcd");
    $dumpvars(0, tb);
    #12 rst = 0;
    @(negedge clk);
    req = 2'b11;                     // both masters request for eight cycles
    repeat (8) @(negedge clk);
    req = 2'b00;
    repeat (2) @(negedge clk);
    $display("fixed priority: master 0 got %0d transfers, master 1 got %0d", n0_fp, n1_fp);
    $display("round robin:    master 0 got %0d transfers, master 1 got %0d", n0_rr, n1_rr);
    $finish;
  end
endmodule
Admin mode — edit and delete controls are visible on each row. Use the IDE to add new snippets via File → Save as Snippet.