In Part 1, we established a fundamental rule of multi-master hardware: you can never route raw, asynchronous requests directly into a combinatorial priority encoder. Doing so guarantees catastrophic metastability and bus collisions.
To solve this spatial contention problem, we must capture and stabilize the incoming requests using a synchronization matrix before the Arbiter makes a decision. But building this in RTL is not just about slapping a few flip-flops onto a wire. It requires scalable architecture and a deep understanding of timing penalties.
Architecting the N-Channel Matrix
When designing an Arbiter for a modern System-on-Chip (SoC), hardcoding synchronizers for a fixed number of masters is poor practice. Your architecture might have three masters today, but what happens when the next revision of the board adds two more?

Professional RTL should be scalable. We can achieve this by writing a parameterized matrix using Verilog's generate blocks. This allows the synthesizer to automatically construct the exact number of parallel 2-Flip-Flop (2-FF) synchronizer chains required based on a single parameter.
Here is the clean, synthesis-ready RTL for a scalable synchronization array:
module sync_matrix #(
parameter NUM_MASTERS = 4 // Defines how many masters share the bus
) (
input wire clk_arb, // The Arbiter's core clock
input wire rst_n, // Active-low reset
input wire [NUM_MASTERS-1:0] async_req, // Raw requests from different domains
output reg [NUM_MASTERS-1:0] sync_req // Stabilized requests safe for evaluation
);
// Stage 1 registers to absorb metastability
reg [NUM_MASTERS-1:0] meta_reg;
// Generate a 2-FF synchronizer chain for every master request
genvar i;
generate
for (i = 0; i < NUM_MASTERS; i = i + 1) begin : gen_sync_chains
always @(posedge clk_arb or negedge rst_n) begin
if (!rst_n) begin
meta_reg[i] <= 1'b0;
sync_req[i] <= 1'b0;
end else begin
// Shift the asynchronous request through the pipeline
meta_reg[i] <= async_req[i];
sync_req[i] <= meta_reg[i];
end
end
end
endgenerate
endmoduleWith this architecture, the Arbiter core only ever evaluates the sync_req bus, which is guaranteed to be stable and perfectly aligned with clk_arb.
Physics Isn't Free: The Latency Penalty
We have solved the metastability problem, but safety in hardware always comes at a cost. In this case, the cost is latency.
Take a look at Panel 2 in the visual guide. Because we are using a 2-FF synchronizer, an asynchronous request must propagate through two clock edges of clk_arb before it emerges as a valid, synchronized request.
This introduces a minimum 2-cycle latency penalty. If a master asserts a request, it will sit idle for at least two Arbiter clock cycles before the arbitration logic even sees the request, let alone grants the bus.
Optimizing the Arbiter Clock and MTBF
How do we minimize this penalty so our fast masters don't starve? The standard architectural approach is to run the Arbiter core on a clock frequency ($f_c$) that is significantly faster than the master clocks. If clk_arb runs at 300 MHz, a 2-cycle penalty is only ~6.6 nanoseconds, which is a negligible wait time for a 50 MHz peripheral.
However, increasing the Arbiter's clock frequency introduces a new challenge governed by the Mean Time Between Failures (MTBF) equation:

Notice that $f_c$ (the clock frequency) is in the denominator. As you drive the Arbiter's clock faster to reduce the absolute time penalty, you actively reduce the MTBF. The flip-flops have less physical time to resolve their metastable states.
If your Arbiter clock is aggressively fast, a 2-FF synchronizer might no longer provide a safe enough MTBF. In high-frequency designs, you may be forced to increase the pipeline depth to a 3-FF synchronizer. You trade an additional clock cycle of latency for a massive exponential recovery in MTBF.
In Part 3, we will cross into the Arbiter logic core itself. With our requests safely synchronized and stabilized, we will design the combinatorial decision trees that evaluate these requests and issue the grants, breaking down the critical differences between Fixed Priority and Round-Robin architectures.
If you want to view the complete Verilog source code for this multi-master asynchronous architecture right now, you can explore my GitHub repository here:
🔗 Heterogeneous CDC Arbiter Repository