Engineering domain: Digital Hardware Design

Write a Vivado HLS-compatible C++ function called gemm that performs matrix multiplication C = A * B where A is of size M×K, B is of size K×N, and C is of size M×N. Set M = N = K = 256. Implement tiling with block sizes TM = TN = TK = 64 to optimize data movement and reuse. Include the headers hls_stream.h, ap_int.h, and ap_axi_sdata.h for Vivado HLS compatibility. Use a tiled loop structure across the M, N, and K dimensions. For local storage, use on-chip buffers localA[TM][TK], localB[TK][TN], and localC[TM][TN]. Partition localA across dimension 2, localB across dimension 1, and localC fully across all dimensions, as required to achieve an initiation interval (II) of 1 in the innermost loops. Apply #pragma HLS PIPELINE II=1 to the inner loops to maximize throughput. Do not manually apply #pragma HLS UNROLL, because achieving II=1 with pipelining will automatically imply sufficient unrolling when the array partitioning is properly done. Assign appropriate Vivado HLS interface pragmas: use m_axi interfaces for A, B, and C arrays, each mapped to different memory bundles (gmem0, gmem1, gmem2 respectively), and assign s_axilite interfaces for A, B, C, and return control ports to allow CPU control. Insert a #pragma HLS DATAFLOW pragma to allow overlap of memory access and computation phases through streaming/pipelining. Function signature: void gemm(float A[M_SIZE][K_SIZE], float B[K_SIZE][N_SIZE], float C[M_SIZE][N_SIZE]). Optimize the model so that it maximizes the number of DSPs in the VCK5000.