openfpga/src/fabric/build_top_module_memory.cpp
/********************************************************************
 * Organize the list of memory modules and instances
 * This function will record all the sub modules of the top-level module
 * (those have memory ports) to two lists:
 * 1. memory_modules records the module ids
 * 2. memory_instances records the instance ids
 * To keep a clean memory connection between sub modules and top-level module,
 * the sequence of memory_modules and memory_instances will follow
 * a chain of tiles considering their physical location
 *
 * Inter-tile connection:
 *
 * Inter-tile connection always start from the I/O peripherals 
 * and the core tiles (CLBs and heterogeneous blocks).
 * The sequence of configuration memory will be organized as follows:
 *   - I/O peripherals
 *     - BOTTOM side (From left to right)
 *     - RIGHT side (From bottom to top)
 *     - TOP side (From left to right)
 *     - LEFT side (From top to bottom)
 *   - Core tiles
 *     - Tiles at the bottom row, i.e., Tile[0..i] (From left to right)
 *     - One row upper, i.e. Tile[i+1 .. j] (From right to left)
 *     - Repeat until we finish all the rows
 *
 *   Note: the tail may not always be on the top-right corner as shown in the figure.
 *         It may exit at the top-left corner.
 *         This really depends on the number of rows your have in the core tile array.
 *
 *   Note: the organization of inter-tile aims to reduce the wire length
 *         to connect between tiles. Therefore, it is organized as a snake
 *         where we can avoid long wires between rows and columns
 *
 *    +--------------------------------------------------------+
 *    |              +------+------+-----+------+              |
 *    |              | I/O  | I/O  | ... | I/O  |              |
 *    |              | TOP  | TOP  |     | TOP  |              |
 *    |              +------+------+-----+------+              |
 *    |           +---------------------------------->tail     |
 *    |  +------+ |  +------+------+-----+------+   +------+   |
 *    |  |      | |  |      |      |     |      |   |      |   |
 *    |  | I/O  | |  | Tile | Tile | ... | Tile |   | I/O  |   |
 *    |  | LEFT | |  | [h+1]| [h+2]|     |  [n] |   |RIGHT |   |
 *    |  +------+ |  +------+------+-----+------+   +------+   |
 *    |           +-------------------------------+            |
 *    |    ...         ...    ...    ...   ...    |   ...      |
 *    |           +-------------------------------+            |
 *    |  +------+ |  +------+------+-----+------+   +------+   |
 *    |  |      | |  |      |      |     |      |   |      |   |
 *    |  | I/O  | |  | Tile | Tile | ... | Tile |   | I/O  |   |
 *    |  | LEFT | |  | [i+1]| [i+2]|     | [j]  |   |RIGHT |   |
 *    |  +------+ |  +------+------+-----+------+   +------+   |
 *    |           +-------------------------------+            |
 *    |  +------+    +------+------+-----+------+ | +------+   |
 *    |  |      |    |      |      |     |      | | |      |   |
 *    |  | I/O  |    | Tile | Tile | ... | Tile | | | I/O  |   |
 *    |  | LEFT |    | [0]  |  [1] |     |  [i] | | |RIGHT |   |
 *    |  +------+    +------+------+-----+------+ | +------+   |
 *    +-------------------------------------------+            |
 *                   +------+------+-----+------+              |
 *                   | I/O  | I/O  | ... | I/O  |              |
 *                   |BOTTOM|BOTTOM|     |BOTTOM|              |
 *                   +------+------+-----+------+              |
 *        head >-----------------------------------------------+
 *
 * Inner tile connection:
 *
 *   Inside each tile, the configuration memory will be organized
 *   in the following sequence:
 *     - Switch Block (SB)
 *     - X-directional Connection Block (CBX)
 *     - Y-directional Connection Block (CBY)
 *     - Configurable Logic Block (CLB), which could also be heterogeneous blocks
 *
 *   Note:
 *     Due to multi-column and multi-width hetergeoenous blocks,
 *     each tile may not have one or more of SB, CBX, CBY, CLB
 *     In such case, the sequence will be respected.
 *     The missing block will just be skipped when organizing the configuration memories.
 *
 *       Tile
 *     +---------------+----------+
 *   <-+---------------+ +        |
 *     |               | |        |
 *     |     CLB       | | CBY    |
 *     |             +-|-+        |  
 *     |             | |          |
 *     +---------------+----------+
 *     |             +-+----+-----+---<---
 *     |     CBX       |   SB     |
 *     |               |          |
 *     +---------------+----------+
 *
 *******************************************************************/
Organize the list of memory modules and instances
This function will record all the sub modules of the top-level module
(those have memory ports) to two lists:
1. memory_modules records the module ids
2. memory_instances records the instance ids
To keep a clean memory connection between sub modules and top-level module,
the sequence of memory_modules and memory_instances will follow
a chain of tiles considering their physical location

Inter-tile connection.

Inter-tile connection always start from the I/O peripherals
and the core tiles (CLBs and heterogeneous blocks).

