[prim/arbiter] Keep current request until acked
If downstream isn't ready (arb_ready = 0), then if higher priority
request comes later but before ready, it outtakes previous request,
which results in the arb_data change.
It doesn't harm as the data supposes to be used when valid & ready. It,
however, looks bad on the crossbar. inside `tlul_socket_m1` it could
happen that the downstream request write data or address could be
changed without notice, and it violates TL-UL spec.
This is related to #152
diff --git a/hw/ip/prim/rtl/prim_arbiter.sv b/hw/ip/prim/rtl/prim_arbiter.sv
index 2336300..c9e7bd0 100644
--- a/hw/ip/prim/rtl/prim_arbiter.sv
+++ b/hw/ip/prim/rtl/prim_arbiter.sv
@@ -30,6 +30,8 @@
logic [N-1:0] mask, mask_next;
+ logic [N-1:0] winner;
+
assign masked_req = mask & req;
assign arb_req = (|masked_req) ? masked_req : req;
@@ -44,16 +46,21 @@
end
// Grant Generation: Leading-One detector
- assign gnt = (arb_ready) ? ppc_out ^ {ppc_out[N-2:0], 1'b0} : '0;
+ assign winner = ppc_out ^ {ppc_out[N-2:0], 1'b0};
+ assign gnt = (arb_ready) ? winner : '0;
+
assign arb_valid = |req;
// Mask Generation
assign mask_next = {ppc_out[N-2:0], 1'b0};
always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
mask <= '0;
- end else if (|req && arb_ready) begin
+ end else if (arb_valid && arb_ready) begin
// Latch only when requests available
mask <= mask_next;
+ end else if (arb_valid && !arb_ready) begin
+ // Downstream isn't yet ready so, keep current request alive. (First come first serve)
+ mask <= ppc_out;
end
end
@@ -61,7 +68,7 @@
always_comb begin
arb_data = '0;
for (int i = 0 ; i < N ; i++) begin
- if (gnt[i]) arb_data = req_data[i];
+ if (winner[i]) arb_data = req_data[i];
end
end
endmodule