Main Content

The `eml_hdl_design_patterns`

library is an extensive collection
of examples demonstrating useful applications of the MATLAB Function
block in HDL code generation.

To open the library, type the following command at the MATLAB^{®} prompt:

eml_hdl_design_patterns

You can use many blocks in the library as cookbook examples of various hardware elements, as follows:

Copy a block from the library to your model and use it as a computational unit.

Copy the code from the block and use it as a local function in an existing MATLAB Function block.

When you create custom blocks, you can control whether to inline or instantiate
the HDL code generated from MATLAB Function blocks. Use the
**Inline MATLAB Function block code** check box in the **HDL Code Generation** > **Global Settings** > **Coding style** section of the Configuration Parameters dialog box. For more
information, see Inline MATLAB Function block code.

**Note**

Do not use the **Inline MATLAB Function block code** setting
with the `MATLAB Datapath`

architecture of the MATLAB
Function block. Use **FlattenHierarchy** instead.
For more information, see HDL Optimizations Across MATLAB Function Block Boundary Using MATLAB Datapath Architecture.

The MATLAB Function block supports floating-point arithmetic and
also fixed point arithmetic by using the Fixed-Point Designer™
`fi`

function. This function supports rounding and saturation
modes that are useful for coding algorithms that manipulate arbitrary word and
fraction lengths. HDL Coder™ supports all
`fi`

rounding and overflow modes. HDL code generated from the
MATLAB Function block is bit-true to MATLAB semantics. Generated code uses bit manipulation and bit access
operators (for example, Slice, Extend, Reduce, Concat, etc.) that are native to
VHDL^{®} and Verilog^{®}.

The following discussion shows how HDL code generated from the MATLAB Function block follows cast-before-sum semantics, in which addition and subtraction operands are cast to the result type before the addition or subtraction is performed.

Open the `eml_hdl_design_patterns`

library and select the
`Combinatorics/eml_expr`

block. `eml_expr`

implements a simple expression containing addition, subtraction, and multiplication
operators with differing fixed point data types. The generated HDL code shows the
conversion of this expression with fixed point operands. The MATLAB
Function block uses the following code:

% fixpt arithmetic expression expr = (a*b) - (a+b); % cast the result to (sfix7_En4) output type y = fi(expr, 1, 7, 4);

The default `fimath`

specification for the block determines the
behavior of arithmetic expressions using fixed point operands inside the
MATLAB Function block:

fimath(... 'RoundMode', 'ceil',... 'OverflowMode', 'saturate',... 'ProductMode', 'FullPrecision', 'ProductWordLength', 32,... 'SumMode', 'FullPrecision', 'SumWordLength', 32,... 'CastBeforeSum', true)

The data types of operands and output are as follows:

`a`

:`(sfix5_En2)`

`b`

:`(sfix5_En3)`

`y`

:`(sfix7_En4)`

Before HDL code generation, this expression is broken down internally into many steps.

expr = (a*b) - (a+b);

The steps include:

`tmul = a * b;`

`tadd = a + b;`

`tsub = tmul - tadd;`

`y = tsub;`

Based on the `fimath`

settings as described in Design Guidelines for the MATLAB Function Block, this expression is further broken down
internally as follows:

Based on the specified

`ProductMode`

,`'FullPrecision'`

, the output type of`tmul`

is computed as`(sfix10_En5)`

.Since the

`CastBeforeSum`

property is set to`'true'`

, step 2 is broken down as follows:t1 = (sfix7_En3) a; t2 = (sfix7_En3) b; tadd = t1 + t2;

`sfix7_En3`

is the result sum type after aligning binary points and accounting for an extra bit to account for possible overflow.Based on intermediate types of

`tmul (sfix10_En5)`

and`tadd (sfix7_En3)`

the result type of the subtraction in step 3 is computed as`sfix11_En5`

. Accordingly, step 3 is broken down as follows:t3 = (sfix11_En5) tmul; t4 = (sfix11_En5) tadd; tsub = t3 - t4;

