/* Arbiter * A module that grants access to a shared ressource (e.g a bus) * to an arbitrary amount of drivers. A driver of the shared resource * has a bit on the `request` line and fires it up when it wants to use * the resource. The arbiter fires the corresponding `grant` bit when * the driver is allowed to use the resource */ module arbiter #( parameter NUM_CLIENTS = 4 ) ( input clk, // Request bits, each driver has its request line input[NUM_CLIENTS-1:0] request, // Grant bits, each driver has its grant line output[NUM_CLIENTS-1:0] grant ); // The current round of the arbiter reg[NUM_CLIENTS-1:0] round = 1; // A circle of wires used by the arbiter to // indicate that a driver that has the priority // to use the resource yields it to the next driver // because it doesn't need to use the resource wire pass_on_rollover; /* verilator lint_off UNOPTFLAT */ logic pass_on; assign pass_on_rollover = pass_on; // NOTE: assign is applied on last assignment to wire // Logic bitfield used to generate the grant bus logic[NUM_CLIENTS-1:0] grant_gen; assign grant = grant_gen; always @(posedge clk) begin // Keep current grant as round, allowing a selected driver // to freeze the arbiter during the entire duration of its // resource utilization round <= |grant ? grant : { round[NUM_CLIENTS-2:0], round[NUM_CLIENTS-1] }; end always_comb begin pass_on = pass_on_rollover; for (integer i = 0; i < NUM_CLIENTS; i++) begin logic has_priority; // Current driver has priority if it's its round // or previous driver has passed on its has_priority = round[i] || pass_on; // By default, do not grant to driver grant_gen[i] = 0; // By default, do not pass on priority // to next driver (current may not have it) pass_on = 0; if (has_priority) begin if (request[i]) grant_gen[i] = 1; else pass_on = 1; end end end endmodule