Array Layouts for HLS Code Generation
Array layout can be important for integration, usability, and performance. The code generator produces code that uses column-major layout by default. However, many devices, sensors, and libraries use row-major array layout for their data. You can apply your code directly to this data by generating code that uses row-major layout. Array layout can also affect performance. Many algorithms perform memory access more efficiently for one specific array layout.
You can specify row-major array layout at the command line, with code generation configuration properties, or by using the HDL Coder™ app. You can also specify row-major layout or column-major layout for individual functions. The inputs and outputs of your entry-point (top-level) functions must all use the same array layout.
Note
By default, code generation uses column-major array layout.
Specify row-major layout using -rowmajor
option
Consider this function addMatrix
and test bench
addMatrix_tb
for adding two matrices. The algorithm performs the
addition through explicit row and column traversal.
% MATLAB Code, save it as addMatrix function [S] = addMatrix(A,B) %#codegen S = zeros(size(A)); for row = 1:size(A,1) for col = 1:size(A,2) S(row,col) = A(row,col) + B(row,col); end end % MATLAB Test Bench, save it as addMatrix_tb a = randi(100, 5,3); b = randi(100, 5,3); out = addMatrix(a,b);
Generate HLS code for addMatrix
by using the
-rowmajor
option. Specify the form of the input parameters by using the
-args
option and launch the code generation report.
hdlcfg = coder.config("hdl"); hdlcfg.TestBenchName = "addMatrix_tb"; hdlcfg.Workflow = "High Level Synthesis"; codegen -config hdlcfg addMatrix -rowmajor -report
Alternatively, configure your code for row-major layout by modifying the
RowMajor
parameter in the code generation configuration object.
hdlcfg = coder.config("hdl"); hdlcfg.TestBenchName = "addMatrix_tb"; hdlcfg.Workflow = "High Level Synthesis"; hdlcfg.RowMajor = true; codegen -config hdlcfg addMatrix -launchreport
Code generation results in this HLS code:
... /* generated code for addMatrix using row-major */ for (int32_T row = 0; row < 5; row = row + 1) { for (int32_T col = 0; col < 3; col = col + 1) { S[row][col] = A[row][col] + B[row][col]; } } ...
To specify row-major layout using the HDL Coder app:
Open the HDL Coder dialog box. Select the Code Generation Workflow as
MATLAB to HLS
.Go to the HLS Code Generation step.
On the Advanced tab, set Array layout:
Row-major
.
To verify that your generated code uses row-major layout, compare the array indexing in your generated code with the array indexing in code that uses column-major layout. You can also generate code that uses upto 3-dimensional indexing. 3-dimensional indexing can make differences in array layout more apparent.
Specify Array Layout in Functions
You can specialize individual MATLAB® functions for row-major layout or column-major layout by inserting
coder.rowMajor
or coder.columnMajor
calls into
the function body. Using these function specializations, you can combine row-major data and
column-major data in your generated code.
For the entry-point (top-level) functions, all inputs and outputs must use the same array layout. In the generated HLS code, the entry-point function interface accepts and returns data with the same array layout as the function array layout specification.
For an example of a specialized function, consider function
addMatrixRM
and test bench
addMatrixRM_tb
:
% MATLAB code, save it as addMatrixRM function [S] = addMatrixRM(A,B) %#codegen S = zeros(size(A)); coder.rowMajor; % specify row-major code for row = 1:size(A,1) for col = 1:size(A,2) S(row,col) = A(row,col) + B(row,col); end end % MATLAB test bench, save it as addMatrixRM_tb a = randi(100, 5,3); b = randi(100, 5,3); out = addMatrixRM(a,b);
addMatrixRM
by using these
commands.hdlcfg = coder.config("hdl"); hdlcfg.TestBenchName = "addMatrixRM_tb"; hdlcfg.Workflow = "High Level Synthesis"; codegen -config hdlcfg addMatrixRM -launchreport
Because of the coder.rowMajor
call, the code generator produces code
that uses data stored in row-major layout.
Other functions called from a row-major function or column-major function inherit the
same array layout. If a called function has its own distinct
coder.rowMajor
or coder.columnMajor
call, the
local call takes precedence.
You can mix column-major and row-major functions in the same code. The code generator inserts transpose or conversion operations when passing data between row-major and column-major functions. These conversion operations ensure that array elements are stored as required by functions with different array layout specifications. For example, the inputs to a column-major function, called from a row-major function, are converted to column-major layout before being passed to the column-major function.
Query Array Layout of a Function
To query the array layout of a function at compile time, use
coder.isRowMajor
or coder.isColumnMajor
. This
query can be useful for specializing your generated code when it involves row-major and
column-major functions. For example, consider this
function:
function [S] = addMatrixRouted(A,B) if coder.isRowMajor %execute this code if row-major S = addMatrixRM(A,B); elseif coder.isColumnMajor %execute this code if column-major S = addMatrix_OptimizedForColumnMajor(A,B); end
addMatrixRouted
is row-major, it calls the
addMatrixRM
function, which has efficient memory access for row-major
data. When the function is column-major, it calls a version of the
addMatrixRM
function optimized for column-major data.For example, consider this function definition. The algorithm iterates through the
columns in the outer loop and the rows in the inner loop, in contrast to the
addMatrixRM
function.
function [S] = addMatrix_OptimizedForColumnMajor(A,B) %#codegen S = zeros(size(A)); for col = 1:size(A,2) for row = 1:size(A,1) S(row,col) = A(row,col) + B(row,col); end end
... /* column-major layout */ for (col = 0; col < 10; col++) { for (row = 0; row < 20; row++) { S[row + 20 * col] = A[row + 20 * col] + B[row + 20 * col]; } } ...
addMatrixRouted
provides
efficient memory access for either choice of array layout.Specify Array Layout in External Function Calls
To call external C/C++ functions that expect data stored with a specific layout, use
coder.ceval
with the layout
syntax. If you do not
use this syntax, the external function inputs and outputs are assumed to use column-major
layout by default.
Consider an external C function designed to use row-major layout called
myCFunctionRM
. To integrate this function into your code, call the
function using the -layout:rowMajor
or -row
option.
This option ensures that the input and output arrays are stored in row-major order. The code
generator automatically inserts array layout conversions as
needed.
coder.ceval('-layout:rowMajor','myCFunctionRM',coder.ref(in),coder.ref(out))
Within a MATLAB function that uses row-major layout, you may seek to call an external function
designed to use column-major layout. In this case, use the
'-layout:columnMajor'
or '-col'
option.
coder.ceval('-layout:columnMajor','myCFunctionCM',coder.ref(in),coder.ref(out))
You can perform row-major and column-major function calls in the same code. Consider the
function myMixedFn1
as an example:
function [E] = myMixedFn1(x,y) %#codegen % specify type of return arguments for ceval calls D = zeros(size(x)); E = zeros(size(x)); % include external C functions that use row-major & column-major coder.cinclude('addMatrixRM.h'); coder.updateBuildInfo('addSourceFiles', 'addMatrixRM.c'); coder.cinclude('addMatrixCM.h'); coder.updateBuildInfo('addSourceFiles', 'addMatrixCM.c'); % call C function that uses row-major order coder.ceval('-layout:rowMajor','addMatrixRM', ... coder.rref(x),coder.rref(y),coder.wref(D)); % call C function that uses column-major order coder.ceval('-layout:columnMajor','addMatrixCM', ... coder.rref(x),coder.rref(D),coder.wref(E)); end
The external files are:
To generate code, enter:
hdlcfg = coder.config("hdl"); hdlcfg.Workflow = "High Level Synthesis"; codegen -config hdlcfg myMixedFn1 -args {ones(20,10),ones(20,10)} -rowmajor -launchreport
See Also
coder.columnMajor
| coder.rowMajor
| coder.isRowMajor
| coder.isColumnMajor