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"]