From 31f64b66a770816f86c7d783cde6c2b80e8ead1c Mon Sep 17 00:00:00 2001
From: "Wesley W. Terpstra" <w.terpstra@gsi.de>
Date: Fri, 22 Apr 2016 16:14:18 +0200
Subject: [PATCH] crossbar: eliminate code duplication

---
 .../wishbone/wb_crossbar/xwb_sdb_crossbar.vhd | 64 ++-----------
 modules/wishbone/wishbone_pkg.vhd             | 94 ++++++++++++-------
 2 files changed, 68 insertions(+), 90 deletions(-)

diff --git a/modules/wishbone/wb_crossbar/xwb_sdb_crossbar.vhd b/modules/wishbone/wb_crossbar/xwb_sdb_crossbar.vhd
index 361b52f0..8cec9681 100644
--- a/modules/wishbone/wb_crossbar/xwb_sdb_crossbar.vhd
+++ b/modules/wishbone/wb_crossbar/xwb_sdb_crossbar.vhd
@@ -47,60 +47,8 @@ architecture rtl of xwb_sdb_crossbar is
   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_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
-    assert (g_sdb_addr and std_logic_vector(to_unsigned(c_rom_bytes - 1, c_wishbone_address_width))) = zero
-    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.bus_last := (others => '0');
-      for i in 0 to c_wishbone_address_width-1 loop
-        result.bus_last(i) := '1';
-      end loop;
-    end if;
-    
-    return result;
-  end f_sizes;
-
-  constant c_sizes : t_sizes := f_sizes;
+  constant c_bus_last : unsigned := f_sdb_bus_end(g_wraparound, g_layout, g_sdb_addr, false);
+  constant c_msi_last : unsigned := f_sdb_bus_end(g_wraparound, g_layout, g_sdb_addr, true);
 
   type t_addresses is record
     bus_address : t_wishbone_address_array(g_num_slaves -1 downto 0);
@@ -162,7 +110,7 @@ architecture rtl of xwb_sdb_crossbar is
           report "Too many device and bridge records found in g_layout"
           severity Failure;
           
-          size := c_sizes.bus_last - size;
+          size := c_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;
@@ -172,7 +120,7 @@ architecture rtl of xwb_sdb_crossbar is
           report "Too many msi records found in g_layout"
           severity Failure;
           
-          size := c_sizes.msi_last - size;
+          size := c_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;
@@ -213,7 +161,7 @@ architecture rtl of xwb_sdb_crossbar is
 
   -- Figure out the mask for the SDB slave
   constant c_rom_mask : unsigned(63 downto 0) := 
-    c_sizes.bus_last - to_unsigned(c_rom_bytes-1, 64);
+    c_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));
   
@@ -237,7 +185,7 @@ begin
     generic map(
       g_layout   => c_layout,
       g_masters  => g_num_masters,
-      g_bus_end  => c_sizes.bus_last)
+      g_bus_end  => c_bus_last)
     port map(
       clk_sys_i => clk_sys_i,
       master_i  => sdb_sel,
diff --git a/modules/wishbone/wishbone_pkg.vhd b/modules/wishbone/wishbone_pkg.vhd
index 0cec2cb7..a0e62806 100644
--- a/modules/wishbone/wishbone_pkg.vhd
+++ b/modules/wishbone/wishbone_pkg.vhd
@@ -207,6 +207,7 @@ package wishbone_pkg is
   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_bus_end(g_wraparound : boolean; g_layout : t_sdb_record_array; g_sdb_addr : t_wishbone_address; msi : boolean) return unsigned;
   function f_sdb_embed_product(product         : t_sdb_product) return std_logic_vector;  -- (319 downto 8)
   function f_sdb_embed_component(sdb_component : t_sdb_component; address : t_wishbone_address) return std_logic_vector;  -- (447 downto 8)
   function f_sdb_extract_product(sdb_record    : std_logic_vector(319 downto 8)) return t_sdb_product;
@@ -346,8 +347,11 @@ package wishbone_pkg is
     g_layout     : t_sdb_record_array;
     g_sdb_addr   : t_wishbone_address) return t_sdb_bridge;
 