the tail may not always be on the top-right corner as shown in the figure.
It may exit at the top-left corner.
This really depends on the number of rows your have in the core tile array.

the organization of inter-tile aims to reduce the wire length
to connect between tiles. Therefore, it is organized as a snake
where we can avoid long wires between rows and columns



Inner tile connection.



Due to multi-column and multi-width hetergeoenous blocks,
each tile may not have one or more of SB, CBX, CBY, CLB
In such case, the sequence will be respected.
The missing block will just be skipped when organizing the configuration memories.


Organize the list of memory modules and instances This function will record all the sub modules of the top - level module ( those have memory ports ) to two lists : 1 . memory_modules records the module ids 2 . memory_instances records the instance ids To keep a clean memory connection between sub modules and top - level module the sequence of memory_modules and memory_instances will follow a chain of tiles considering their physical location Inter - tile connection . Inter - tile connection always start from the I / O peripherals and the core tiles ( CLBs and heterogeneous blocks ) . the tail may not always be on the top - right corner as shown in the figure . It may exit at the top - left corner . This really depends on the number of rows your have in the core tile array . the organization of inter - tile aims to reduce the wire length to connect between tiles . Therefore it is organized as a snake where we can avoid long wires between rows and columns Inner tile connection . Due to multi - column and multi - width hetergeoenous blocks each tile may not have one or more of SB CBX CBY CLB In such case the sequence will be respected . The missing block will just be skipped when organizing the configuration memories .
void organize_top_module_memory_modules(ModuleManager& module_manager, 
                                        const ModuleId& top_module,
                                        const CircuitLibrary& circuit_lib,
                                        const ConfigProtocol& config_protocol,
                                        const CircuitModelId& sram_model,
                                        const DeviceGrid& grids,
                                        const vtr::Matrix<size_t>& grid_instance_ids,
                                        const DeviceRRGSB& device_rr_gsb,
                                        const vtr::Matrix<size_t>& sb_instance_ids,
                                        const std::map<t_rr_type, vtr::Matrix<size_t>>& cb_instance_ids,
                                        const bool& compact_routing_hierarchy) {
  VTR_ASSERT(true == module_manager.configurable_children(top_module).empty());
  std::vector<e_side> io_sides{BOTTOM, RIGHT, TOP, LEFT};
  std::map<e_side, std::vector<vtr::Point<size_t>>> io_coords;
  for (size_t ix = 1; ix < grids.width() - 1; ++ix) {
    io_coords[BOTTOM].push_back(vtr::Point<size_t>(ix, 0));
  }
  for (size_t iy = 1; iy < grids.height() - 1; ++iy) {
    io_coords[RIGHT].push_back(vtr::Point<size_t>(grids.width() - 1, iy));
  }
  for (size_t ix = grids.width() - 2; ix >= 1; --ix) {
    io_coords[TOP].push_back(vtr::Point<size_t>(ix, grids.height() - 1));
  }
  io_coords[TOP].push_back(vtr::Point<size_t>(0, grids.height() - 1));
  for (size_t iy = grids.height() - 2; iy >= 1; --iy) {
    io_coords[LEFT].push_back(vtr::Point<size_t>(0, iy));
  }
  for (const e_side& io_side : io_sides) {
    for (const vtr::Point<size_t>& io_coord : io_coords[io_side]) {
      organize_top_module_tile_memory_modules(module_manager, top_module, 
                                              circuit_lib, config_protocol.type(), sram_model,
                                              grids, grid_instance_ids,
                                              device_rr_gsb, sb_instance_ids, cb_instance_ids,
                                              compact_routing_hierarchy,
                                              io_coord, io_side);
    }
  }
  std::vector<vtr::Point<size_t>> core_coords;
  bool positive_direction = true;
  for (size_t iy = 1; iy < grids.height() - 1; ++iy) {
    if (true == positive_direction) {
      for (size_t ix = 1; ix < grids.width() - 1; ++ix) {
        core_coords.push_back(vtr::Point<size_t>(ix, iy)); 
      }
    } else {
      VTR_ASSERT(false == positive_direction);
      for (size_t ix = grids.width() - 2; ix >= 1; --ix) {
        core_coords.push_back(vtr::Point<size_t>(ix, iy)); 
      }
    }
    positive_direction = !positive_direction;
  }
  for (const vtr::Point<size_t>& core_coord : core_coords) {
    organize_top_module_tile_memory_modules(module_manager, top_module,  
                                            circuit_lib, config_protocol.type(), sram_model, 
                                            grids, grid_instance_ids,
                                            device_rr_gsb, sb_instance_ids, cb_instance_ids,
                                            compact_routing_hierarchy,
                                            core_coord, NUM_SIDES);
  }
  build_top_module_configurable_regions(module_manager, top_module, config_protocol);  
}
void organize_top_module_memory_modules ( ModuleManager & module_manager , const ModuleId & top_module , const CircuitLibrary & circuit_lib , const ConfigProtocol & config_protocol , const CircuitModelId & sram_model , const DeviceGrid & grids , const vtr :: Matrix < size_t > & grid_instance_ids , const DeviceRRGSB & device_rr_gsb , const vtr :: Matrix < size_t > & sb_instance_ids , const std :: map < t_rr_type , vtr :: Matrix < size_t > > & cb_instance_ids , const bool & compact_routing_hierarchy ) { VTR_ASSERT ( true == module_manager . configurable_children ( top_module ) . empty ( ) ) ; std :: vector < e_side > io_sides { BOTTOM , RIGHT , TOP , LEFT } ; std :: map < e_side , std :: vector < vtr :: Point < size_t > > > io_coords ; for ( size_t ix = 1 ; ix < grids . width ( ) - 1 ; ++ ix ) { io_coords [ BOTTOM ] . push_back ( vtr :: Point < size_t > ( ix , 0 ) ) ; } for ( size_t iy = 1 ; iy < grids . height ( ) - 1 ; ++ iy ) { io_coords [ RIGHT ] . push_back ( vtr :: Point < size_t > ( grids . width ( ) - 1 , iy ) ) ; } for ( size_t ix = grids . width ( ) - 2 ; ix >= 1 ; -- ix ) { io_coords [ TOP ] . push_back ( vtr :: Point < size_t > ( ix , grids . height ( ) - 1 ) ) ; } io_coords [ TOP ] . push_back ( vtr :: Point < size_t > ( 0 , grids . height ( ) - 1 ) ) ; for ( size_t iy = grids . height ( ) - 2 ; iy >= 1 ; -- iy ) { io_coords [ LEFT ] . push_back ( vtr :: Point < size_t > ( 0 , iy ) ) ; } for ( const e_side & io_side : io_sides ) { for ( const vtr :: Point < size_t > & io_coord : io_coords [ io_side ] ) { organize_top_module_tile_memory_modules ( module_manager , top_module , circuit_lib , config_protocol . type ( ) , sram_model , grids , grid_instance_ids , device_rr_gsb , sb_instance_ids , cb_instance_ids , compact_routing_hierarchy , io_coord , io_side ) ; } } std :: vector < vtr :: Point < size_t > > core_coords ; bool positive_direction = true ; for ( size_t iy = 1 ; iy < grids . height ( ) - 1 ; ++ iy ) { if ( true == positive_direction ) { for ( size_t ix = 1 ; ix < grids . width ( ) - 1 ; ++ ix ) { core_coords . push_back ( vtr :: Point < size_t > ( ix , iy ) ) ; } } else { VTR_ASSERT ( false == positive_direction ) ; for ( size_t ix = grids . width ( ) - 2 ; ix >= 1 ; -- ix ) { core_coords . push_back ( vtr :: Point < size_t > ( ix , iy ) ) ; } } positive_direction = ! positive_direction ; } for ( const vtr :: Point < size_t > & core_coord : core_coords ) { organize_top_module_tile_memory_modules ( module_manager , top_module , circuit_lib , config_protocol . type ( ) , sram_model , grids , grid_instance_ids , device_rr_gsb , sb_instance_ids , cb_instance_ids , compact_routing_hierarchy , core_coord , NUM_SIDES ) ; } build_top_module_configurable_regions ( module_manager , top_module , config_protocol ) ; }
Organize the list of memory modules and instances
 This function will record all the sub modules of the top-level module
 (those have memory ports) to two lists:
 1. memory_modules records the module ids
 2. memory_instances records the instance ids
 To keep a clean memory connection between sub modules and top-level module,
 the sequence of memory_modules and memory_instances will follow
 a chain of tiles considering their physical location
