diff --git a/modules/wishbone/wb_crossbar/sdwb_rom.vhd b/modules/wishbone/wb_crossbar/sdwb_rom.vhd new file mode 100644 index 0000000000000000000000000000000000000000..248894e634291ec115f6f166a344febea349e745 --- /dev/null +++ b/modules/wishbone/wb_crossbar/sdwb_rom.vhd @@ -0,0 +1,111 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use work.wishbone_pkg.all; + +entity sdwb_rom is + generic( + g_layout : t_sdwb_device_array; + g_bus_end : unsigned(63 downto 0)); + port( + clk_sys_i : in std_logic; + slave_i : in t_wishbone_slave_in; + slave_o : out t_wishbone_slave_out); +end sdwb_rom; + +architecture rtl of sdwb_rom is + function f_ceil_log2(x : natural) return natural is + begin + if x <= 1 + then return 0; + else return f_ceil_log2((x+1)/2) +1; + end if; + end f_ceil_log2; + + constant c_version : natural := 1; + constant c_date : natural := 16#20120305#; + constant c_rom_description : string(1 to 16) := "WB4-Crossbar-GSI"; + + -- The ROM must describe all slaves and the crossbar itself + alias c_layout : t_sdwb_device_array(1 to g_layout'length) is g_layout; + constant c_used_entries : natural := g_layout'length + 1; + constant c_rom_entries : natural := 2**f_ceil_log2(c_used_entries); -- next power of 2 + constant c_sdwb_words : natural := c_sdwb_device_length / c_wishbone_data_width; + constant c_rom_words : natural := c_rom_entries * c_sdwb_words; + constant c_rom_depth : natural := f_ceil_log2(c_rom_words); + constant c_rom_lowbits : natural := f_ceil_log2(c_wishbone_data_width / 8); + + type t_rom is array(c_rom_words-1 downto 0) of t_wishbone_data; + function f_build_rom + return t_rom is + variable res : t_rom := (others => (others => '0')); + variable sdwb_device : std_logic_vector(0 to c_sdwb_device_length-1) := (others => '0'); + begin + sdwb_device( 0 to 127) := not x"40f6e98c29eae24c7e6461ae8d2af247"; -- magic + sdwb_device(128 to 191) := std_logic_vector(g_bus_end); -- bus_end + sdwb_device(192 to 207) := std_logic_vector(to_unsigned(c_used_entries, 8)); -- sdwb_records + sdwb_device(208 to 215) := x"01"; -- sdwb_ver_major + sdwb_device(216 to 223) := x"00"; -- sdwb_ver_minor + sdwb_device(224 to 255) := x"00000651"; -- bus_vendor (GSI) + sdwb_device(256 to 287) := x"00000004"; -- bus_device + sdwb_device(288 to 319) := std_logic_vector(to_unsigned(c_version, 32)); -- bus_version + sdwb_device(320 to 351) := std_logic_vector(to_unsigned(c_date, 32)); -- bus_date + sdwb_device(352 to 383) := x"00000000"; -- bus_flags + for i in 1 to 16 loop + sdwb_device(376+i*8 to 383+i*8) := + std_logic_vector(to_unsigned(character'pos(c_rom_description(i)), 8)); + end loop; + + for i in 0 to c_sdwb_words-1 loop + res(i) := + sdwb_device(i*c_wishbone_data_width to (i+1)*c_wishbone_data_width-1); + end loop; + + for slave in 1 to c_used_entries-1 loop + sdwb_device( 0 to 63) := std_logic_vector(c_layout(slave).wbd_begin); + sdwb_device( 64 to 127) := std_logic_vector(c_layout(slave).wbd_end); + sdwb_device(128 to 191) := std_logic_vector(c_layout(slave).sdwb_child); + sdwb_device(192 to 199) := c_layout(slave).wbd_flags; + sdwb_device(200 to 207) := c_layout(slave).wbd_width; + sdwb_device(208 to 215) := std_logic_vector(c_layout(slave).abi_ver_major); + sdwb_device(216 to 223) := std_logic_vector(c_layout(slave).abi_ver_minor); + sdwb_device(224 to 255) := c_layout(slave).abi_class; + sdwb_device(256 to 287) := c_layout(slave).dev_vendor; + sdwb_device(288 to 319) := c_layout(slave).dev_device; + sdwb_device(320 to 351) := c_layout(slave).dev_version; + sdwb_device(352 to 383) := c_layout(slave).dev_date; + for i in 1 to 16 loop + -- string to ascii + sdwb_device(376+i*8 to 383+i*8) := + std_logic_vector(to_unsigned(character'pos(g_layout(slave).description(i)), 8)); + end loop; + + for i in 0 to c_sdwb_words-1 loop + res(slave*c_sdwb_words + i) := + sdwb_device(i*c_wishbone_data_width to (i+1)*c_wishbone_data_width-1); + end loop; + end loop; + return res; + end f_build_rom; + + signal rom : t_rom := f_build_rom; + signal adr_reg : unsigned(c_rom_depth-1 downto 0); + +begin + -- Simple ROM; ignore we/sel/dat + slave_o.err <= '0'; + slave_o.rty <= '0'; + slave_o.stall <= '0'; + slave_o.int <= '0'; -- Tom sucks! This should not be here. + + slave_o.dat <= rom(to_integer(adr_reg)); + + slave_clk : process(clk_sys_i) + begin + if (rising_edge(clk_sys_i)) then + adr_reg <= unsigned(slave_i.adr(c_rom_depth+c_rom_lowbits-1 downto c_rom_lowbits)); + slave_o.ack <= slave_i.cyc and slave_i.stb; + end if; + end process; + +end rtl; diff --git a/modules/wishbone/wb_crossbar/xwb_crossbar.vhd b/modules/wishbone/wb_crossbar/xwb_crossbar.vhd index 17dbe3427472eb8dbe29dc3f3804740c0490c4b5..14ed1ddf9740786ed4a7f42cbd96eaa90f04e35e 100644 --- a/modules/wishbone/wb_crossbar/xwb_crossbar.vhd +++ b/modules/wishbone/wb_crossbar/xwb_crossbar.vhd @@ -18,9 +18,8 @@ -- All participants must support the same data bus width. -- -- If a master raises STB_O with an address not mapped by the crossbar, --- ERR_I will be raised. If the crossbar has overlapping address ranges, --- the lowest numbered slave is selected. If two masters address the same --- slave simultaneously, the lowest numbered master is granted access. +-- ERR_I will be raised. If two masters address the same slave +-- simultaneously, the lowest numbered master is granted access. -- -- The implementation of this crossbar locks a master to a slave so long as -- CYC_O is held high. @@ -40,6 +39,7 @@ ------------------------------------------------------------------------------- -- Revisions : -- Date Version Author Description +-- 2012-03-05 3.0 wterpstra made address generic and check overlap -- 2011-11-04 2.0 wterpstra timing improvements -- 2011-06-08 1.0 wterpstra import from SVN ------------------------------------------------------------------------------- @@ -54,8 +54,10 @@ entity xwb_crossbar is generic( g_num_masters : integer := 2; g_num_slaves : integer := 1; - g_registered : boolean := false - ); + g_registered : boolean := false; + -- Address of the slaves connected + g_address : t_wishbone_address_array; + g_mask : t_wishbone_address_array); port( clk_sys_i : in std_logic; rst_n_i : in std_logic; @@ -64,14 +66,13 @@ entity xwb_crossbar is slave_o : out t_wishbone_slave_out_array(g_num_masters-1 downto 0); -- Slave connections (INTERCON is a master) master_i : in t_wishbone_master_in_array(g_num_slaves-1 downto 0); - master_o : out t_wishbone_master_out_array(g_num_slaves-1 downto 0); - -- Address of the slaves connected - cfg_address_i : in t_wishbone_address_array(g_num_slaves-1 downto 0); - cfg_mask_i : in t_wishbone_address_array(g_num_slaves-1 downto 0) - ); + master_o : out t_wishbone_master_out_array(g_num_slaves-1 downto 0)); end xwb_crossbar; architecture rtl of xwb_crossbar is + alias c_address : t_wishbone_address_array(g_num_slaves-1 downto 0) is g_address; + alias c_mask : t_wishbone_address_array(g_num_slaves-1 downto 0) is g_mask; + -- Crossbar connection matrix type matrix is array (g_num_masters-1 downto 0, g_num_slaves downto 0) of std_logic; @@ -144,8 +145,8 @@ architecture rtl of xwb_crossbar is return output; end ks_OR; - -- Impure because it accesses cfg_{address_i, mask_i} - impure function matrix_logic( + -- Impure because it accesses c_{address, mask} + function matrix_logic( matrix_old : matrix; slave_i : t_wishbone_slave_in_array(g_num_masters-1 downto 0)) return matrix @@ -182,7 +183,7 @@ architecture rtl of xwb_crossbar is -- Decode the request address to see if master wants access for master in g_num_masters-1 downto 0 loop for slave in g_num_slaves-1 downto 0 loop - tmp := not vector_OR((slave_i(master).ADR and cfg_mask_i(slave)) xor cfg_address_i(slave)); + tmp := not vector_OR((slave_i(master).ADR and c_mask(slave)) xor c_address(slave)); tmp_column(slave) := tmp; request(master, slave) := slave_i(master).CYC and slave_i(master).STB and tmp; end loop; @@ -362,4 +363,6 @@ begin master_matrix : for master in g_num_masters-1 downto 0 generate slave_o(master) <= master_logic(master, granted, master_ie); end generate; + + -- !!! check for overlap end rtl; diff --git a/modules/wishbone/wb_crossbar/xwb_sdwb_crossbar.vhd b/modules/wishbone/wb_crossbar/xwb_sdwb_crossbar.vhd index 28a68345dcb68332cbcd58f7c8a0a9e0a95e1088..52bc97aaf4e5a7c5080282717707c8db5d47e389 100644 --- a/modules/wishbone/wb_crossbar/xwb_sdwb_crossbar.vhd +++ b/modules/wishbone/wb_crossbar/xwb_sdwb_crossbar.vhd @@ -8,8 +8,8 @@ entity xwb_sdwb_crossbar is g_num_masters : natural := 1; g_num_slaves : natural := 1; g_registered : boolean := false; - g_address : t_wishbone_address_array; - g_mask : t_wishbone_address_array; + g_wraparound : boolean := true; + g_layout : t_sdwb_device_array; g_sdwb_addr : t_wishbone_address); port( clk_sys_i : in std_logic; @@ -23,81 +23,118 @@ entity xwb_sdwb_crossbar is end xwb_sdwb_crossbar; architecture rtl of xwb_sdwb_crossbar is - function ceil_log2(x : natural) return natural is + -- Step 1. Find the size of the bus address lines + type bus_size is record + bus_end : unsigned(63 downto 0); + bus_bits : natural; + end record bus_size; + + function f_bus_size return bus_size is + variable result : bus_size; + begin + if not g_wraparound then + result.bus_bits := c_wishbone_address_width; + result.bus_end := (others => '0'); + for i in 0 to c_wishbone_address_width-1 loop + result.bus_end(i) := '1'; + end loop; + else + result.bus_end := (others => '0'); + for i in g_layout'range loop + if g_layout(i).wbd_end > result.bus_end then + result.bus_end := g_layout(i).wbd_end; + end if; + end loop; + -- round result up to a power of two -1 + result.bus_bits := 0; + for i in 0 to 63 loop + if result.bus_end(i) = '1' then + result.bus_bits := i + 1; + end if; + end loop; + for i in 62 downto 0 loop + result.bus_end(i) := result.bus_end(i) or result.bus_end(i+1); + end loop; + end if; + return result; + end f_bus_size; + + constant c_bus_size : bus_size := f_bus_size; + constant c_bus_bits : natural := c_bus_size.bus_bits; + constant c_bus_end : unsigned(63 downto 0) := c_bus_size.bus_end; + + function f_addresses return t_wishbone_address_array is + variable result : t_wishbone_address_array(g_layout'range); + begin + for i in g_layout'range loop + result(i) := std_logic_vector(g_layout(i).wbd_begin(c_wishbone_address_width-1 downto 0)); + -- !!! report if address is too big + -- !!! report if end < begin + end loop; + return result; + end f_addresses; + + function f_masks return t_wishbone_address_array is + variable result : t_wishbone_address_array(g_layout'range); + variable size : unsigned(63 downto 0); + begin + for i in g_layout'range loop + size := (g_layout(i).wbd_end - g_layout(i).wbd_begin); + -- !!! report if size not a power of 2 + -- !!! report if address is misaligned + result(i) := std_logic_vector(c_bus_bits - size); + end loop; + return result; + end f_masks; + + function f_ceil_log2(x : natural) return natural is begin if x <= 1 then return 0; - else return ceil_log2((x+1)/2) +1; + else return f_ceil_log2((x+1)/2) +1; end if; - end ceil_log2; + end f_ceil_log2; - -- Our next crossbar will have one extra slave - -- The ROM must describe all slaves and the crossbar itself - constant c_rom_entries : natural := 2**ceil_log2(g_num_slaves + 2); - constant c_sdwb_words : natural := c_sdwb_device_length / c_wishbone_data_width; - constant c_rom_words : natural := c_rom_entries * c_sdwb_words; - constant c_rom_depth : natural := ceil_log2(c_rom_words); - constant c_rom_lowbits : natural := ceil_log2(c_wishbone_data_width / 8); - constant c_rom_mask : t_wishbone_address := - not std_logic_vector(to_unsigned((c_rom_words*c_wishbone_data_width/8) - 1, - c_wishbone_address_width)); + -- How much space does the ROM need? + constant c_used_entries : natural := g_layout'length + 1; + constant c_rom_entries : natural := 2**f_ceil_log2(c_used_entries); -- next power of 2 + constant c_sdwb_bytes : natural := c_sdwb_device_length / 8; + constant c_rom_bytes : natural := c_rom_entries * c_sdwb_bytes; + constant c_rom_mask : unsigned(63 downto 0) := c_bus_bits - to_unsigned(c_rom_bytes-1, 64); + constant c_sdwb_mask : t_wishbone_address := std_logic_vector(c_rom_mask(c_wishbone_address_width-1 downto 0)); constant c_address : t_wishbone_address_array(g_num_slaves downto 0) := - g_sdwb_addr & g_address(g_num_slaves-1 downto 0); + g_sdwb_addr & f_addresses; constant c_mask : t_wishbone_address_array(g_num_slaves downto 0) := - c_rom_mask & g_mask(g_num_slaves-1 downto 0); + c_sdwb_mask & f_masks; - type t_rom is array(c_rom_words-1 downto 0) of t_wishbone_data; - function build_rom - return t_rom is - variable res : t_rom := (others => (others => '0')); - variable sdwb_device : std_logic_vector(c_sdwb_device_length-1 downto 0) := (others => '0'); - begin - for slave in 1 to g_num_slaves loop - res(slave*c_sdwb_words+0) := c_address(slave-1); - res(slave*c_sdwb_words+1) := c_mask(slave-1); - end loop; - return res; - end build_rom; - - signal rom : t_rom := build_rom; - signal rom_i : t_wishbone_slave_in; - signal rom_o : t_wishbone_slave_out; - signal rom_reg : unsigned(c_rom_depth-1 downto 0); - signal master_i_1 : t_wishbone_master_in_array(g_num_slaves downto 0); signal master_o_1 : t_wishbone_master_out_array(g_num_slaves downto 0); begin - master_i_1 <= rom_o & master_i; + master_i_1(g_num_slaves-1 downto 0) <= master_i; master_o <= master_o_1(g_num_slaves-1 downto 0); - rom_i <= master_o_1(g_num_slaves); - -- Simple ROM; ignore we/sel/dat - rom_o.err <= '0'; - rom_o.rty <= '0'; - rom_o.stall <= '0'; - rom_o.int <= '0'; -- Tom sucks! This should not be here. - rom_o.dat <= rom(to_integer(rom_reg)); - rom_clk : process(clk_sys_i) - begin - if (rising_edge(clk_sys_i)) then - rom_reg <= unsigned(rom_i.adr(c_rom_depth+c_rom_lowbits-1 downto c_rom_lowbits)); - rom_o.ack <= rom_i.cyc and rom_i.stb; - end if; - end process; + rom : sdwb_rom + generic map( + g_layout => g_layout, + g_bus_end => c_bus_end) + port map( + clk_sys_i => clk_sys_i, + slave_i => master_o_1(g_num_slaves), + slave_o => master_i_1(g_num_slaves)); crossbar : xwb_crossbar generic map( g_num_masters => g_num_masters, g_num_slaves => g_num_slaves + 1, - g_registered => g_registered) + g_registered => g_registered, + g_address => c_address, + g_mask => c_mask) port map( clk_sys_i => clk_sys_i, rst_n_i => rst_n_i, slave_i => slave_i, slave_o => slave_o, master_i => master_i_1, - master_o => master_o_1, - cfg_address_i => c_address, - cfg_mask_i => c_mask); + master_o => master_o_1); end rtl; diff --git a/modules/wishbone/wishbone_pkg.vhd b/modules/wishbone/wishbone_pkg.vhd index a1f56a2a1403f0bf977c206387a0afc9799c2747..04811c54fefb532990e111ef6fb8f35bf4a7efb6 100644 --- a/modules/wishbone/wishbone_pkg.vhd +++ b/modules/wishbone/wishbone_pkg.vhd @@ -73,21 +73,21 @@ package wishbone_pkg is ------------------------------------------------------------------------------ constant c_sdwb_device_length : natural := 512; -- bits type t_sdwb_device is record - vendor : std_logic_vector(63 downto 0); - device : std_logic_vector(31 downto 0); - wbd_width : std_logic_vector(7 downto 0); - wbd_reserved : std_logic_vector(7 downto 0); - wbd_ver_major : std_logic_vector(7 downto 0); - wbd_ver_minor : std_logic_vector(7 downto 0); - hdl_base : std_logic_vector(63 downto 0); - hdl_size : std_logic_vector(63 downto 0); - wbd_flags : std_logic_vector(31 downto 0); - hdl_class : std_logic_vector(31 downto 0); - hdl_version : std_logic_vector(31 downto 0); - hdl_date : std_logic_vector(31 downto 0); - description : string(1 to 16); + wbd_begin : unsigned(63 downto 0); + wbd_end : unsigned(63 downto 0); + sdwb_child : unsigned(63 downto 0); + wbd_flags : std_logic_vector(7 downto 0); + wbd_width : std_logic_vector(7 downto 0); + abi_ver_major : unsigned(7 downto 0); + abi_ver_minor : unsigned(7 downto 0); + abi_class : std_logic_vector(31 downto 0); + dev_vendor : std_logic_vector(31 downto 0); + dev_device : std_logic_vector(31 downto 0); + dev_version : std_logic_vector(31 downto 0); + dev_date : std_logic_vector(31 downto 0); + description : string(1 to 16); end record t_sdwb_device; - type t_sdwb_devices_array is array(natural range <>) of t_sdwb_device; + type t_sdwb_device_array is array(natural range <>) of t_sdwb_device; ------------------------------------------------------------------------------ -- Components declaration @@ -200,25 +200,25 @@ package wishbone_pkg is generic ( g_num_masters : integer; g_num_slaves : integer; - g_registered : boolean); + g_registered : boolean; + g_address : t_wishbone_address_array; + g_mask : t_wishbone_address_array); port ( clk_sys_i : in std_logic; rst_n_i : in std_logic; slave_i : in t_wishbone_slave_in_array(g_num_masters-1 downto 0); slave_o : out t_wishbone_slave_out_array(g_num_masters-1 downto 0); master_i : in t_wishbone_master_in_array(g_num_slaves-1 downto 0); - master_o : out t_wishbone_master_out_array(g_num_slaves-1 downto 0); - cfg_address_i : in t_wishbone_address_array(g_num_slaves-1 downto 0); - cfg_mask_i : in t_wishbone_address_array(g_num_slaves-1 downto 0)); + master_o : out t_wishbone_master_out_array(g_num_slaves-1 downto 0)); end component; component xwb_sdwb_crossbar generic ( g_num_masters : integer; g_num_slaves : integer; - g_registered : boolean; - g_address : t_wishbone_address_array; - g_mask : t_wishbone_address_array; + g_registered : boolean := false; + g_wraparound : boolean := true; + g_layout : t_sdwb_device_array; g_sdwb_addr : t_wishbone_address); port ( clk_sys_i : in std_logic; @@ -229,6 +229,16 @@ package wishbone_pkg is master_o : out t_wishbone_master_out_array(g_num_slaves-1 downto 0)); end component; + component sdwb_rom is + generic( + g_layout : t_sdwb_device_array; + g_bus_end : unsigned(63 downto 0)); + port( + clk_sys_i : in std_logic; + slave_i : in t_wishbone_slave_in; + slave_o : out t_wishbone_slave_out); + end component; + component xwb_dpram generic ( g_size : natural;