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 <benh@kernel.crashing.org>
pull/118/head
Benjamin Herrenschmidt 5 years ago
parent 336f0e0690
commit 472d8f94a2

@ -24,58 +24,53 @@ entity wishbone_arbiter is
end wishbone_arbiter; end wishbone_arbiter;


architecture behave of wishbone_arbiter is architecture behave of wishbone_arbiter is
type wishbone_arbiter_state_t is (IDLE, WB1_BUSY, WB2_BUSY, WB3_BUSY); type wb_arb_master_t is (WB1, WB2, WB3);
signal state : wishbone_arbiter_state_t := IDLE; signal candidate, selected : wb_arb_master_t;
begin 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 begin
-- Requests from masters are fully muxed -- Requests from masters are fully muxed
wb_out <= wb1_in when state = WB1_BUSY else wb_out <= wb1_in when selected = WB1 else
wb2_in when state = WB2_BUSY else wb2_in when selected = WB2 else
wb3_in when state = WB3_BUSY else wb3_in when selected = WB3;
wishbone_master_out_init;


-- Responses from slave don't need to mux the data bus -- Responses from slave don't need to mux the data bus
wb1_out.dat <= wb_in.dat; wb1_out.dat <= wb_in.dat;
wb2_out.dat <= wb_in.dat; wb2_out.dat <= wb_in.dat;
wb3_out.dat <= wb_in.dat; wb3_out.dat <= wb_in.dat;
wb1_out.ack <= wb_in.ack when state = WB1_BUSY else '0'; wb1_out.ack <= wb_in.ack when selected = WB1 else '0';
wb2_out.ack <= wb_in.ack when state = WB2_BUSY else '0'; wb2_out.ack <= wb_in.ack when selected = WB2 else '0';
wb3_out.ack <= wb_in.ack when state = WB3_BUSY else '0'; wb3_out.ack <= wb_in.ack when selected = WB3 else '0';
wb1_out.stall <= wb_in.stall when state = WB1_BUSY else '1'; wb1_out.stall <= wb_in.stall when selected = WB1 else '1';
wb2_out.stall <= wb_in.stall when state = WB2_BUSY else '1'; wb2_out.stall <= wb_in.stall when selected = WB2 else '1';
wb3_out.stall <= wb_in.stall when state = WB3_BUSY 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; end process;


wishbone_arbiter_process: process(clk) wishbone_arbiter_process: process(clk)
begin begin
if rising_edge(clk) then if rising_edge(clk) then
if rst = '1' then if rst = '1' then
state <= IDLE; selected <= WB1;
else elsif wb_out.cyc = '0' then
case state is selected <= candidate;
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;
end if; end if;
end if; end if;
end process; end process;

Loading…
Cancel
Save