wb_arbiter: Avoid IDLE cycle when not changing master
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>
Wed, 23 Oct 2019 03:01:48 +0000 (14:01 +1100)
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>
Wed, 30 Oct 2019 02:18:58 +0000 (13:18 +1100)
Consecutive accesses from the same master shouldn't need an IDLE
cycle. Completely remove the IDLE state and switch master when
the bus is idle, but stay on the last selected one between cycles.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
wishbone_arbiter.vhdl

index 8e2358b253bf53239bb21398613627bec60f8aca..b206df1561bcc60cf254a92609046d3ee2fa0483 100644 (file)
@@ -24,58 +24,53 @@ entity wishbone_arbiter is
 end wishbone_arbiter;
 
 architecture behave of wishbone_arbiter is
-    type wishbone_arbiter_state_t is (IDLE, WB1_BUSY, WB2_BUSY, WB3_BUSY);
-    signal state : wishbone_arbiter_state_t := IDLE;
+    type wb_arb_master_t is (WB1, WB2, WB3);
+    signal candidate, selected : wb_arb_master_t;
 begin
 
-    wishbone_muxes: process(state, wb_in, wb1_in, wb2_in, wb3_in)
+    wishbone_muxes: process(selected, wb_in, wb1_in, wb2_in, wb3_in)
     begin
        -- Requests from masters are fully muxed
-       wb_out <= wb1_in when state = WB1_BUSY else
-                 wb2_in when state = WB2_BUSY else
-                 wb3_in when state = WB3_BUSY else
-                 wishbone_master_out_init;
+       wb_out <= wb1_in when selected = WB1 else
+                 wb2_in when selected = WB2 else
+                 wb3_in when selected = WB3;
 
        -- Responses from slave don't need to mux the data bus
        wb1_out.dat <= wb_in.dat;
        wb2_out.dat <= wb_in.dat;
        wb3_out.dat <= wb_in.dat;
-       wb1_out.ack <= wb_in.ack when state = WB1_BUSY else '0';
-       wb2_out.ack <= wb_in.ack when state = WB2_BUSY else '0';
-       wb3_out.ack <= wb_in.ack when state = WB3_BUSY else '0';
-       wb1_out.stall <= wb_in.stall when state = WB1_BUSY else '1';
-       wb2_out.stall <= wb_in.stall when state = WB2_BUSY else '1';
-       wb3_out.stall <= wb_in.stall when state = WB3_BUSY else '1';
+       wb1_out.ack <= wb_in.ack when selected = WB1 else '0';
+       wb2_out.ack <= wb_in.ack when selected = WB2 else '0';
+       wb3_out.ack <= wb_in.ack when selected = WB3 else '0';
+       wb1_out.stall <= wb_in.stall when selected = WB1 else '1';
+       wb2_out.stall <= wb_in.stall when selected = WB2 else '1';
+       wb3_out.stall <= wb_in.stall when selected = WB3 else '1';
+    end process;
+
+    -- Candidate selection is dumb, priority order... we could
+    -- instead consider some form of fairness but it's not really
+    -- an issue at the moment.
+    --
+    wishbone_candidate: process(wb1_in.cyc, wb2_in.cyc, wb3_in.cyc)
+    begin
+       if wb1_in.cyc = '1' then
+           candidate <= WB1;
+       elsif wb2_in.cyc = '1' then
+           candidate <= WB2;
+       elsif wb3_in.cyc = '1' then
+           candidate <= WB3;
+       else
+           candidate <= selected;
+       end if;
     end process;
 
     wishbone_arbiter_process: process(clk)
     begin
        if rising_edge(clk) then
            if rst = '1' then
-               state <= IDLE;
-           else
-               case state is
-               when IDLE =>
-                   if wb1_in.cyc = '1' then
-                       state <= WB1_BUSY;
-                   elsif wb2_in.cyc = '1' then
-                       state <= WB2_BUSY;
-                   elsif wb3_in.cyc = '1' then
-                       state <= WB3_BUSY;
-                   end if;
-               when WB1_BUSY =>
-                   if wb1_in.cyc = '0' then
-                       state <= IDLE;
-                   end if;
-               when WB2_BUSY =>
-                   if wb2_in.cyc = '0' then
-                       state <= IDLE;
-                   end if;
-               when WB3_BUSY =>
-                   if wb3_in.cyc = '0' then
-                       state <= IDLE;
-                   end if;
-               end case;
+               selected <= WB1;
+           elsif wb_out.cyc = '0' then
+               selected <= candidate;
            end if;
        end if;
     end process;