trashernet-soc/fpga/hdl/generics/wishbone_arbiter.vhd

137 lines
5.3 KiB
VHDL
Raw Normal View History

2024-06-12 20:03:04 +02:00
-- -------------------------------------------------------------------------- --
-- TRASHERNET SoC - A Trashy Ethernet SoC for FPGAs --
-- -------------------------------------------------------------------------- --
-- TODO
-- -------------------------------------------------------------------------- --
-- Author : Markus Koch <markus@notsyncing.net>
-- 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;