# Optimize Data Types for an FPGA with DSP Slices

This example shows how to use the `addSpecification`

method of the `fxpOptimizationOptions`

class to achieve better mapping for product blocks on DSP slices for FPGA targets. Use `addSpecification`

to specify known data types in a system. After specifying these known parameters, when you optimize data types in the system, the optimization process does not change the specified block parameter data type.

Many FPGA boards have specific multiply-accumulate hardware accelerators, called DSP slices that speed up the execution of signal processing functions. DSP slices vary in size depending on the vendor. To gain the hardware acceleration benefits of DSP slices, it is common in FPGA design to map multiply and accumulate operations in the algorithm onto these slices.

In this example, optimize data types for 3 DSP families of Xilinx® boards, as well as for a generic 18x18 bit input. Use the `addSpecification`

method to achieve a good mapping between the Product blocks in the design and the target DSP slices.

This example makes the following assumptions:

Only Product and Gain blocks are targeted for mapping to DSP slices. You can handle other blocks in a similar fashion.

Product blocks have only 2 inputs.

Driver blocks (blocks that precede Product or Gain blocks) have

`OutDataTypeStr`

as a parameter.Only blocks that do not have the HDL property

**DSPStyle**set to`off`

are targeted.

### Instrument the Model and Collect Ranges

To begin, open the system for which you want to optimize data types. In this example, data types are optimized for an automatic gain control algorithm.

model = 'mQAMAGC'; sud = [model '/Automatic Gain Control']; open_system(model);

Initialize the QAM Tx subsystem.

initQAM;

Create a structure array that describes the properties of the target DSP slice. The `dspStyle`

function included in this example provides information about common Xilinx® DSP slices including DSP48A1 (18x18 bit signed), DSP48E1 (18x25 bit signed), and DSP48E2 (18x27 bit signed). It also provides an example of a generic 18x18 signed DSP slice.

```
dspStyle = getDSPStyle('DSP48E2');
```

In this example, only Product and Gain blocks are targeted for mapping to DSP slices. Find all the Product and Gain blocks in the system under design that do not have the HDL block property **DSPStyle** set to `off`

. For more information, see DSPStyle (HDL Coder).

productBlocks = find_system(sud,'LookUnderMasks','on','BlockType','Product'); hasDSPOff = cellfun(@(x)(isequal(hdlget_param(x,'DSPStyle'),'off')), productBlocks); productDSP = productBlocks(~hasDSPOff); gainBlocks = find_system(sud,'LookUnderMasks','on','BlockType','Gain'); hasDSPOff = cellfun(@(x)(isequal(hdlget_param(x,'DSPStyle'),'off')), productBlocks); gainDSP = gainBlocks(~hasDSPOff);

Enable instrumentation to log minimum, maximum, and overflow data during simulation for Product blocks and driver blocks that precede Product blocks. Simulate the model to collect ranges.

c = DataTypeWorkflow.Converter(sud,'TopModel',model); c.CurrentRunName = 'RangeCollection'; c.simulateSystem('MinMaxOverflowLogging','MinMaxAndOverflow');

### Get Specifications for Product Blocks

For efficient mapping of Product blocks to available DSP slices, consider the range requirements of the Product blocks. Create a structure array to store simulation minimum and maximum values for Product blocks collected during the range collection run.

specs = struct('Block',productDSP{1},'Drivers',[],'Min',[],'Max',[]); %#ok<*SAGROW> r = c.results(c.CurrentRunName,@(x)(strcmp(x.ResultName,productDSP{1}))); specs.Min = r.SimMin; specs.Max = r.SimMax; predecessorBlocks = predecessors(productDSP{1}); for pIndex = 1:numel(predecessorBlocks) pBlkObj = get_param(predecessorBlocks{pIndex},'Object'); specs.Drivers(pIndex) = pBlkObj.Handle; r = c.results(c.CurrentRunName,@(x)(strcmp(x.ResultName,pBlkObj.getFullName()))); specs.Min(pIndex+1) = r.SimMin; specs.Max(pIndex+1) = r.SimMax; end

Store these known parameter specifications for the Product blocks in a `Simulink.Simulation.BlockParameter`

object.

