137 lines
5.3 KiB
VHDL
137 lines
5.3 KiB
VHDL
|
-- -------------------------------------------------------------------------- --
|
||
|
-- 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;
|