Finally, the result is cast to a smaller type (

`sfix7_En4`

) leading to the following final expression statements:tmul = a * b; t1 = (sfix7_En3) a; t2 = (sfix7_En3) b; tadd = t1 + t2; t3 = (sfix11_En5) tmul; t4 = (sfix11_En5) tadd; tsub = t3 - t4; y = (sfix7_En4) tsub;

The following listings show the generated VHDL and Verilog code from the `eml_expr`

block.

This is the VHDL code:

BEGIN --MATLAB Function 'Subsystem/eml_expr': '<S2>:1' -- fixpt arithmetic expression --'<S2>:1:4' mul_temp <= signed(a) * signed(b); sub_cast <= resize(mul_temp, 11); add_cast <= resize(signed(a & '0'), 7); add_cast_0 <= resize(signed(b), 7); add_temp <= add_cast + add_cast_0; sub_cast_0 <= resize(add_temp & '0' & '0', 11); expr <= sub_cast - sub_cast_0; -- cast the result to correct output type --'<S2>:1:7' y <= "0111111" WHEN ((expr(10) = '0') AND (expr(9 DOWNTO 7) /= "000")) OR ((expr(10) = '0') AND (expr(7 DOWNTO 1) = "0111111")) ELSE "1000000" WHEN (expr(10) = '1') AND (expr(9 DOWNTO 7) /= "111") ELSE std_logic_vector(expr(7 DOWNTO 1) + ("0" & expr(0))); END fsm_SFHDL;

This is the Verilog code:

//MATLAB Function 'Subsystem/eml_expr': '<S2>:1' // fixpt arithmetic expression //'<S2>:1:4' assign mul_temp = a * b; assign sub_cast = mul_temp; assign add_cast = {a[4], {a, 1'b0}}; assign add_cast_0 = b; assign add_temp = add_cast + add_cast_0; assign sub_cast_0 = {{2{add_temp[6]}}, {add_temp, 2'b00}}; assign expr = sub_cast - sub_cast_0; // cast the result to correct output type //'<S2>:1:7' assign y = (((expr[10] == 0) && (expr[9:7] != 0)) || ((expr[10] == 0) && (expr[7:1] == 63)) ? 7'sb0111111 : ((expr[10] == 1) && (expr[9:7] != 7) ? 7'sb1000000 : expr[7:1] + $signed({1'b0, expr[0]})));

These code excerpts show that the generated HDL code from the MATLAB
Function block represents the bit-true behavior of fixed point
arithmetic expressions using high-level HDL operators. The HDL code is generated
using HDL coding rules like high level `bitselect`

and
`partselect`

replication operators and explicit sign extension
and resize operators.

In the MATLAB Function block programming model, state-holding
elements are represented as persistent variables. A variable that is declared
`persistent`

retains its value across function calls in
software, and across sample time steps during simulation.

Please note that your MATLAB code *must* read the persistent variable before it
is written if you want HDL Coder to infer a register in the HDL code. The code generator displays a
warning message if your code does not follow this rule.

The following example shows the `unit delay`

block, which delays
the input sample, `u`

, by one simulation time step.
`u`

is a fixed-point operand of type `sfix6`

.
`u_d`

is a persistent variable that holds the input
sample.

function y = fcn(u) persistent u_d; if isempty(u_d) u_d = fi(-1, numerictype(u), fimath(u)); end % return delayed input from last sample time hit y = u_d; % store the current input to be used later u_d = u;

Because this code intends for `u_d`

to infer a register during
HDL code generation, `u_d`

is read in the assignment statement,
`y = u_d`

, before it is written in ```
u_d =
u
```

.

HDL Coder generates the following HDL code for the `unit delay`

block.