bpProductBlock = Simulink.Simulation.BlockParameter.empty(0,3); fout = fi(max([abs(specs.Min(1)) abs(specs.Max(1))]),dspStyle.sout,dspStyle.wout); bpProductBlock(1) = Simulink.Simulation.BlockParameter(specs.Block, ... 'OutDataTypeStr', ... sprintf('fixdt(%i,%i,%i)',dspStyle.sout,dspStyle.wout,fout.FractionLength));

Assign the largest type to the largest range of the driver blocks. This ensures that the largest data type available in the target hardware is applied to the block with the largest range requirement.

dMax1 = max([abs(specs.Min(2)) abs(specs.Max(2))]); dMax2 = max([abs(specs.Min(3)) abs(specs.Max(3))]); if dMax1 < dMax2 win_1 = dspStyle.win_1; sin_1 = dspStyle.sin_1; win_2 = dspStyle.win_2; sin_2 = dspStyle.sin_2; if dspStyle.win_1 >= dspStyle.win_2 win_1 = dspStyle.win_2; sin_1 = dspStyle.sin_2; win_2 = dspStyle.win_1; sin_2 = dspStyle.sin_1; end else win_1 = dspStyle.win_2; sin_1 = dspStyle.sin_2; win_2 = dspStyle.win_1; sin_2 = dspStyle.sin_1; if dspStyle.win_1 >= dspStyle.win_2 win_1 = dspStyle.win_1; sin_1 = dspStyle.sin_1; win_2 = dspStyle.win_2; sin_2 = dspStyle.sin_2; end end

Get specifications for blocks preceding Product blocks. Note that this example assumes that Product blocks have two inputs.

fin1 = fi(dMax1, sin_1, win_1); blkObj = get_param(specs.Drivers(1), 'Object'); bpProductBlock(2) = Simulink.Simulation.BlockParameter(blkObj.getFullName, ... 'OutDataTypeStr', ... sprintf('fixdt(%i, %i, %i)', sin_1, win_1, fin1.FractionLength)); fin2 = fi(dMax2, sin_2, win_2); blkObj = get_param(specs.Drivers(2), 'Object'); bpProductBlock(3) = Simulink.Simulation.BlockParameter(blkObj.getFullName, ... 'OutDataTypeStr', ... sprintf('fixdt(%i, %i, %i)', sin_2, win_2, fin2.FractionLength));

### Get Specifications for Gain Blocks

Store known parameter specifications for the Gain blocks in a `Simulink.Simulation.BlockParameter`

object.

bpGainBlock = Simulink.Simulation.BlockParameter.empty(0,3); specs = struct('Block',gainDSP{1},'Drivers',[],'Min',[],'Max',[]); %#ok<*SAGROW> r = c.results(c.CurrentRunName,@(x)(strcmp(x.ResultName,gainDSP{1}))); specs.Min = r.SimMin; specs.Max = r.SimMax; predecessorBlocks = predecessors(gainDSP{1}); pBlkObj = get_param(predecessorBlocks{1},'Object'); specs.Drivers(1) = pBlkObj.Handle; r = c.results(c.CurrentRunName,@(x)(strcmp(x.ResultName,pBlkObj.getFullName()))); specs.Min(2) = r.SimMin; specs.Max(2) = r.SimMax;

Get specifications for the output of Gain blocks.

fout = fi(max(abs([specs.Min(1) specs.Max(1)])),dspStyle.sout,dspStyle.wout); bpGainBlock(1) = Simulink.Simulation.BlockParameter(gainDSP{1}, ... 'OutDataTypeStr', ... sprintf('fixdt(%i, %i, %i)',dspStyle.sout,dspStyle.wout,fout.FractionLength));

Get specifications for the blocks preceding Gains blocks and assign this to the first configuration of the `Simulink.Simulation.BlockParameter`

object `bpGainBlock`

.

blkObj = get_param(specs.Drivers(1),'Object'); fin = fi(max(abs([specs.Min(2) specs.Max(2)])),dspStyle.sin_1,dspStyle.win_1); bpGainBlock(2) = Simulink.Simulation.BlockParameter(blkObj.getFullName, ... 'OutDataTypeStr', ... sprintf('fixdt(%i,%i,%i)',dspStyle.sin_1,dspStyle.win_1,fin.FractionLength));

Get specifications for the **Gain** parameter of the system under design and assign this value to the second configuration of `bpGainBlock`

.

