3.5.1.17.1 Struct Packing

Packing a struct creates a single scalar with a wide word width. All the struct members are placed in the scalar with their order in the struct definition such that the first element is the least significant part of the vector and the last element is the most significant part of the vector. Packing allows all the struct elements to be read and written simultaneously. There are two packing options in SmartHLS: bit-packing and byte-packing. A pragma is specified for the argument / variable to be packed with the packing option. Note that packing an array of struct results in an array with each element as a wide-vector representing the packed struct.

Important: Struct packing supports casting a struct to another type only if the packed type is the same as the cast type. For example, the following code shows a supproted cast for struct s because packing the two uint8_t members is the same as uint16_t:
struct S {
  uint8_t a;
  uint8_t b
};

#pragma HLS memory impl variable(s) pack(bit)
S s;
uint16_t &cast = (uint16_t &)s;  
            
Bit-Packing
Bit-packing uses the bit-width of each of element of the struct. In our example, clients argument can be bit-packed as following:
int find(Client clients[N], ap_uint<6> id) {
#pragma HLS function noinline
    //...
}

UpdateResult update(Client clients[N], ap_uint<6> id, Account acc) {
#pragma HLS function top
#pragma HLS memory impl argument(clients) pack(bit)
    //...
}
In the HLS summary report, the interface for clients has a data width of 134, which is the sum of the id (6-bits), acc.checking (64-bits), and acc.savings (64-bits). The following layout of packed struct follows the order of the fields such that the first field is the least significant part of the layout.
|133 .......... 70|69 .......... 6|5 .. 0|
|-----------------|---------------|------|
|   acc.savings   |  acc.checking |  id  |
| RTL Interface Generated by SmartHLS                                                                |
+----------+-----------------+---------------------------------+------------------+------------------+
| C++ Name | Interface Type  | Signal Name                     | Signal Bit-width | Signal Direction |
+----------+-----------------+---------------------------------+------------------+------------------+
|          | Clock & Reset   | clk (positive edge)             | 1                | input            |
|          |                 | clients_address_b               | 2                | output           |
|          |                 | clients_clken                   | 1                | output           |
|          |                 | clients_read_data_a             | 134              | input            |
|          |                 | clients_read_data_b             | 134              | input            |
|          |                 | clients_read_en_a               | 1                | output           |
|          |                 | clients_read_en_b               | 1                | output           |
|          |                 | clients_write_data_a            | 134              | output           |
|          |                 | clients_write_data_b            | 134              | output           |
|          |                 | clients_write_en_a              | 1                | output           |
|          |                 | clients_write_en_b              | 1                | output           |
+----------+-----------------+---------------------------------+------------------+------------------+
| acc      | Scalar Memory   | acc_read_data                   | 128              | input            |
Byte-Packing
Byte-packing is similar to bit-packing except that each element of the struct is aligned to 8-bits. In our example, clients can be byte-packed as following:
int find(Client clients[N], ap_uint<6> id) {
#pragma HLS function noinline
    //...
}

UpdateResult update(Client clients[N], ap_uint<6> id, Account acc) {
#pragma HLS function top
#pragma HLS memory impl argument(clients) pack(byte)
    //...
}

In the HLS summary report, the interface for clients has a data width of 136, which is the sum of the id (8-bits), acc.checking (64-bits), and acc.savings (64-bits). The following layout of packed struct follows the order of the fields such that the first field is the least significant part of the layout.

|135 .......... 72|71 .......... 8|7 .. 0|
|-----------------|---------------|------|
|   acc.savings   |  acc.checking |  id  |
| RTL Interface Generated by SmartHLS                                                                |
+----------+-----------------+---------------------------------+------------------+------------------+
| C++ Name | Interface Type  | Signal Name                     | Signal Bit-width | Signal Direction |
+----------+-----------------+---------------------------------+------------------+------------------+
|          | Clock & Reset   | clk (positive edge)             | 1                | input            |
|          |                 | clients_address_b               | 2                | output           |
|          |                 | clients_clken                   | 1                | output           |
|          |                 | clients_read_data_a             | 136              | input            |
|          |                 | clients_read_data_b             | 136              | input            |
|          |                 | clients_read_en_a               | 1                | output           |
|          |                 | clients_read_en_b               | 1                | output           |
|          |                 | clients_write_data_a            | 136              | output           |
|          |                 | clients_write_data_b            | 136              | output           |
|          |                 | clients_write_en_a              | 1                | output           |
|          |                 | clients_write_en_b              | 1                | output           |
+----------+-----------------+---------------------------------+------------------+------------------+
| acc      | Scalar Memory   | acc_read_data                   | 128              | input            |
For byte-packing, the interface can either use byte-enable to write individual fields or it can be a wide scalar as shown before. To use byte-enable signals, byte_enable parameter should be set to true in the packing pragma:
int find(Client clients[N], ap_uint<6> id) {
#pragma HLS function noinline
    //...
}

UpdateResult update(Client clients[N], ap_uint<6> id, Account acc) {
#pragma HLS function top
#pragma HLS memory impl argument(clients) pack(byte) byte_enable(true)
    //...
}
The HLS summary report will show clients_byte_en_a and clients_byte_en_b signals that are added to the interface.
Important: byte_enable parameter is default to false and can only be specified with pack(byte), i.e. using it with pack(bit) will error during compilation.
| RTL Interface Generated by SmartHLS                                                                |
+----------+-----------------+---------------------------------+------------------+------------------+
| C++ Name | Interface Type  | Signal Name                     | Signal Bit-width | Signal Direction |
+----------+-----------------+---------------------------------+------------------+------------------+
|          | Clock & Reset   | clk (positive edge)             | 1                | input            |
|          |                 | clients_address_b               | 2                | output           |
|          |                 | clients_byte_en_a               | 17               | output           |
|          |                 | clients_byte_en_b               | 17               | output           |
|          |                 | clients_clken                   | 1                | output           |
|          |                 | clients_read_data_a             | 136              | input            |
|          |                 | clients_read_data_b             | 136              | input            |
|          |                 | clients_read_en_a               | 1                | output           |
|          |                 | clients_read_en_b               | 1                | output           |
|          |                 | clients_write_data_a            | 136              | output           |
|          |                 | clients_write_data_b            | 136              | output           |
|          |                 | clients_write_en_a              | 1                | output           |
|          |                 | clients_write_en_b              | 1                | output           |
+----------+-----------------+---------------------------------+------------------+------------------+
| acc      | Scalar Memory   | acc_read_data                   | 128              | input            |