Organize the list of memory modules and instances This function will record all the sub modules of the top - level module ( those have memory ports ) to two lists : 1 . memory_modules records the module ids 2 . memory_instances records the instance ids To keep a clean memory connection between sub modules and top - level module the sequence of memory_modules and memory_instances will follow a chain of tiles considering their physical location
/* Ensure clean vectors to return */ /* First, organize the I/O tiles on the border */ /* Special for the I/O tileas on RIGHT and BOTTOM,
   * which are only I/O blocks, which do NOT contain CBs and SBs 
   */ /* BOTTOM side I/Os */ /* RIGHT side I/Os */ /* TOP side I/Os 
   * Special case for TOP side: We need tile at ix = 0, which has a SB!!! 
   *
   *  TOP-LEFT CORNER of FPGA fabric
   *    
   *    +--------+ +-------+
   *    | EMPTY  | | EMPTY |
   *    | Grid   | |  CBX  |
   *    | [0][x] | |       |
   *    +--------+ +-------+
   *    +--------+ +--------+
   *    | EMPTY  | |  SB    |
   *    | CBX    | | [0][x] |
   *    +--------+ +--------+
   * 
   */ /* LEFT side I/Os */ /* Identify the GSB that surrounds the grid */ /* For the core grids */ /* For positive direction: -----> */ /* For negative direction: -----> */ /* Flip the positive direction to be negative */ /* Split memory modules into different regions */