+  function f_xwb_msi_manual_sdb(        -- take a manual bus size
+    g_size     : t_wishbone_address) return t_sdb_msi;
+
   function f_xwb_msi_layout_sdb(     -- determine MSI size from layout
-    g_layout     : t_sdb_record_array) return t_sdb_bridge;
+    g_layout     : t_sdb_record_array) return t_sdb_msi;
 
   component xwb_sdb_crossbar
     generic (
@@ -1744,33 +1748,11 @@ package body wishbone_pkg is
 -- END MAT's NEW FUNCTIONS FROM  18th Oct 2013
 ------------------------------------------------------------------------------------------------------------------------------
 
-  function f_xwb_bridge_manual_sdb(
-    g_size     : t_wishbone_address;
-    g_sdb_addr : t_wishbone_address) return t_sdb_bridge
-  is
-    variable result : t_sdb_bridge;
-  begin
-    result.sdb_child                                      := (others => '0');
-    result.sdb_child(c_wishbone_address_width-1 downto 0) := g_sdb_addr;
-
-    result.sdb_component.addr_first                                     := (others => '0');
-    result.sdb_component.addr_last                                      := (others => '0');
-    result.sdb_component.addr_last(c_wishbone_address_width-1 downto 0) := g_size;
-
-    result.sdb_component.product.vendor_id := x"0000000000000651";  -- GSI
-    result.sdb_component.product.device_id := x"eef0b198";
-    result.sdb_component.product.version   := x"00000001";
-    result.sdb_component.product.date      := x"20120511";
-    result.sdb_component.product.name      := "WB4-Bridge-GSI     ";
-
-    return result;
-  end f_xwb_bridge_manual_sdb;
-  
-  function f_xwb_bridge_layout_sdb_helper(
-    g_wraparound : boolean := true;
+  function f_sdb_bus_end(
+    g_wraparound : boolean;
     g_layout     : t_sdb_record_array;
     g_sdb_addr   : t_wishbone_address;
-    msi          : boolean) return t_sdb_bridge
+    msi          : boolean) return unsigned
   is
     alias c_layout : t_sdb_record_array(g_layout'length-1 downto 0) is g_layout;
 
@@ -1814,23 +1796,71 @@ package body wishbone_pkg is
       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;
+    return result;
+  end f_sdb_bus_end;
 
+  function f_xwb_bridge_manual_sdb(
+    g_size     : t_wishbone_address;
+    g_sdb_addr : t_wishbone_address) return t_sdb_bridge
+  is
+    variable result : t_sdb_bridge;
+  begin
+    result.sdb_child                                      := (others => '0');
+    result.sdb_child(c_wishbone_address_width-1 downto 0) := g_sdb_addr;
+
+    result.sdb_component.addr_first                                     := (others => '0');
+    result.sdb_component.addr_last                                      := (others => '0');
+    result.sdb_component.addr_last(c_wishbone_address_width-1 downto 0) := g_size;
+
+    result.sdb_component.product.vendor_id := x"0000000000000651";  -- GSI
+    result.sdb_component.product.device_id := x"eef0b198";
+    result.sdb_component.product.version   := x"00000001";
+    result.sdb_component.product.date      := x"20120511";
+    result.sdb_component.product.name      := "WB4-Bridge-GSI     ";
+
+    return result;
+  end f_xwb_bridge_manual_sdb;
+  
   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);
+  is
+    variable address : t_wishbone_address;
+  begin
+    address := std_logic_vector(f_sdb_bus_end(g_wraparound, g_layout, g_sdb_addr, false)(address'range));
+    return f_xwb_bridge_manual_sdb(address, g_sdb_addr);
   end f_xwb_bridge_layout_sdb;
 
+  function f_xwb_msi_manual_sdb(
+    g_size     : t_wishbone_address) return t_sdb_msi
+  is
+    variable result : t_sdb_msi;
+  begin
+    result.wbd_endian := '0';
+    result.wbd_width  := x"7";
+
+    result.sdb_component.addr_first                                     := (others => '0');
+    result.sdb_component.addr_last                                      := (others => '0');
+    result.sdb_component.addr_last(c_wishbone_address_width-1 downto 0) := g_size;
+
+    result.sdb_component.product.vendor_id := x"0000000000000651";  -- GSI
+    result.sdb_component.product.device_id := x"aa7bfb3c";
+    result.sdb_component.product.version   := x"00000001";
+    result.sdb_component.product.date      := x"20160422";
+    result.sdb_component.product.name      := "WB4-MSI-Bridge-GSI ";
+
+    return result;
+  end f_xwb_msi_manual_sdb;
+  
   function f_xwb_msi_layout_sdb(     -- determine MSI size from layout
-    g_layout     : t_sdb_record_array) return t_sdb_bridge
+    g_layout     : t_sdb_record_array) return t_sdb_msi
   is
     constant zero : t_wishbone_address := (others => '0');
+    variable address : t_wishbone_address;
   begin
-    return f_xwb_bridge_layout_sdb_helper(false, g_layout, zero, true);
+    address := std_logic_vector(f_sdb_bus_end(true, g_layout, zero, true)(address'range));
+    return f_xwb_msi_manual_sdb(address);
   end f_xwb_msi_layout_sdb;
   
   function f_xwb_dpram(g_size : natural) return t_sdb_device
-- 
GitLab