Intel® High Level Synthesis Compiler Standard Edition: Best Practices Guide

ID 683259
Date 12/18/2019
Public
Document Table of Contents

5.3.1. Example: Merging Memories Depth-Wise

Use the hls_merge("<mem_name>","depth") attribute to force the Intel® HLS Compiler Standard Edition to implement variables in the same memory system, merging their memories by depth.

All variables with the same <mem_name> label set in their hls_merge attributes are merged.

Consider the following component code:

component int depth_manual(bool use_a, int raddr, int waddr, int wdata) {
  int a[128];
  int b[128];

  int rdata;

  // mutually exclusive write
  if (use_a) {
    a[waddr] = wdata;
  } else {
    b[waddr] = wdata;
  }

  // mutually exclusive read
  if (use_a) {
    rdata = a[raddr];
  } else {
    rdata = b[raddr];
  }

  return rdata;
}

The code instructs the Intel® HLS Compiler to implement local memories a and b as two on-chip memory blocks, each with its own load and store instructions.

Figure 13. Implementation of Local Memory for Component depth_manual

Because the load and store instructions for local memories a and b are mutually exclusive, you can merge the accesses, as shown in the example code below. Merging the memory accesses reduces the number of load and store instructions, and the number of on-chip memory blocks, by half.

component int depth_manual(bool use_a, int raddr, int waddr, int wdata) {
  int a[128] hls_merge("mem","depth");
  int b[128] hls_merge("mem","depth");

  int rdata;

  // mutually exclusive write
  if (use_a) {
    a[waddr] = wdata;
  } else {
    b[waddr] = wdata;
  }

  // mutually exclusive read
  if (use_a) {
    rdata = a[raddr];
  } else {
    rdata = b[raddr];
  }

  return rdata;
}
Figure 14. Depth-Wise Merge of Local Memories for Component depth_manual

There are cases where merging local memories with respect to depth might degrade memory access efficiency. Before you decide whether to merge the local memories with respect to depth, refer to the HLD report ( <result>.prj/reports/report.html) to ensure that they have produced the expected memory configuration with the expected number of loads and stores instructions. In the example below, the Intel® HLS Compiler should not merge the accesses to local memories a and b because the load and store instructions to each memory are not mutually exclusive.

component int depth_manual(bool use_a, int raddr, int waddr, int wdata) {
  int a[128] hls_merge("mem","depth");
  int b[128] hls_merge("mem","depth");

  int rdata;

  // NOT mutually exclusive write

  a[waddr] = wdata;
  b[waddr] = wdata;
  
  // NOT mutually exclusive read

  rdata = a[raddr];
  rdata += b[raddr];
  
  return rdata;
}

In this case, the Intel® HLS Compiler might double pump the memory system to provide enough ports for all the accesses. Otherwise, the accesses must share ports, which prevent stall-free accesses.

Figure 15. Local Memories for Component depth_manual with Non-Mutually Exclusive Accesses