paramValue = str2double(get_param(sud,'AGC_Gain')); fParam = fi(paramValue,dspStyle.sin_2,dspStyle.win_2); bpGainBlock(3) = Simulink.Simulation.BlockParameter(gainDSP{1}, ... 'ParamDataTypeStr', ... sprintf('fixdt(%i,%i,%i)',dspStyle.sin_2,dspStyle.win_2,fParam.FractionLength));

### Define Constraints and Tolerances

Create an `fxpOptimizationOptions`

object to define constraints and tolerances. Specify allowed word lengths of 8 bits to 32 bits.

```
options = fxpOptimizationOptions('AllowableWordLengths',8:2:32);
```

Use the `addTolerance`

method to define tolerances for the differences between the original behavior of the system and the behavior using the optimized fixed-point data types.

addTolerance(options,sud,1,'RelTol',1e-2); addTolerance(options,sud,2,'RelTol',1e-2); addTolerance(options,sud,1,'AbsTol',1e-3); addTolerance(options,sud,2,'AbsTol',1e-3);

Use the `addSpecification`

method to define specifications for the Product and Gain blocks.

addSpecification(options,'BlockParameter',bpProductBlock); % set the specifications for the product block addSpecification(options,'BlockParameter',bpGainBlock); % set the specifications for the gain block showSpecifications(options);

Index Name BlockPath Value _____ ________________ _____________________________________________ __________________ 1 OutDataTypeStr mQAMAGC/Automatic Gain Control/LoopGain 'fixdt(1, 45, 53)' 2 ParamDataTypeStr mQAMAGC/Automatic Gain Control/LoopGain 'fixdt(1,27,35)' 3 OutDataTypeStr mQAMAGC/Automatic Gain Control/LoopGainDriver 'fixdt(1,18,16)' 4 OutDataTypeStr mQAMAGC/Automatic Gain Control/Product 'fixdt(1,45,43)' 5 OutDataTypeStr mQAMAGC/Automatic Gain Control/ProductDriverA 'fixdt(1, 27, 25)' 6 OutDataTypeStr mQAMAGC/Automatic Gain Control/ProductDriverB 'fixdt(1, 18, 17)' varSpecs ________

### Optimize Fixed-Point Data Types

Use the `fxpopt`

function to run the optimization. The software analyzes ranges of objects in the system under design and the constraints specified in the `fxpOptimizationOptions`

object to apply heterogeneous data types to your system while minimizing the total bit width. Known parameter specifications included using the `addSpecification`

method is not affected by the optimization process.

result = fxpopt(model,sud,options);