ENTITY Unit_Delay IS PORT ( clk : IN std_logic; clk_enable : IN std_logic; reset : IN std_logic; u : IN std_logic_vector(15 DOWNTO 0); y : OUT std_logic_vector(15 DOWNTO 0)); END Unit_Delay; ARCHITECTURE fsm_SFHDL OF Unit_Delay IS BEGIN initialize_Unit_Delay : PROCESS (clk, reset) BEGIN IF reset = '1' THEN y <= std_logic_vector(to_signed(0, 16)); ELSIF clk'EVENT AND clk = '1' THEN IF clk_enable = '1' THEN y <= u; END IF; END IF; END PROCESS initialize_Unit_Delay;

Initialization of persistent variables is moved into the master reset region in the initialization process.

Refer to the `Delays`

subsystem in the
`eml_hdl_design_patterns`

library to see how vectors of
persistent variables can be used to model integer delay, tap delay, and tap delay
vector blocks. These design patterns are useful in implementing sequential
algorithms that carry state between executions of the MATLAB Function
block in a model.

The MATLAB Function block helps you author intellectual property and create alternate implementations of part of an algorithm. By using MATLAB Function blocks in this way, you can guide the detailed operation of the HDL code generator even while writing high-level algorithms.

For example, the subsystem `Comparators`

in the
`eml_hdl_design_patterns`

library includes several alternate
algorithms for finding the minimum value of a vector. The
`Comparators/eml_linear_min`

block finds the minimum of the
vector in a linear mode serially. The `Comparators/eml_tree_min`

block compares the elements in a tree structure. The tree implementation can achieve
a higher clock frequency by adding pipeline registers between the
`log2(N)`

stages. (See
`eml_hdl_design_patterns/Filters`

for an example.)

Now consider replacing the simple comparison operation in the
`Comparators`

blocks with an arithmetic operation (for example,
addition, subtraction, or multiplication) where intermediate results must be
quantized. Using `fimath`

rounding settings, you can fine tune
intermediate value computations before intermediate values feed into the next stage.
You can use this technique for tuning the generated hardware or customizing your
algorithm.

You can declare a nontunable parameter for a MATLAB Function block
by setting its **Scope** to `Parameter`

in
the Ports and Data Manager GUI, and clearing the **Tunable**
option.

A nontunable parameter does not appear as a signal port on the block. Parameter
arguments for MATLAB Function blocks take their values from
parameters defined in a parent Simulink^{®} masked subsystem or from variables defined in the MATLAB base workspace, not from signals in the Simulink model.

MATLAB Function block control constructs such as
`switch/case`

and `if-elseif-else`

, coupled
with fixed point arithmetic operations let you model control logic quickly.

The `FSMs/mealy_fsm_blk`

and`FSMs/moore_fsm_blk`

blocks in the `eml_hdl_design_patterns`

library provide example
implementations of Mealy and Moore finite state machines in the MATLAB
Function block.

The following listing implements a Moore state machine.

function Z = moore_fsm(A) persistent moore_state_reg; if isempty(moore_state_reg) moore_state_reg = fi(0, 0, 2, 0); end S1 = 0; S2 = 1; S3 = 2; S4 = 3; switch uint8(moore_state_reg) case S1, Z = true; if (~A) moore_state_reg(1) = S1; else moore_state_reg(1) = S2; end case S2, Z = false; if (~A) moore_state_reg(1) = S1; else moore_state_reg(1) = S2; end case S3, Z = false; if (~A) moore_state_reg(1) = S2; else moore_state_reg(1) = S3; end case S4, Z = true; if (~A) moore_state_reg(1) = S1; else moore_state_reg(1) = S3; end otherwise, Z = false; end

In this example, a persistent variable (`moore_state_reg`

) models
state variables. The output depends only on the state variables, thus modeling a
Moore machine.

The `FSMs/mealy_fsm_blk`

block in the
`eml_hdl_design_patterns`

library implements a Mealy state
machine. A Mealy state machine differs from a Moore state machine in that the
outputs depend on inputs as well as state variables.

