-- -------------------------------------------------------------------------- -- -- TRASHERNET SoC - A Trashy Ethernet SoC for FPGAs -- -- -------------------------------------------------------------------------- -- -- TODO -- -------------------------------------------------------------------------- -- -- Author : Markus Koch -- Contributors : None -- License : Mozilla Public License (MPL) Version 2 -- -------------------------------------------------------------------------- -- library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; use work.wishbone_pkg.all; entity wishbone_arbiter is generic( ASYNC : boolean := true; -- Generate the switch as a fully asynchronous circuit when false, register outputs when true. NO_DEAD_SLAVE : boolean := true -- Connect to slave 0,0 on no address match (saves resources) ); port( clk : in std_logic; -- System clock, must be shared with all slaves and masters. rst : in std_logic; -- Asynchronous reset -- Master connections (crossbar is a slave) masters_o : in wishbone_slave_in_vector; -- Connections to masters (crossbar is slave), inputs to crossbar masters_i : out wishbone_slave_out_vector; -- Connections to masters (crossbar is slave), outputs from crossbar -- Slave connections (crossbar is a master) slaves_o : in wishbone_master_in_vector; -- Connections to slaves (crossbar is master), inputs to crossbar slaves_i : out wishbone_master_out_vector; -- Connections to slaves (crossbar is master), outputs from crossbar -- Address configuration of the slaves connected address : in wishbone_address_vector; -- Base address for each slave connection. Must be the same size as `master_i` and `master_o` mask : in wishbone_address_vector -- Bit mask for slave base addresses. Must be the same size as `master_i` and `master_o` ); end wishbone_arbiter; architecture rtl of wishbone_arbiter is subtype slave_index is integer range 0 to slaves_i'length - 1; subtype master_index is integer range 0 to masters_i'length - 1; signal slave_sel : slave_index; signal master_sel : master_index; signal matched : std_logic; constant SLEEPY_MASTER : wishbone_master_out := (cyc => '0', stb => '0', adr => (others => '-'), sel => (others => '-'), we => '-', dat => (others => '-')); constant SLEEPY_SLAVE : wishbone_slave_out := (ack => '0', err => '0', rty => '0', stall => '1', dat => (others => '-')); procedure generate_logic( signal mo : in wishbone_slave_in_vector; signal so : in wishbone_master_in_vector; signal ssel : out slave_index; signal msel : out master_index; signal mtch : out std_logic ) is begin ssel <= 0; msel <= 0; mtch <= '0'; master_loop : for master_id in mo'range loop if (mo(master_id).cyc and mo(master_id).stb) then slave_loop : for slave_id in so'range loop if (mo(master_id).adr and mask(slave_id)) = address(slave_id) then ssel <= slave_id; msel <= master_id; mtch <= '1'; exit master_loop; end if; end loop; end if; end loop; end procedure generate_logic; procedure connect_slaves( signal mo : in wishbone_slave_in_vector; signal mi : out wishbone_slave_out_vector; signal so : in wishbone_master_in_vector; signal si : out wishbone_master_out_vector; constant ssel : in slave_index; constant msel : in master_index; signal mtch : in std_logic ) is begin for slave_id in si'range loop si(slave_id) <= SLEEPY_MASTER; -- Always connect data path from selected master to *all* slave inputs si(slave_id).dat <= mo(msel).dat; si(slave_id).we <= mo(msel).we; si(slave_id).sel <= mo(msel).sel; si(slave_id).adr <= mo(msel).adr and (not mask(ssel)); if (mtch = '1' or NO_DEAD_SLAVE) and (slave_id = ssel) then -- If we are the currently active slave, then also connect these (else SLEEPY default) si(slave_id).cyc <= mo(msel).cyc; si(slave_id).stb <= mo(msel).stb; end if; end loop; for master_id in mi'range loop mi(master_id) <= SLEEPY_SLAVE; -- Always connect data path from selected slave to *all* master inputs mi(master_id).dat <= so(ssel).dat; if (mtch = '1' or NO_DEAD_SLAVE) and (master_id = msel) then -- If we are the currently active master, also connect these (else SLEEPY default) mi(master_id).ack <= so(ssel).ack; mi(master_id).err <= so(ssel).err; mi(master_id).rty <= so(ssel).rty; mi(master_id).stall <= so(ssel).stall; end if; end loop; end procedure connect_slaves; begin assert ASYNC = true report "Arbiter does not support ASYNC mode" severity failure; sync : if ASYNC generate name : process(masters_o, slaves_o, address, mask) is begin generate_logic(masters_o, slaves_o, slave_sel, master_sel, matched); end process name; else generate sync_proc : process(rst, clk) is begin if rst then slave_sel <= 0; master_sel <= 0; elsif rising_edge(clk) then generate_logic(masters_o, slaves_o, slave_sel, master_sel, matched); end if; end process sync_proc; end generate sync; name : process(masters_o, slaves_o, slave_sel, master_sel, matched, mask) is begin connect_slaves(masters_o, masters_i, slaves_o, slaves_i, slave_sel, master_sel, matched); end process name; end rtl;