+ Starting data type optimization... + Checking for unsupported constructs. + Preprocessing + Modeling the optimization problem - Constructing decision variables + Running the optimization solver Exporting logged dataset prior to deleting run...done. - Evaluating new solution: cost 200, does not meet the behavioral constraints. - Evaluating new solution: cost 250, does not meet the behavioral constraints. - Evaluating new solution: cost 300, does not meet the behavioral constraints. - Evaluating new solution: cost 350, does not meet the behavioral constraints. - Evaluating new solution: cost 400, does not meet the behavioral constraints. - Evaluating new solution: cost 450, does not meet the behavioral constraints. - Evaluating new solution: cost 500, meets the behavioral constraints. - Updated best found solution, cost: 500 - Evaluating new solution: cost 496, meets the behavioral constraints. - Updated best found solution, cost: 496 - Evaluating new solution: cost 492, meets the behavioral constraints. - Updated best found solution, cost: 492 - Evaluating new solution: cost 488, meets the behavioral constraints. - Updated best found solution, cost: 488 - Evaluating new solution: cost 484, meets the behavioral constraints. - Updated best found solution, cost: 484 - Evaluating new solution: cost 480, meets the behavioral constraints. - Updated best found solution, cost: 480 - Evaluating new solution: cost 478, meets the behavioral constraints. - Updated best found solution, cost: 478 - Evaluating new solution: cost 476, does not meet the behavioral constraints. - Evaluating new solution: cost 472, does not meet the behavioral constraints. - Evaluating new solution: cost 476, meets the behavioral constraints. - Updated best found solution, cost: 476 - Evaluating new solution: cost 474, meets the behavioral constraints. - Updated best found solution, cost: 474 - Evaluating new solution: cost 468, meets the behavioral constraints. - Updated best found solution, cost: 468 - Evaluating new solution: cost 458, meets the behavioral constraints. - Updated best found solution, cost: 458 - Evaluating new solution: cost 454, meets the behavioral constraints. - Updated best found solution, cost: 454 - Evaluating new solution: cost 450, meets the behavioral constraints. - Updated best found solution, cost: 450 - Evaluating new solution: cost 446, meets the behavioral constraints. - Updated best found solution, cost: 446 - Evaluating new solution: cost 442, meets the behavioral constraints. - Updated best found solution, cost: 442 - Evaluating new solution: cost 438, meets the behavioral constraints. - Updated best found solution, cost: 438 - Evaluating new solution: cost 436, meets the behavioral constraints. - Updated best found solution, cost: 436 - Evaluating new solution: cost 434, does not meet the behavioral constraints. - Evaluating new solution: cost 430, does not meet the behavioral constraints. - Evaluating new solution: cost 434, meets the behavioral constraints. - Updated best found solution, cost: 434 - Evaluating new solution: cost 432, meets the behavioral constraints. - Updated best found solution, cost: 432 - Evaluating new solution: cost 426, meets the behavioral constraints. - Updated best found solution, cost: 426 - Evaluating new solution: cost 416, meets the behavioral constraints. - Updated best found solution, cost: 416 - Evaluating new solution: cost 412, meets the behavioral constraints. - Updated best found solution, cost: 412 - Evaluating new solution: cost 408, meets the behavioral constraints. - Updated best found solution, cost: 408 - Evaluating new solution: cost 404, meets the behavioral constraints. - Updated best found solution, cost: 404 - Evaluating new solution: cost 400, meets the behavioral constraints. - Updated best found solution, cost: 400 - Evaluating new solution: cost 396, meets the behavioral constraints. - Updated best found solution, cost: 396 - Evaluating new solution: cost 394, meets the behavioral constraints. - Updated best found solution, cost: 394 - Evaluating new solution: cost 392, does not meet the behavioral constraints. - Evaluating new solution: cost 388, does not meet the behavioral constraints. - Evaluating new solution: cost 392, meets the behavioral constraints. - Updated best found solution, cost: 392 - Evaluating new solution: cost 390, meets the behavioral constraints. - Updated best found solution, cost: 390 - Evaluating new solution: cost 384, meets the behavioral constraints. - Updated best found solution, cost: 384 - Evaluating new solution: cost 374, meets the behavioral constraints. - Updated best found solution, cost: 374 - Evaluating new solution: cost 370, meets the behavioral constraints. - Updated best found solution, cost: 370 - Evaluating new solution: cost 366, meets the behavioral constraints. - Updated best found solution, cost: 366 - Evaluating new solution: cost 362, meets the behavioral constraints. - Updated best found solution, cost: 362 - Evaluating new solution: cost 358, meets the behavioral constraints. - Updated best found solution, cost: 358 - Evaluating new solution: cost 354, meets the behavioral constraints. - Updated best found solution, cost: 354 - Evaluating new solution: cost 352, meets the behavioral constraints. - Updated best found solution, cost: 352 - Evaluating new solution: cost 350, does not meet the behavioral constraints. - Evaluating new solution: cost 346, does not meet the behavioral constraints. - Evaluating new solution: cost 350, meets the behavioral constraints. - Updated best found solution, cost: 350 - Evaluating new solution: cost 348, meets the behavioral constraints. - Updated best found solution, cost: 348 - Evaluating new solution: cost 342, does not meet the behavioral constraints. - Evaluating new solution: cost 338, does not meet the behavioral constraints. - Evaluating new solution: cost 344, does not meet the behavioral constraints. + Optimization has finished. - Neighborhood search complete. - Maximum number of iterations completed. + Fixed-point implementation that satisfies the behavioral constraints found. The best found solution is applied on the model. - Total cost: 348 - Maximum absolute difference: 0.006126 - Use the explore method of the result to explore the implementation.

Use the `explore`

method of the `OptimizationResult`

object, `result`

, to open the Simulation Data Inspector and explore the design.

explore(result)

ans = OptimizationSolution with properties: Cost: 348 Pass: 1 MaxDifference: 0.0061 RunID: 21328 RunName: {'solution_56ed4ad01b357d644b124a742c8b97a4bc862de7_1'}