The MATLAB Function block can quickly model simple state machines and other control-based hardware algorithms (such as pattern matchers or synchronization-related controllers) using control statements and persistent variables.

For modeling more complex and hierarchical state machines with complicated
temporal logic, use a Stateflow^{®} chart to model the state machine.

To implement arithmetic and control logic algorithms in MATLAB Function blocks intended for HDL code generation, there are some simple HDL related coding requirements:

The top level MATLAB Function block must be called once per time step.

It must be possible to fully unroll program loops.

Persistent variables with reset values and update logic must be used to hold values across simulation time steps.

Quantized data variables must be used inside loops.

The following script shows how to model a synchronous up/down counter with preset
values and control inputs. The example provides both master reset control of
persistent state variables and local reset control using block inputs (e.g.
`presetClear`

). The `isempty`

condition enters
the initialization process under the control of a synchronous reset. The
`presetClear`

section is implemented in the output section in
the generated HDL code.

Both the up and down case statements implementing the count loop require that the values of the counter are quantized after addition or subtraction. By default, the MATLAB Function block automatically propagates fixed-point settings specified for the block. In this script, however, fixed-point settings for intermediate quantities and constants are explicitly specified.

function [Q, QN] = up_down_ctr(upDown, presetClear, loadData, presetData) % up down result % 'result' syntheses into sequential element result_nt = numerictype(0,4,0); result_fm = fimath('OverflowMode', 'saturate', 'RoundMode', 'floor'); initVal = fi(0, result_nt, result_fm); persistent count; if isempty(count) count = initVal; end if presetClear count = initVal; elseif loadData count = presetData; elseif upDown inc = count + fi(1, result_nt, result_fm); -- quantization of output count = fi(inc, result_nt, result_fm); else dec = count - fi(1, result_nt, result_fm); -- quantization of output count = fi(dec, result_nt, result_fm); end Q = count; QN = bitcmp(count);

The following code example shows how to model shift registers in MATLAB
Function block code by using the `bitsliceget`

and
`bitconcat`

functions. This function implements a serial
input and output shifters with a 32–bit fixed-point operand input. See the
`Shift Registers/shift_reg_1by32`

block in the
`eml_hdl_design_patterns`

library for more details.

function sr_out = fcn(shift, sr_in) %shift register 1 by 32 persistent sr; if isempty(sr) sr = fi(0, 0, 32, 0, 'fimath', fimath(sr_in)); end % return sr[31] sr_out = getmsb(sr); if (shift) % sr_new[32:1] = sr[31:1] & sr_in sr = bitconcat(bitsliceget(sr, 31, 1), sr_in); end

The following code example shows VHDL process code generated for the `shift_reg_1by32`

block.

shift_reg_1by32 : PROCESS (shift, sr_in, sr) BEGIN sr_next <= sr; -- MATLAB Function Function 'Subsystem/shift_reg_1by32': '<S2>:1' --shift register 1 by 32 --'<S2>:1:1 -- return sr[31] --'<S2>:1:10' sr_out <= sr(31); IF shift /= '0' THEN --'<S2>:1:12' -- sr_new[32:1] = sr[31:1] & sr_in --'<S2>:1:14' sr_next <= sr(30 DOWNTO 0) & sr_in; END IF; END PROCESS shift_reg_1by32;

The `Shift Registers/shift_reg_1by64`

block shows a 64 bit
shifter. In this case, the shifter uses two fixed point words, to represent the
operand, overcoming the 32–bit word length limitation for fixed-point integers.

Browse the `eml_hdl_design_patterns`

model for other useful
hardware elements that can be easily implemented using the MATLAB
Function block.

You can perform conversions from an integer type to generate a bit vector output
and vice-versa. For an example model that shows how to perform this conversion, open
the model
`hdlcoder_int2bits_bits2int`

.

`open_system('hdlcoder_int2bits_bits2int')`

`eml_hdl_design_patterns`

library under the ```
Word
Twiddlers
```

library.Check for MATLAB Function block settings