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;

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;

Loading…
Cancel
Save