3.5.1.17 Struct Support

A C++ struct is a user-defined data type that is used to group several fields, possibly with different data types. Using struct allows passing a set of variables around the design together while retaining the readability and accessibility of each of these variables. In this section, we will discuss how interfaces and memories with struct types are handled in SmartHLS including partitioning, packing, and returning by value.

Example

This example will be used in the following sub-sections to show the different interfaces. There are three struct types in the code below:

  • Account: represents a bank account with checking and savings balances.
  • Client: represents a bank client with an ID id and an account acc . Note that id has a 6-bit unsigned integer type to demonstrate struct packing.
  • UpdateResult: used as a return type for the top-level function update to report if the update was completed and the final account balance.

The top-level function update of the example takes a clients' list clients , an ID id and an account balance acc to be added to the client's balance. It returns UpdateResult with updated = 1 and the final balance acc if an account with ID id is found in the client's list clients , otherwise it returns updated = 0.

To demonstrate another advantage of using struct, Account has a member function add that is used to update the balances which makes the code more readable in update function.

Another function find is used to search for an account with ID id in the clients' list. Notice that this function has noinline attribute. This is intended to demonstrate how struct types are passed through RTL modules after synthesizing the design.

#include <hls/ap_int.hpp>
#include <stdint.h>
#include <stdio.h>
#include <string.h>

#define N 4

using namespace hls;
struct Account {
    uint64_t checking;
    uint64_t savings;

    void add(const Account &acc) {
        checking += acc.checking;
        savings += acc.savings;
    }
};

struct Client {
    ap_uint<6> id;
    Account acc;
};

struct UpdateResult {
    ap_uint<1> updated;
    Account acc;
};

int find(Client clients[N], ap_uint<6> id) {
#pragma HLS function noinline
    for (int i = 0; i < N; i++)
        if (clients[i].id == id)
            return i;
    return -1;
}

UpdateResult update(Client clients[N], ap_uint<6> id, Account acc) {
#pragma HLS function top
    UpdateResult ret{};
    int idx = find(clients, id);
    if (idx != -1) {
        clients[idx].acc.add(acc);
        ret.acc = clients[idx].acc;
        ret.updated = 1;
    }
    return ret;
}

Client clients[N];

int main() {
    for (int i = 0; i < N; i++) {
        clients[i].id = i;
        clients[i].acc.checking = 0;
        clients[i].acc.savings = 0;
    }
    Account test_acc{100, 100};
    int passes = 0;
    UpdateResult test_ret{};
    for (int j = 0; j < N; j++) {
        test_ret = update(clients, j, test_acc);
        if (test_ret.updated == 1) {
            if (clients[j].acc.checking == 100 && clients[j].acc.savings == 100)
                passes++;
        }
    }
    // Should return 0 if passes == N
    return (passes != N);
}