diff --git a/modules/genrams/Manifest.py b/modules/genrams/Manifest.py index 572151fd4b30ff2455e607ced36031f0e5368749..d987832ca3c96786476d2f888b25fc1c88d0cff2 100644 --- a/modules/genrams/Manifest.py +++ b/modules/genrams/Manifest.py @@ -1,13 +1,10 @@ files = [ - "genram_pkg.vhd", - "memory_loader_pkg.vhd", - "generic_shiftreg_fifo.vhd", - "inferred_sync_fifo.vhd", - "inferred_async_fifo.vhd"]; + "genram_pkg.vhd", + "memory_loader_pkg.vhd"]; if (target == "altera"): - modules = {"local" : "altera"} + modules = {"local" : ["altera", "generic"]} elif (target == "xilinx" and syn_device[0:4].upper()=="XC6V"): modules = {"local" : ["xilinx", "xilinx/virtex6"]} elif (target == "xilinx"): diff --git a/modules/genrams/altera/Manifest.py b/modules/genrams/altera/Manifest.py index 1d702f9bda47a1bfbdc85ddc8c4ac302e333f2be..4f1fe441a71a27afe895727f84c2f84576e204d0 100644 --- a/modules/genrams/altera/Manifest.py +++ b/modules/genrams/altera/Manifest.py @@ -1,8 +1,8 @@ files = [ -"generic_async_fifo.vhd", +"altera_async_fifo.vhd", "generic_simple_dpram.vhd", "generic_dpram.vhd", "generic_spram.vhd", "generic_dpram_mixed.vhd", -"generic_sync_fifo.vhd", +"altera_sync_fifo.vhd", "gc_shiftreg.vhd"] diff --git a/modules/genrams/altera/generic_async_fifo.vhd b/modules/genrams/altera/altera_async_fifo.vhd similarity index 98% rename from modules/genrams/altera/generic_async_fifo.vhd rename to modules/genrams/altera/altera_async_fifo.vhd index 71a2d49840902a554cab9a4ac7a6030cea408e67..bbcaf42319bac1282e4d8d2e9102a0af5a12d819 100644 --- a/modules/genrams/altera/generic_async_fifo.vhd +++ b/modules/genrams/altera/altera_async_fifo.vhd @@ -34,7 +34,7 @@ use altera_mf.all; use work.genram_pkg.all; -entity generic_async_fifo is +entity altera_async_fifo is generic ( g_data_width : natural; @@ -85,9 +85,9 @@ entity generic_async_fifo is rd_count_o : out std_logic_vector(f_log2_size(g_size)-1 downto 0) ); -end generic_async_fifo; +end altera_async_fifo; -architecture syn of generic_async_fifo is +architecture syn of altera_async_fifo is component dcfifo generic ( diff --git a/modules/genrams/altera/generic_sync_fifo.vhd b/modules/genrams/altera/altera_sync_fifo.vhd similarity index 98% rename from modules/genrams/altera/generic_sync_fifo.vhd rename to modules/genrams/altera/altera_sync_fifo.vhd index c3de0e04c83350142afbe2a59bec05bcb0e8365f..00b578d077a2728144e8b1e925237ca50d172073 100644 --- a/modules/genrams/altera/generic_sync_fifo.vhd +++ b/modules/genrams/altera/altera_sync_fifo.vhd @@ -32,7 +32,7 @@ use altera_mf.all; use work.genram_pkg.all; -entity generic_sync_fifo is +entity altera_sync_fifo is generic ( g_data_width : natural; @@ -67,9 +67,9 @@ entity generic_sync_fifo is count_o : out std_logic_vector(f_log2_size(g_size)-1 downto 0) ); -end generic_sync_fifo; +end altera_sync_fifo; -architecture syn of generic_sync_fifo is +architecture syn of altera_sync_fifo is component scfifo generic ( diff --git a/modules/genrams/generic/Manifest.py b/modules/genrams/generic/Manifest.py index 22f6cb8d282070cae341a1261c509b72041276d2..18c923407bc00c98130631b3c3593f9cae7f38cf 100644 --- a/modules/genrams/generic/Manifest.py +++ b/modules/genrams/generic/Manifest.py @@ -1,2 +1,5 @@ files = ["generic_async_fifo.vhd", -"generic_sync_fifo.vhd"] +"generic_sync_fifo.vhd", +"inferred_sync_fifo.vhd", +"generic_shiftreg_fifo.vhd", +"inferred_async_fifo.vhd"] diff --git a/modules/genrams/generic_shiftreg_fifo.vhd b/modules/genrams/generic/generic_shiftreg_fifo.vhd similarity index 100% rename from modules/genrams/generic_shiftreg_fifo.vhd rename to modules/genrams/generic/generic_shiftreg_fifo.vhd diff --git a/modules/genrams/inferred_async_fifo.vhd b/modules/genrams/generic/inferred_async_fifo.vhd similarity index 100% rename from modules/genrams/inferred_async_fifo.vhd rename to modules/genrams/generic/inferred_async_fifo.vhd diff --git a/modules/genrams/inferred_sync_fifo.vhd b/modules/genrams/generic/inferred_sync_fifo.vhd similarity index 99% rename from modules/genrams/inferred_sync_fifo.vhd rename to modules/genrams/generic/inferred_sync_fifo.vhd index 2714d8fe77dfa2f66f341661d452c40bc8ac7c6c..aad112f82231257e41b744e3dac0766f7eda1c5c 100644 --- a/modules/genrams/inferred_sync_fifo.vhd +++ b/modules/genrams/generic/inferred_sync_fifo.vhd @@ -91,7 +91,7 @@ begin -- syn g_data_width => g_data_width, g_size => g_size, g_with_byte_enable => false, - g_addr_conflict_resolution => "read_first", + g_addr_conflict_resolution => "dont_care", g_dual_clock => false) port map ( rst_n_i => rst_n_i, diff --git a/modules/wishbone/Manifest.py b/modules/wishbone/Manifest.py index 11c93159462e346faa034c1df2ad27d22456ed16..6ebc4aeb0dc26c76703c4ca61debd7bcd98be96d 100644 --- a/modules/wishbone/Manifest.py +++ b/modules/wishbone/Manifest.py @@ -20,7 +20,8 @@ modules = { "local" : [ "wb_spi_flash", "wb_simple_pwm", "wb_i2c_bridge", - "wbgen2" + "wbgen2", + "wbgenplus", ]} files = [ diff --git a/modules/wishbone/wb_crossbar/sdb_rom.vhd b/modules/wishbone/wb_crossbar/sdb_rom.vhd index 1c47f7534d033f1e39ef728749440c6f40636e48..aa09950f99f48c2f972d03d23f4237ecdeb2063b 100644 --- a/modules/wishbone/wb_crossbar/sdb_rom.vhd +++ b/modules/wishbone/wb_crossbar/sdb_rom.vhd @@ -5,83 +5,153 @@ use work.wishbone_pkg.all; entity sdb_rom is generic( - g_layout : t_sdb_record_array; - g_bus_end : unsigned(63 downto 0)); + g_layout : t_sdb_record_array; + g_masters : natural; + 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); + clk_sys_i : in std_logic; + master_i : in std_logic_vector(g_masters-1 downto 0); + slave_i : in t_wishbone_slave_in; + slave_o : out t_wishbone_slave_out); end sdb_rom; architecture rtl of sdb_rom is alias c_layout : t_sdb_record_array(g_layout'length downto 1) is g_layout; -- The ROM must describe all slaves, the crossbar itself and the optional information records - constant c_used_entries : natural := c_layout'length + 1; + constant c_used_entries : natural := c_layout'high + 1; constant c_rom_entries : natural := 2**f_ceil_log2(c_used_entries); -- next power of 2 constant c_sdb_words : natural := c_sdb_device_length / c_wishbone_data_width; constant c_rom_words : natural := c_rom_entries * c_sdb_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); + -- Index of the MSI entry in SDB + type t_nat_array is array(g_masters-1 downto 0) of natural; + function f_master_positions return t_nat_array is + variable typ : std_logic_vector(7 downto 0); + variable result : t_nat_array; + variable master : natural := 0; + begin + for rec in c_layout'low to c_layout'high loop + typ := c_layout(rec)(7 downto 0); + case typ is + when x"03" | x"f3" => + assert master < g_masters + report "Too many msi records found" + severity failure; + + result(master) := rec; + master := master + 1; + + when others => null; + end case; + end loop; + + if master = 0 then + result := (others => g_masters); + else + assert master = g_masters + report "Insufficient msi records found (" & Integer'image(master) & "/" & Integer'image(g_masters) & ")" + severity failure; + end if; + return result; + end f_master_positions; + + constant c_master_positions : t_nat_array := f_master_positions; + constant c_msi : boolean := c_master_positions(0) /= g_masters; + + function f_msi_flag_index(y : std_logic_vector) return std_logic_vector is + variable offset : unsigned(c_rom_depth-1 downto 0) := (others => '0'); + variable result : std_logic_vector(c_rom_depth-1 downto 0) := (others => '0'); + begin + for i in c_master_positions'range loop + if c_msi then + offset := to_unsigned(c_master_positions(i)*16, offset'length); + end if; + for b in result'range loop + result(b) := result(b) or (offset(b) and y(i)); + end loop; + end loop; + return result; + end f_msi_flag_index; + 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 sdb_device : std_logic_vector(c_sdb_device_length-1 downto 0) := (others => '0'); + variable sdb_record : t_sdb_record; variable sdb_component : t_sdb_component; begin - sdb_device(511 downto 480) := x"5344422D" ; -- sdb_magic - sdb_device(479 downto 464) := std_logic_vector(to_unsigned(c_used_entries, 16)); -- sdb_records - sdb_device(463 downto 456) := x"01"; -- sdb_version - sdb_device(455 downto 448) := x"00"; -- sdb_bus_type = sdb_wishbone - sdb_device( 7 downto 0) := x"00"; -- record_type = sdb_interconnect + sdb_record(511 downto 480) := x"5344422D" ; -- sdb_magic + sdb_record(479 downto 464) := std_logic_vector(to_unsigned(c_used_entries, 16)); -- sdb_records + sdb_record(463 downto 456) := x"01"; -- sdb_version + sdb_record(455 downto 448) := x"00"; -- sdb_bus_type = sdb_wishbone + sdb_record( 7 downto 0) := x"00"; -- record_type = sdb_interconnect sdb_component.addr_first := (others => '0'); sdb_component.addr_last := std_logic_vector(g_bus_end); sdb_component.product.vendor_id := x"0000000000000651"; -- GSI sdb_component.product.device_id := x"e6a542c9"; - sdb_component.product.version := x"00000002"; + sdb_component.product.version := x"00000003"; sdb_component.product.date := x"20120511"; sdb_component.product.name := "WB4-Crossbar-GSI "; - sdb_device(447 downto 8) := f_sdb_embed_component(sdb_component, (others => '0')); + sdb_record(447 downto 8) := f_sdb_embed_component(sdb_component, (others => '0')); for i in 0 to c_sdb_words-1 loop res(c_sdb_words-1-i) := - sdb_device((i+1)*c_wishbone_data_width-1 downto i*c_wishbone_data_width); + sdb_record((i+1)*c_wishbone_data_width-1 downto i*c_wishbone_data_width); end loop; - for slave in 1 to c_used_entries-1 loop - sdb_device(511 downto 0) := c_layout(slave); + for idx in c_layout'range loop + sdb_record := c_layout(idx); + + -- All local/temporary types => empty record + if sdb_record(7 downto 4) = x"f" then + sdb_record(3 downto 0) := x"f"; + end if; for i in 0 to c_sdb_words-1 loop - res((slave+1)*c_sdb_words-1-i) := - sdb_device((i+1)*c_wishbone_data_width-1 downto i*c_wishbone_data_width); + res((idx+1)*c_sdb_words-1-i) := + sdb_record((i+1)*c_wishbone_data_width-1 downto i*c_wishbone_data_width); 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); + + signal s_adr : unsigned(c_rom_depth-1 downto 0); + signal s_sel : unsigned(c_rom_depth-1 downto 0); + + signal r_rom : t_wishbone_data; + signal r_flag : t_wishbone_data; + signal r_ack : std_logic; begin - -- Simple ROM; ignore we/sel/dat + + slave_o.dat <= r_rom or r_flag; + slave_o.ack <= r_ack; 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)); + s_adr <= unsigned(slave_i.adr(c_rom_depth+c_rom_lowbits-1 downto c_rom_lowbits)); + s_sel <= unsigned(f_msi_flag_index(master_i)); 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; + r_ack <= slave_i.cyc and slave_i.stb; + r_rom <= rom(to_integer(s_adr)); + r_flag <= (others => '0'); + if s_adr = s_sel and c_msi then + r_flag(r_flag'high) <= '1'; + end if; end if; end process; diff --git a/modules/wishbone/wb_crossbar/xwb_crossbar.vhd b/modules/wishbone/wb_crossbar/xwb_crossbar.vhd index bfce52a5000e4d7c586dfba8d17014f883778cae..265e3495b9ebbcdb11882865bd2b7bb755a3bd7f 100644 --- a/modules/wishbone/wb_crossbar/xwb_crossbar.vhd +++ b/modules/wishbone/wb_crossbar/xwb_crossbar.vhd @@ -66,7 +66,9 @@ 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)); + master_o : out t_wishbone_master_out_array(g_num_slaves-1 downto 0); + -- Master granted access to SDB for use by MSI crossbar (please ignore it) + sdb_sel_o : out std_logic_vector(g_num_masters-1 downto 0)); end xwb_crossbar; architecture rtl of xwb_crossbar is @@ -77,22 +79,40 @@ architecture rtl of xwb_crossbar is function f_ranges_ok return boolean is - constant zero : t_wishbone_address := (others => '0'); + constant zero : t_wishbone_address := (others => '0'); + constant align : std_logic_vector(f_ceil_log2(c_wishbone_data_width)-4 downto 0) := (others => '0'); begin - for i in 0 to g_num_slaves-2 loop - for j in i+1 to g_num_slaves-1 loop - assert not (((c_mask(i) and c_mask(j)) and (c_address(i) xor c_address(j))) = zero) or - ((c_mask(i) or not c_address(i)) = zero) or -- disconnected slave? - ((c_mask(j) or not c_address(j)) = zero) -- disconnected slave? - report "Address ranges must be distinct (slaves " & - Integer'image(i) & "[" & f_bits2string(c_address(i)) & "/" & - f_bits2string(c_mask(i)) & "] & " & - Integer'image(j) & "[" & f_bits2string(c_address(j)) & "/" & - f_bits2string(c_mask(j)) & "])" - severity Failure; + -- all (i,j) with 0 <= i < j < n + if g_num_slaves > 1 then + for i in 0 to g_num_slaves-2 loop + for j in i+1 to g_num_slaves-1 loop + assert not (((c_mask(i) and c_mask(j)) and (c_address(i) xor c_address(j))) = zero) or + ((c_mask(i) or not c_address(i)) = zero) or -- disconnected slave? + ((c_mask(j) or not c_address(j)) = zero) -- disconnected slave? + report "Address ranges must be distinct (slaves " & + Integer'image(i) & "[" & f_bits2string(c_address(i)) & "/" & + f_bits2string(c_mask(i)) & "] & " & + Integer'image(j) & "[" & f_bits2string(c_address(j)) & "/" & + f_bits2string(c_mask(j)) & "])" + severity Failure; + end loop; end loop; - end loop; + end if; for i in 0 to g_num_slaves-1 loop + assert (c_address(i) and not c_mask(i)) = zero or -- at least 1 bit outside mask + (not c_address(i) or c_mask(i)) = zero -- all bits outside mask (= disconnected) + report "Address bits not in mask; slave #" & + Integer'image(i) & "[" & f_bits2string(c_address(i)) & "/" & + f_bits2string(c_mask(i)) & "]" + severity Failure; + + assert c_mask(i)(align'range) = align + report "Address space smaller than a wishbone register; slave #" & + Integer'image(i) & "[" & f_bits2string(c_address(i)) & "/" & + f_bits2string(c_mask(i)) & "]" + severity Failure; + + -- Working case report "Mapping slave #" & Integer'image(i) & "[" & f_bits2string(c_address(i)) & "/" & f_bits2string(c_mask(i)) & "]" @@ -398,4 +418,10 @@ begin master_matrixs : for master in g_num_masters-1 downto 0 generate slave_o(master) <= master_logic(master, granted, master_ie); end generate; + + -- Tell SDB which master is accessing it (SDB is last slave) + sdb_masters : for master in g_num_masters-1 downto 0 generate + sdb_sel_o(master) <= granted(master, g_num_slaves-1); + end generate; + end rtl; diff --git a/modules/wishbone/wb_crossbar/xwb_sdb_crossbar.vhd b/modules/wishbone/wb_crossbar/xwb_sdb_crossbar.vhd index f03f03c3de7a531a712c142f4831f99e07f2fe01..361b52f039855d90efe28d8c77e3cab48767bbbd 100644 --- a/modules/wishbone/wb_crossbar/xwb_sdb_crossbar.vhd +++ b/modules/wishbone/wb_crossbar/xwb_sdb_crossbar.vhd @@ -15,11 +15,15 @@ entity xwb_sdb_crossbar is clk_sys_i : in std_logic; rst_n_i : in std_logic; -- Master connections (INTERCON is a slave) - 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); + 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); + msi_master_i : in t_wishbone_master_in_array (g_num_masters-1 downto 0) := (others => cc_dummy_master_in); + msi_master_o : out t_wishbone_master_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)); + 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); + msi_slave_i : in t_wishbone_slave_in_array (g_num_slaves -1 downto 0) := (others => cc_dummy_slave_in); + msi_slave_o : out t_wishbone_slave_out_array (g_num_slaves -1 downto 0)); end xwb_sdb_crossbar; architecture rtl of xwb_sdb_crossbar is @@ -42,11 +46,17 @@ architecture rtl of xwb_sdb_crossbar is constant c_rom_entries : natural := 2**f_ceil_log2(c_used_entries); -- next power of 2 constant c_sdb_bytes : natural := c_sdb_device_length / 8; constant c_rom_bytes : natural := c_rom_entries * c_sdb_bytes; + + type t_sizes is record + bus_last : unsigned(63 downto 0); + msi_last : unsigned(63 downto 0); + end record t_sizes; -- Step 2. Find the size of the bus - function f_bus_end return unsigned is - variable result : unsigned(63 downto 0); - variable sdb_component : t_sdb_component; + function f_sizes return t_sizes is + variable result : t_sizes; + variable typ : std_logic_vector(7 downto 0); + variable last : unsigned(63 downto 0); constant zero : t_wishbone_address := (others => '0'); begin -- The SDB block must be aligned @@ -54,123 +64,183 @@ architecture rtl of xwb_sdb_crossbar is report "SDB address is not aligned (" & f_bits2string(g_sdb_addr) & "). This is not supported by the crossbar." severity Failure; + -- The ROM will be an addressed slave as well + result.bus_last := (others => '0'); + result.bus_last(g_sdb_addr'range) := unsigned(g_sdb_addr); + result.bus_last := result.bus_last + to_unsigned(c_rom_bytes, 64) - 1; + + -- There are no MSI targets by default + result.msi_last := (others => '0'); + + for i in c_layout'range loop + typ := c_layout(i)(7 downto 0); + last := unsigned(f_sdb_extract_component(c_layout(i)(447 downto 8)).addr_last); + case typ is + when x"01" => if last > result.bus_last then result.bus_last := last; end if; + when x"02" => if last > result.bus_last then result.bus_last := last; end if; + when x"03" => if last > result.msi_last then result.msi_last := last; end if; + when others => null; + end case; + end loop; + + -- round result up to a power of two -1 + for i in 62 downto 0 loop + result.bus_last(i) := result.bus_last(i) or result.bus_last(i+1); + result.msi_last(i) := result.msi_last(i) or result.msi_last(i+1); + end loop; + + -- Not a wraparound bus? Ignore all that hard work. if not g_wraparound then - result := (others => '0'); + result.bus_last := (others => '0'); for i in 0 to c_wishbone_address_width-1 loop - result(i) := '1'; - end loop; - else - -- The ROM will be an addressed slave as well - result := (others => '0'); - result(c_wishbone_address_width-1 downto 0) := unsigned(g_sdb_addr); - result := result + to_unsigned(c_rom_bytes, 64) - 1; - - for i in g_num_slaves-1 downto 0 loop - if c_layout(i)(7) /= '1' then -- Ignore meta-information - sdb_component := f_sdb_extract_component(c_layout(i)(447 downto 8)); - if unsigned(sdb_component.addr_last) > result then - result := unsigned(sdb_component.addr_last); - end if; - end if; - end loop; - -- round result up to a power of two -1 - for i in 62 downto 0 loop - result(i) := result(i) or result(i+1); + result.bus_last(i) := '1'; end loop; end if; + return result; - end f_bus_end; + end f_sizes; - constant c_bus_end : unsigned(63 downto 0) := f_bus_end; + constant c_sizes : t_sizes := f_sizes; + + type t_addresses is record + bus_address : t_wishbone_address_array(g_num_slaves -1 downto 0); + bus_mask : t_wishbone_address_array(g_num_slaves -1 downto 0); + msi_address : t_wishbone_address_array(g_num_masters-1 downto 0); + msi_mask : t_wishbone_address_array(g_num_masters-1 downto 0); + end record t_addresses; -- Step 3. Map device address begin values - function f_addresses return t_wishbone_address_array is - variable result : t_wishbone_address_array(g_num_slaves-1 downto 0); + function f_addresses return t_addresses is + variable result : t_addresses; + + variable typ : std_logic_vector(7 downto 0); variable sdb_component : t_sdb_component; - variable extend : unsigned(63 downto 0) := (others => '0'); + + variable address : t_wishbone_address; + variable extend : std_logic_vector(63 downto 0) := (others => '0'); + variable size : unsigned(63 downto 0); + + variable bus_index : natural := 0; + variable msi_index : natural := 0; begin - for i in g_num_slaves-1 downto 0 loop - if c_layout(i)(7) = '1' then - -- ignore meta-data - result(i) := (others => '1'); - else - sdb_component := f_sdb_extract_component(c_layout(i)(447 downto 8)); - result(i) := sdb_component.addr_first(c_wishbone_address_width-1 downto 0); - - -- Range must be valid - assert unsigned(sdb_component.addr_first) <= unsigned(sdb_component.addr_last) - report "Wishbone slave device #" & Integer'image(i) & " (" & f_trim(sdb_component.product.name) & ") sdb_component.addr_first (" & f_bits2string(sdb_component.addr_first) & ") must precede sdb_component.addr_last address (" & f_bits2string(sdb_component.addr_last) & ")." - severity Failure; - - -- Address must fit - extend(c_wishbone_address_width-1 downto 0) := unsigned(result(i)); - assert unsigned(sdb_component.addr_first) = extend - report "Wishbone slave device #" & Integer'image(i) & " (" & f_trim(sdb_component.product.name) & ") sdb_component.addr_first (" & f_bits2string(sdb_component.addr_first) & " does not fit in t_wishbone_address." - severity Failure; - end if; - end loop; - return result; - end f_addresses; + for i in c_layout'low to c_layout'high loop + typ := c_layout(i)(7 downto 0); + sdb_component := f_sdb_extract_component(c_layout(i)(447 downto 8)); - -- Step 3. Map device address end values - function f_masks return t_wishbone_address_array is - variable result : t_wishbone_address_array(g_num_slaves-1 downto 0); - variable sdb_component : t_sdb_component; - variable size : unsigned(63 downto 0); - constant zero : unsigned(63 downto 0) := (others => '0'); - begin - for i in g_num_slaves-1 downto 0 loop - if c_layout(i)(7) = '1' then - -- ignore meta-data - result(i) := (others => '0'); - else - sdb_component := f_sdb_extract_component(c_layout(i)(447 downto 8)); - size := unsigned(sdb_component.addr_last) - unsigned(sdb_component.addr_first); - - -- size must be of the form 000000...00001111...1 - assert (size and (size + to_unsigned(1, 64))) = zero - report "Wishbone slave device #" & Integer'image(i) & " (" & f_trim(sdb_component.product.name) & ") has an address range that is not a power of 2 minus one (" & f_bits2string(std_logic_vector(size)) & "). This is not supported by the crossbar." - severity Warning; - - -- fix the size up to the form 000...0001111...11 - for j in c_wishbone_address_width-2 downto 0 loop - size(j) := size(j) or size(j+1); - end loop; - - -- the base address must be aligned to the size - assert (unsigned(sdb_component.addr_first) and size) = zero - report "Wishbone slave device #" & Integer'image(i) & " (" & f_trim(sdb_component.product.name) & ") sdb_component.addr_first (" & f_bits2string(sdb_component.addr_first) & ") is not aligned. This is not supported by the crossbar." - severity Failure; - - size := c_bus_end - size; - result(i) := std_logic_vector(size(c_wishbone_address_width-1 downto 0)); - end if; + -- Range must be valid + assert unsigned(sdb_component.addr_first) <= unsigned(sdb_component.addr_last) + report "Wishbone slave device #" & Integer'image(i) & " (" & f_trim(sdb_component.product.name) & ") sdb_component.addr_first (" & f_bits2string(sdb_component.addr_first) & ") must precede sdb_component.addr_last address (" & f_bits2string(sdb_component.addr_last) & ")." + severity Failure; + + -- Address must fit within Wishbone address width + address := sdb_component.addr_first(address'range); + extend(address'range) := address; + assert sdb_component.addr_first = extend + report "Wishbone slave device #" & Integer'image(i) & " (" & f_trim(sdb_component.product.name) & ") sdb_component.addr_first (" & f_bits2string(sdb_component.addr_first) & " does not fit in t_wishbone_address." + severity Failure; + + size := unsigned(sdb_component.addr_last) - unsigned(sdb_component.addr_first); + -- size must be of the form 000000...00001111...1 + assert (size and (size + 1)) = 0 + report "Wishbone slave device #" & Integer'image(i) & " (" & f_trim(sdb_component.product.name) & ") has an address range that is not a power of 2 minus one (" & f_bits2string(std_logic_vector(size)) & "). This is not supported by the crossbar." + severity Warning; + + -- fix the size up to the form 000...0001111...11 + for j in c_wishbone_address_width-2 downto 0 loop + size(j) := size(j) or size(j+1); + end loop; + + -- the base address must be aligned to the size + assert (unsigned(sdb_component.addr_first) and size) = 0 + report "Wishbone slave device #" & Integer'image(i) & " (" & f_trim(sdb_component.product.name) & ") sdb_component.addr_first (" & f_bits2string(sdb_component.addr_first) & ") is not aligned. This is not supported by the crossbar." + severity Failure; + + -- Record the address for posterity + case typ is + when x"01" | x"02" => + assert bus_index < g_num_slaves + report "Too many device and bridge records found in g_layout" + severity Failure; + + size := c_sizes.bus_last - size; + result.bus_address(bus_index) := address; + result.bus_mask (bus_index) := std_logic_vector(size(address'range)); + bus_index := bus_index + 1; + + when x"03" => + assert msi_index < g_num_masters + report "Too many msi records found in g_layout" + severity Failure; + + size := c_sizes.msi_last - size; + result.msi_address(msi_index) := address; + result.msi_mask (msi_index) := std_logic_vector(size(address'range)); + msi_index := msi_index + 1; + + when x"f1" | x"f2" => + result.bus_address(bus_index) := (others => '1'); + result.bus_mask (bus_index) := (others => '0'); + bus_index := bus_index + 1; + + when x"f3" => + result.msi_address(msi_index) := (others => '1'); + result.msi_mask (msi_index) := (others => '0'); + msi_index := msi_index + 1; + + when others => null; + end case; end loop; + + -- There must be exactly the right number of slave SDB records + assert bus_index = g_num_slaves + report "Too few device and bridge records found in g_layout" + severity Failure; + + -- It is OK to have no master records (backwards compat) + if msi_index = 0 then + result.msi_address := (others => (others => '1')); + result.msi_mask := (others => (others => '0')); + else + assert msi_index = g_num_masters + report "Too few msi records found in g_layout" + severity Failure; + end if; + return result; - end f_masks; + end f_addresses; + constant c_addresses : t_addresses := f_addresses; + + -- Figure out the mask for the SDB slave constant c_rom_mask : unsigned(63 downto 0) := - c_bus_end - to_unsigned(c_rom_bytes-1, 64); + c_sizes.bus_last - to_unsigned(c_rom_bytes-1, 64); constant c_sdb_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_sdb_addr & f_addresses; + -- Fill bus crossbar parameters + constant c_address : t_wishbone_address_array(g_num_slaves downto 0) := + g_sdb_addr & c_addresses.bus_address; constant c_mask : t_wishbone_address_array(g_num_slaves downto 0) := - c_sdb_mask & f_masks; + c_sdb_mask & c_addresses.bus_mask; 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); + signal sdb_sel : std_logic_vector(g_num_masters-1 downto 0); + begin + + -- Pass-through all slave ports except SDB master_i_1(g_num_slaves-1 downto 0) <= master_i; master_o <= master_o_1(g_num_slaves-1 downto 0); rom : sdb_rom generic map( g_layout => c_layout, - g_bus_end => c_bus_end) + g_masters => g_num_masters, + g_bus_end => c_sizes.bus_last) port map( clk_sys_i => clk_sys_i, + master_i => sdb_sel, slave_i => master_o_1(g_num_slaves), slave_o => master_i_1(g_num_slaves)); @@ -187,5 +257,23 @@ begin slave_i => slave_i, slave_o => slave_o, master_i => master_i_1, - master_o => master_o_1); + master_o => master_o_1, + sdb_sel_o => sdb_sel); + + msi : xwb_crossbar + generic map( + g_num_masters => g_num_slaves, + g_num_slaves => g_num_masters, + g_registered => g_registered, + g_address => c_addresses.msi_address, + g_mask => c_addresses.msi_mask) + port map( + clk_sys_i => clk_sys_i, + rst_n_i => rst_n_i, + slave_i => msi_slave_i, + slave_o => msi_slave_o, + master_i => msi_master_i, + master_o => msi_master_o, + sdb_sel_o => open); + end rtl; diff --git a/modules/wishbone/wbgenplus/Manifest.py b/modules/wishbone/wbgenplus/Manifest.py new file mode 100644 index 0000000000000000000000000000000000000000..61622b747ff052e2df9b52ca14c3e7ec006964a0 --- /dev/null +++ b/modules/wishbone/wbgenplus/Manifest.py @@ -0,0 +1,5 @@ +files = ["wb_skidpad.vhd", + "wbgenplus_pkg.vhd", + +] + diff --git a/modules/wishbone/wbgenplus/wb_skidpad.vhd b/modules/wishbone/wbgenplus/wb_skidpad.vhd new file mode 100644 index 0000000000000000000000000000000000000000..2e16a8088529bd72543103736aaa59c8ad247788 --- /dev/null +++ b/modules/wishbone/wbgenplus/wb_skidpad.vhd @@ -0,0 +1,77 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +entity wb_skidpad is +generic( + g_adrbits : natural := 32 --Number of bits in adr + +); +Port( + clk_i : std_logic; + rst_n_i : std_logic; + + push_i : in std_logic; + pop_i : in std_logic; + full_o : out std_logic; + empty_o : out std_logic; + + adr_i : in std_logic_vector(g_adrbits-1 downto 0); + dat_i : in std_logic_vector(32-1 downto 0); + sel_i : in std_logic_vector(4-1 downto 0); + we_i : in std_logic; + + adr_o : out std_logic_vector(g_adrbits-1 downto 0); + dat_o : out std_logic_vector(32-1 downto 0); + sel_o : out std_logic_vector(4-1 downto 0); + we_o : out std_logic + + +); +end wb_skidpad; + +architecture rtl of wb_skidpad is + + signal s_full, s_valid : std_logic; + signal r_full0, r_full1 : std_logic := '0'; + signal r_buff0, r_buff1 : std_logic_vector(g_adrbits + 32 + 4 + 1 -1 downto 0); + signal s_mux : std_logic_vector(g_adrbits + 32 + 4 + 1 -1 downto 0); + +begin + + s_valid <= r_full1 or r_full0; + s_full <= r_full1 and r_full0; + + control : process(clk_i, rst_n_i) is + begin + if rst_n_i = '0' then + r_full0 <= '0'; + r_full1 <= '0'; + elsif rising_edge(clk_i) then + r_full0 <= push_i or s_full; + r_full1 <= not pop_i and s_valid; + end if; + end process; + + bulk : process(clk_i) is + begin + if rising_edge(clk_i) then + if s_full = '0' then + r_buff0 <= adr_i & dat_i & sel_i & we_i; + end if; + if r_full1 = '0' then + r_buff1 <= r_buff0; + end if; + end if; + end process; + + s_mux <= r_buff1 when r_full1='1' else r_buff0; + adr_o <= s_mux(37+g_adrbits-1 downto 37); + dat_o <= s_mux(36 downto 5); + sel_o <= s_mux(4 downto 1); + we_o <= s_mux(0); + + full_o <= s_full; + empty_o <= not s_valid; + +end rtl; diff --git a/modules/wishbone/wbgenplus/wbgenplus_pkg.vhd b/modules/wishbone/wbgenplus/wbgenplus_pkg.vhd new file mode 100644 index 0000000000000000000000000000000000000000..dd39c5a65cf84e1815a0aa8bf045836145b519db --- /dev/null +++ b/modules/wishbone/wbgenplus/wbgenplus_pkg.vhd @@ -0,0 +1,170 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +package wbgenplus_pkg is + + component wb_skidpad is + generic( + g_adrbits : natural := 32 --Number of bits in adr + ); + Port( + clk_i : std_logic; + rst_n_i : std_logic; + + push_i : in std_logic; + pop_i : in std_logic; + full_o : out std_logic; + empty_o : out std_logic; + + adr_i : in std_logic_vector(g_adrbits-1 downto 0); + dat_i : in std_logic_vector(32-1 downto 0); + sel_i : in std_logic_vector(4-1 downto 0); + we_i : in std_logic; + + adr_o : out std_logic_vector(g_adrbits-1 downto 0); + dat_o : out std_logic_vector(32-1 downto 0); + sel_o : out std_logic_vector(4-1 downto 0); + we_o : out std_logic + + + ); + end component; + + type matrix is array(natural range <>, natural range <>) of std_logic; + + -- assign row + + function mrst(slm : matrix) return matrix; + + -- assign row + + ---function mset(slm : matrix; slv : std_logic_vector; rowindex : natural) return matrix; + + procedure mset(signal slm : out matrix; slv : std_logic_vector; rowindex : natural); + + procedure mset_no_rng(signal slm : out matrix; slv : std_logic_vector; rowindex : natural); + + -- get std logic vector from matrix row + + function mget(slm : matrix; rowindex : natural) return std_logic_vector; + + -- flatten matrix to std logic vector + + function mflat(slm : matrix) return std_logic_vector; + + -- inflate std logic vector to matrix + function minfl(slm : matrix; slv : std_logic_vector ) return matrix; + + -- inflate std logic vector to m x n matrix + + function minflmn(slv : std_logic_vector; col_len : natural; row_len : natural) return matrix; + +end wbgenplus_pkg; + +package body wbgenplus_pkg is + + function mrst(slm : matrix) return matrix is + variable res : matrix(slm'length(1)-1 downto 0, slm'length(2)-1 downto 0); + variable row, col : natural := 0; + constant row_len : natural := slm'length(2); + constant col_len : natural := slm'length(1); + begin + for row in 0 to col_len-1 loop + for col in 0 to row_len-1 loop + res(row, col) := '0'; + end loop; + end loop; + return res; + end function; + + + procedure mset(signal slm : out matrix; slv : std_logic_vector; rowindex : natural) is + variable i : natural := 0; + begin + for i in slv'range loop + slm(rowindex, i) <= slv(i); + end loop; + end procedure; + + procedure mset_no_rng(signal slm : out matrix; slv : std_logic_vector; rowindex : natural) is + variable i : natural := 0; + variable j : natural := 0; + begin + j := 0; + for i in slv'range loop + slm(rowindex, j) <= slv(i); + j := j+1; + end loop; + end procedure; + + + -- set matrix row +-- function mset(slm : matrix; slv : std_logic_vector; rowindex : natural) return matrix is +-- variable i : natural := 0; +-- variable res : matrix(slm'length(1)-1 downto 0, slm'length(2)-1 downto 0); +-- begin +-- res := slm; +-- for i in slv'range loop +-- res(rowindex, i) := slv(i); +-- end loop; +-- return res; +-- end function; + + + -- get matrix row + function mget(slm : matrix; rowindex : natural) return std_logic_vector is + variable i : natural := 0; + variable slv : std_logic_vector(slm'high(2) downto 0); + begin + for i in slv'range loop + slv(i) := slm(rowindex, i); + end loop; + return slv; + end function; + + + -- flatten matrix to std logic vector + function mflat(slm : matrix) return std_logic_vector is + constant row_len : natural := slm'length(2); + constant col_len : natural := slm'length(1); + variable res : std_logic_vector(col_len*row_len-1 downto 0); + begin + for row in 0 to col_len-1 loop + for col in 0 to row_len-1 loop + res(row*row_len+col) := slm(row, col); + end loop; + end loop; + return res; + end function; + + + -- inflate std logic vector to matrix + function minfl(slm : matrix; slv : std_logic_vector) return matrix is + constant row_len : natural := slm'length(2); + constant col_len : natural := slm'length(1); + variable res : matrix(slm'length(1)-1 downto 0, slm'length(2)-1 downto 0); + begin + for row in 0 to col_len-1 loop + for col in 0 to row_len-1 loop + res(row, col) := slv(row*row_len+col); + end loop; + end loop; + return res; + end function; + + + -- -- inflate std logic vector to m*n matrix + function minflmn(slv : std_logic_vector; col_len : natural; row_len : natural) return matrix is + variable res : matrix(col_len-1 downto 0, row_len-1 downto 0); + begin + for row in 0 to col_len-1 loop + for col in 0 to row_len-1 loop + res(row, col) := slv(slv'length-1 - (row*row_len+col)); + end loop; + end loop; + return res; + end function; + + +end wbgenplus_pkg; diff --git a/modules/wishbone/wishbone_pkg.vhd b/modules/wishbone/wishbone_pkg.vhd index 72c8ac17f14783648f7a0b86227454b4768d8ddb..0cec2cb752b31f879fa5186b6b3371c10ed73dbc 100644 --- a/modules/wishbone/wishbone_pkg.vhd +++ b/modules/wishbone/wishbone_pkg.vhd @@ -124,6 +124,12 @@ package wishbone_pkg is sdb_component : t_sdb_component; end record t_sdb_device; + type t_sdb_msi is record + wbd_endian : std_logic; -- 0 = big, 1 = little + wbd_width : std_logic_vector(3 downto 0); -- 3=64-bit, 2=32-bit, 1=16-bit, 0=8-bit + sdb_component : t_sdb_component; + end record t_sdb_msi; + type t_sdb_bridge is record sdb_child : std_logic_vector(63 downto 0); sdb_component : t_sdb_component; @@ -146,6 +152,20 @@ package wishbone_pkg is syn_username : string(1 to 15); end record t_sdb_synthesis; + -- If you have a Wishbone master that does not receive MSI, + -- list it in the layout as 'f_sdb_auto_msi(c_null_msi, false)' + constant c_null_msi : t_sdb_msi := ( + wbd_endian => c_sdb_endian_big, + wbd_width => x"0", + sdb_component => ( + addr_first => x"0000000000000000", + addr_last => x"0000000000000000", + product => ( + vendor_id => x"0000000000000000", + device_id => x"00000000", + version => x"00000000", + date => x"00000000", + name => " "))); -- general crossbar building functions function f_sdb_create_array(g_enum_dev_id : boolean := false; @@ -165,12 +185,14 @@ package wishbone_pkg is -- Used to configure a device at a certain address function f_sdb_embed_device(device : t_sdb_device; address : t_wishbone_address) return t_sdb_record; function f_sdb_embed_bridge(bridge : t_sdb_bridge; address : t_wishbone_address) return t_sdb_record; + function f_sdb_embed_msi(msi : t_sdb_msi; address : t_wishbone_address) return t_sdb_record; function f_sdb_embed_integration(integr : t_sdb_integration) return t_sdb_record; function f_sdb_embed_repo_url(url : t_sdb_repo_url) return t_sdb_record; function f_sdb_embed_synthesis(syn : t_sdb_synthesis) return t_sdb_record; function f_sdb_extract_device(sdb_record : t_sdb_record) return t_sdb_device; function f_sdb_extract_bridge(sdb_record : t_sdb_record) return t_sdb_bridge; + function f_sdb_extract_msi(sdb_record : t_sdb_record) return t_sdb_msi; function f_sdb_extract_integration(sdb_record : t_sdb_record) return t_sdb_integration; function f_sdb_extract_repo_url(sdb_record : t_sdb_record) return t_sdb_repo_url; function f_sdb_extract_synthesis(sdb_record : t_sdb_record) return t_sdb_synthesis; @@ -178,8 +200,11 @@ package wishbone_pkg is -- Automatic crossbar mapping functions function f_sdb_auto_device(device : t_sdb_device; enable : boolean := true) return t_sdb_record; function f_sdb_auto_bridge(bridge : t_sdb_bridge; enable : boolean := true) return t_sdb_record; - function f_sdb_auto_layout(records : t_sdb_record_array) return t_sdb_record_array; - function f_sdb_auto_sdb (records : t_sdb_record_array) return t_wishbone_address; + function f_sdb_auto_msi (msi : t_sdb_msi; enable : boolean := true) return t_sdb_record; + function f_sdb_auto_layout(records: t_sdb_record_array) return t_sdb_record_array; + function f_sdb_auto_layout(slaves : t_sdb_record_array; masters : t_sdb_record_array) return t_sdb_record_array; + function f_sdb_auto_sdb (records: t_sdb_record_array) return t_wishbone_address; + function f_sdb_auto_sdb (slaves : t_sdb_record_array; masters : t_sdb_record_array) return t_wishbone_address; -- For internal use by the crossbar function f_sdb_embed_product(product : t_sdb_product) return std_logic_vector; -- (319 downto 8) @@ -307,7 +332,8 @@ package wishbone_pkg is 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)); + master_o : out t_wishbone_master_out_array(g_num_slaves-1 downto 0); + sdb_sel_o : out std_logic_vector(g_num_masters-1 downto 0)); -- leave open! end component; -- Use the f_xwb_bridge_*_sdb to bridge a crossbar to another @@ -320,6 +346,9 @@ package wishbone_pkg is g_layout : t_sdb_record_array; g_sdb_addr : t_wishbone_address) return t_sdb_bridge; + function f_xwb_msi_layout_sdb( -- determine MSI size from layout + g_layout : t_sdb_record_array) return t_sdb_bridge; + component xwb_sdb_crossbar generic ( g_num_masters : integer; @@ -329,12 +358,16 @@ package wishbone_pkg is g_layout : t_sdb_record_array; g_sdb_addr : t_wishbone_address); 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)); + 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); + msi_master_i : in t_wishbone_master_in_array (g_num_masters-1 downto 0) := (others => cc_dummy_master_in); + msi_master_o : out t_wishbone_master_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); + msi_slave_i : in t_wishbone_slave_in_array (g_num_slaves -1 downto 0) := (others => cc_dummy_slave_in); + msi_slave_o : out t_wishbone_slave_out_array (g_num_slaves -1 downto 0)); end component; component xwb_register_link -- puts a register of delay between crossbars @@ -349,10 +382,12 @@ package wishbone_pkg is component sdb_rom is generic( - g_layout : t_sdb_record_array; - g_bus_end : unsigned(63 downto 0)); + g_layout : t_sdb_record_array; + g_masters : natural; + g_bus_end : unsigned(63 downto 0)); port( clk_sys_i : in std_logic; + master_i : in std_logic_vector(g_masters-1 downto 0); slave_i : in t_wishbone_slave_in; slave_o : out t_wishbone_slave_out); end component; @@ -1196,6 +1231,36 @@ package body wishbone_pkg is return result; end; + function f_sdb_embed_msi(msi : t_sdb_msi; address : t_wishbone_address) + return t_sdb_record + is + variable result : t_sdb_record; + begin + result(511 downto 456) := (others => '0'); + result(455) := msi.wbd_endian; + result(454 downto 452) := (others => '0'); + result(451 downto 448) := msi.wbd_width; + result(447 downto 8) := f_sdb_embed_component(msi.sdb_component, address); + result(7 downto 0) := x"03"; -- msi + return result; + end; + + function f_sdb_extract_msi(sdb_record : t_sdb_record) + return t_sdb_msi + is + variable result : t_sdb_msi; + begin + result.wbd_endian := sdb_record(452); + result.wbd_width := sdb_record(451 downto 448); + result.sdb_component := f_sdb_extract_component(sdb_record(447 downto 8)); + + assert sdb_record(7 downto 0) = x"03" + report "Cannot extract t_sdb_msi from record of type " & integer'image(to_integer(unsigned(sdb_record(7 downto 0)))) & "." + severity failure; + + return result; + end; + function f_sdb_embed_integration(integr : t_sdb_integration) return t_sdb_record is @@ -1317,7 +1382,7 @@ package body wishbone_pkg is constant c_zero : t_wishbone_address := (others => '0'); variable v_empty : t_sdb_record := (others => '0'); begin - v_empty(7 downto 0) := (others => '1'); + v_empty(7 downto 0) := x"f1"; if enable then return f_sdb_embed_device(device, c_zero); else @@ -1331,7 +1396,7 @@ package body wishbone_pkg is constant c_zero : t_wishbone_address := (others => '0'); variable v_empty : t_sdb_record := (others => '0'); begin - v_empty(7 downto 0) := (others => '1'); + v_empty(7 downto 0) := x"f2"; if enable then return f_sdb_embed_bridge(bridge, c_zero); else @@ -1339,6 +1404,20 @@ package body wishbone_pkg is end if; end f_sdb_auto_bridge; + function f_sdb_auto_msi(msi : t_sdb_msi; enable : boolean := true) + return t_sdb_record + is + constant c_zero : t_wishbone_address := (others => '0'); + variable v_empty : t_sdb_record := (others => '0'); + begin + v_empty(7 downto 0) := x"f3"; + if enable then + return f_sdb_embed_msi(msi, c_zero); + else + return v_empty; + end if; + end f_sdb_auto_msi; + subtype t_usdb_address is unsigned(63 downto 0); type t_usdb_address_array is array(natural range <>) of t_usdb_address; @@ -1359,8 +1438,10 @@ package body wishbone_pkg is variable v_component : t_sdb_component; variable v_sizes : t_usdb_address_array(c_records'length downto 0); variable v_address : t_usdb_address_array(c_records'length downto 0); - variable v_map : std_logic_vector(c_records'length downto 0) := (others => '0'); - variable v_cursor : unsigned(63 downto 0) := (others => '0'); + variable v_bus_map : std_logic_vector(c_records'length downto 0) := (others => '0'); + variable v_bus_cursor: unsigned(63 downto 0) := (others => '0'); + variable v_msi_map : std_logic_vector(c_records'length downto 0) := (others => '0'); + variable v_msi_cursor: unsigned(63 downto 0) := (others => '0'); variable v_increment : unsigned(63 downto 0) := (others => '0'); variable v_type : std_logic_vector(7 downto 0); begin @@ -1379,8 +1460,9 @@ package body wishbone_pkg is if v_address(i) = c_zero then v_type := c_records(i)(7 downto 0); case v_type is - when x"01" => v_map(i) := '1'; - when x"02" => v_map(i) := '1'; + when x"01" => v_bus_map(i) := '1'; + when x"02" => v_bus_map(i) := '1'; + when x"03" => v_msi_map(i) := '1'; when others => null; end case; end if; @@ -1389,7 +1471,7 @@ package body wishbone_pkg is -- Assign the SDB record a spot as well v_address(c_records'length) := (others => '0'); v_sizes(c_records'length) := to_unsigned(c_rom_bytes-1, 64); - v_map(c_records'length) := '1'; + v_bus_map(c_records'length) := '1'; -- Start assigning addresses for j in 0 to 63 loop @@ -1397,16 +1479,24 @@ package body wishbone_pkg is v_increment(j) := '1'; for i in 0 to c_records'length loop - if v_map(i) = '1' and v_sizes(i)(j) = '0' then - v_map(i) := '0'; - v_address(i) := v_cursor; - v_cursor := v_cursor + v_increment; + if v_bus_map(i) = '1' and v_sizes(i)(j) = '0' then + v_bus_map(i) := '0'; + v_address(i) := v_bus_cursor; + v_bus_cursor := v_bus_cursor + v_increment; + end if; + if v_msi_map(i) = '1' and v_sizes(i)(j) = '0' then + v_msi_map(i) := '0'; + v_address(i) := v_msi_cursor; + v_msi_cursor := v_msi_cursor + v_increment; end if; end loop; -- Round up to the next required alignment - if v_cursor(j) = '1' then - v_cursor := v_cursor + v_increment; + if v_bus_cursor(j) = '1' then + v_bus_cursor := v_bus_cursor + v_increment; + end if; + if v_msi_cursor(j) = '1' then + v_msi_cursor := v_msi_cursor + v_increment; end if; end loop; @@ -1417,25 +1507,33 @@ package body wishbone_pkg is return t_sdb_record_array is alias c_records : t_sdb_record_array(records'length-1 downto 0) is records; + variable v_typ : std_logic_vector(7 downto 0); variable v_result : t_sdb_record_array(c_records'range) := c_records; constant c_address : t_usdb_address_array := f_sdb_auto_layout_helper(c_records); variable v_address : t_wishbone_address; begin -- Put the addresses into the mapping for i in v_result'range loop - v_address := std_logic_vector(c_address(i)(t_wishbone_address'range)); - - if c_records(i)(7 downto 0) = x"01" then - v_result(i) := f_sdb_embed_device(f_sdb_extract_device(v_result(i)), v_address); - end if; - if c_records(i)(7 downto 0) = x"02" then - v_result(i) := f_sdb_embed_bridge(f_sdb_extract_bridge(v_result(i)), v_address); - end if; + v_typ := c_records(i)(7 downto 0); + v_address := std_logic_vector(c_address(i)(t_wishbone_address'range)); + + case v_typ is + when x"01" => v_result(i) := f_sdb_embed_device(f_sdb_extract_device(v_result(i)), v_address); + when x"02" => v_result(i) := f_sdb_embed_bridge(f_sdb_extract_bridge(v_result(i)), v_address); + when x"03" => v_result(i) := f_sdb_embed_msi (f_sdb_extract_msi (v_result(i)), v_address); + when others => null; + end case; end loop; return v_result; end f_sdb_auto_layout; + function f_sdb_auto_layout(slaves : t_sdb_record_array; masters : t_sdb_record_array) + return t_sdb_record_array + is begin + return f_sdb_auto_layout(masters & slaves); + end f_sdb_auto_layout; + function f_sdb_auto_sdb(records : t_sdb_record_array) return t_wishbone_address is @@ -1444,7 +1542,12 @@ package body wishbone_pkg is begin return std_logic_vector(c_address(c_records'length)(t_wishbone_address'range)); end f_sdb_auto_sdb; - + + function f_sdb_auto_sdb(slaves : t_sdb_record_array; masters : t_sdb_record_array) + return t_wishbone_address + is begin + return f_sdb_auto_sdb(masters & slaves); + end f_sdb_auto_sdb; --**************************************************************************************************************************-- -- START MAT's NEW FUNCTIONS FROM 18th Oct 2013 @@ -1663,10 +1766,11 @@ package body wishbone_pkg is return result; end f_xwb_bridge_manual_sdb; - function f_xwb_bridge_layout_sdb( + function f_xwb_bridge_layout_sdb_helper( g_wraparound : boolean := true; g_layout : t_sdb_record_array; - g_sdb_addr : t_wishbone_address) return t_sdb_bridge + g_sdb_addr : t_wishbone_address; + msi : boolean) return t_sdb_bridge is alias c_layout : t_sdb_record_array(g_layout'length-1 downto 0) is g_layout; @@ -1676,35 +1780,59 @@ package body wishbone_pkg is constant c_sdb_bytes : natural := c_sdb_device_length / 8; constant c_rom_bytes : natural := c_rom_entries * c_sdb_bytes; - variable result : unsigned(63 downto 0); - variable sdb_component : t_sdb_component; + variable result : unsigned(63 downto 0) := (others => '0'); + variable typ : std_logic_vector(7 downto 0); + variable last : unsigned(63 downto 0); begin + if not msi then + -- The ROM will be an addressed slave as well + result := (others => '0'); + result(g_sdb_addr'range) := unsigned(g_sdb_addr); + result := result + to_unsigned(c_rom_bytes, 64) - 1; + end if; + + for i in c_layout'range loop + typ := c_layout(i)(7 downto 0); + last := unsigned(f_sdb_extract_component(c_layout(i)(447 downto 8)).addr_last); + case typ is + when x"01" => if not msi and last > result then result := last; end if; + when x"02" => if not msi and last > result then result := last; end if; + when x"03" => if msi and last > result then result := last; end if; + when others => null; + end case; + end loop; + + -- round result up to a power of two -1 + for i in 62 downto 0 loop + result(i) := result(i) or result(i+1); + end loop; + if not g_wraparound then result := (others => '0'); for i in 0 to c_wishbone_address_width-1 loop result(i) := '1'; end loop; - else - -- The ROM will be an addressed slave as well - result := (others => '0'); - result(c_wishbone_address_width-1 downto 0) := unsigned(g_sdb_addr); - result := result + to_unsigned(c_rom_bytes, 64) - 1; - - for i in c_layout'range loop - sdb_component := f_sdb_extract_component(c_layout(i)(447 downto 8)); - if unsigned(sdb_component.addr_last) > result then - result := unsigned(sdb_component.addr_last); - end if; - end loop; - -- round result up to a power of two -1 - for i in 62 downto 0 loop - result(i) := result(i) or result(i+1); - end loop; end if; return f_xwb_bridge_manual_sdb(std_logic_vector(result(c_wishbone_address_width-1 downto 0)), g_sdb_addr); + end f_xwb_bridge_layout_sdb_helper; + + function f_xwb_bridge_layout_sdb( -- determine bus size from layout + g_wraparound : boolean := true; + g_layout : t_sdb_record_array; + g_sdb_addr : t_wishbone_address) return t_sdb_bridge + is begin + return f_xwb_bridge_layout_sdb_helper(g_wraparound, g_layout, g_sdb_addr, false); end f_xwb_bridge_layout_sdb; + function f_xwb_msi_layout_sdb( -- determine MSI size from layout + g_layout : t_sdb_record_array) return t_sdb_bridge + is + constant zero : t_wishbone_address := (others => '0'); + begin + return f_xwb_bridge_layout_sdb_helper(false, g_layout, zero, true); + end f_xwb_msi_layout_sdb; + function f_xwb_dpram(g_size : natural) return t_sdb_device is variable result : t_sdb_device; @@ -1843,6 +1971,7 @@ package body wishbone_pkg is return ret_v; end f_string_fix_len; + -- do not synthesize function f_hot_to_bin(x : std_logic_vector) return natural is variable rv : natural; begin diff --git a/platform/altera/wb_pcie/pcie_wb_pkg.vhd b/platform/altera/wb_pcie/pcie_wb_pkg.vhd index 35bc5d3e5d68937392878f675a7985f053a24647..10e0ca65a084bdc82ad2e6e2344c599e11cf9a8a 100644 --- a/platform/altera/wb_pcie/pcie_wb_pkg.vhd +++ b/platform/altera/wb_pcie/pcie_wb_pkg.vhd @@ -21,6 +21,19 @@ package pcie_wb_pkg is date => x"20131213", name => "Altera-PCIe-MSI-Tgt"))); + constant c_pcie_msi : t_sdb_msi := ( + wbd_endian => c_sdb_endian_big, + wbd_width => x"7", -- 8/16/32-bit port granularity + sdb_component => ( + addr_first => x"0000000000000000", + addr_last => x"000000000000ffff", + product => ( + vendor_id => x"0000000000000651", -- GSI + device_id => x"8a670e73", + version => x"00000001", + date => x"20131213", + name => "Altera-PCIe-MSI-Tgt"))); + component pcie_wb is generic( g_family : string := "Arria II"; diff --git a/testbench/wishbone/lm32_testsys/Manifest.py b/testbench/wishbone/lm32_testsys/Manifest.py index dc4b4ba48fd720e709fa90c95c5af85d73b5a010..9134c2465fba1d70b54392ba1e4b85ed8b62cccb 100644 --- a/testbench/wishbone/lm32_testsys/Manifest.py +++ b/testbench/wishbone/lm32_testsys/Manifest.py @@ -1,5 +1,9 @@ action = "simulation" target = "xilinx" +syn_device = "5agxma3d4f" +top_module = "main" +sim_tool = "modelsim" + modules = {"local" : [ "../../.." ] }; files = ["main.sv", "lm32_test_system.vhd"]