From: Benjamin Herrenschmidt Date: Wed, 23 Oct 2019 03:01:48 +0000 (+1100) Subject: wb_arbiter: Avoid IDLE cycle when not changing master X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=472d8f94a240a3f739ed9fae574e97e1fc57ab8f;p=microwatt.git wb_arbiter: Avoid IDLE cycle when not changing master 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 --- diff --git a/wishbone_arbiter.vhdl b/wishbone_arbiter.vhdl index 8e2358b..b206df1 100644 --- a/wishbone_arbiter.vhdl +++ b/wishbone_arbiter.vhdl @@ -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;