-- TODO: Use an array of master/slaves with parametric size
entity wishbone_arbiter is
+ generic(
+ NUM_MASTERS : positive := 3
+ );
port (clk : in std_ulogic;
rst : in std_ulogic;
- wb1_in : in wishbone_master_out;
- wb1_out : out wishbone_slave_out;
+ wb_masters_in : in wishbone_master_out_vector(0 to NUM_MASTERS-1);
+ wb_masters_out : out wishbone_slave_out_vector(0 to NUM_MASTERS-1);
- wb2_in : in wishbone_master_out;
- wb2_out : out wishbone_slave_out;
-
- wb3_in : in wishbone_master_out;
- wb3_out : out wishbone_slave_out;
-
- wb_out : out wishbone_master_out;
- wb_in : in wishbone_slave_out
+ wb_slave_out : out wishbone_master_out;
+ wb_slave_in : in wishbone_slave_out
);
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;
+ subtype wb_arb_master_t is integer range 0 to NUM_MASTERS-1;
+ signal candidate, selected : wb_arb_master_t;
+ signal busy : std_ulogic;
begin
- wishbone_muxes: process(state, wb_in, wb1_in, wb2_in, wb3_in)
+ busy <= wb_masters_in(selected).cyc;
+
+ wishbone_muxes: process(selected, candidate, busy, wb_slave_in, wb_masters_in)
+ variable early_sel : wb_arb_master_t;
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;
+ early_sel := selected;
+ if busy = '0' then
+ early_sel := candidate;
+ end if;
+ wb_slave_out <= wb_masters_in(early_sel);
+ for i in 0 to NUM_MASTERS-1 loop
+ wb_masters_out(i).dat <= wb_slave_in.dat;
+ wb_masters_out(i).ack <= wb_slave_in.ack when early_sel = i else '0';
+ wb_masters_out(i).stall <= wb_slave_in.stall when early_sel = i else '1';
+ end loop;
+ end process;
- -- 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';
+ -- 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(all)
+ begin
+ candidate <= selected;
+ for i in NUM_MASTERS-1 downto 0 loop
+ if wb_masters_in(i).cyc = '1' then
+ candidate <= i;
+ end if;
+ end loop;
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 <= 0;
+ elsif busy = '0' then
+ selected <= candidate;
end if;
end if;
end process;