Interfacing hardware components with fixed bit width in Simulink/HDL Coder

6 views (last 30 days)
I am searching for a generic solution for the following problem:
Some FPGA synthesis tools require very specific VHDL code for correctly inferring components such as DSPs (math blocks). Instead of tweaking Simulink/HDL Coder for generating this code according to the synthesizer rules, I wish to handle this by instantiating objects that are configured as BlackBox architectures (i.e. manually written HDL modules) and lock the inputs and outputs towards these objects to the fixed point width of the components. HDL Coder will then instantiate the respective HDL module with correct signals tied to the ports. However, when doing this, Simulink no longer has control of the binary point in the respective paths.
Is there a way of locking the word length of a signal without locking the fraction length?

Accepted Answer

Andy Bartlett
Andy Bartlett on 22 Nov 2022
Edited: Andy Bartlett on 22 Nov 2022
Reinterpret Scaling Cast
A technique to achieve goals like you described is to use a "Reinterpret Scaling Cast". The key idea of a "Reinterpret Scaling Cast" is that the raw bits stored in memory are identical for the both the input and the output. For the "Reinterpret Scaling Cast" concept, we don't allow the signedness or word length to change, so both input and output have identical Stored Integer values. What can change is the scaling of the input and output. Changing the scaling will mean that the Real World Value interpretation of the bits will change.
A key attribute of a reinterpretation scaling cast is that its generated code is a no-op. The output stored integer bits are identical to the input stored integer bits, so there is nothing to do. If you are generating C code, you will see no extra code for the actual reinterpretation operation. Likewise in HDL the bits that were stored in the inputs flip-flops are exactly the bits for the output; no need for new flip-flops, no need for additional latency. It's free as in no code and infinitely fast.
A special case of Reinterpret Scaling Cast is a Strip Scaling Cast. This special case forces the output scaling to be trivial so Bias = 0 and Slope = 1. Equivalently, FractionLength = 0, FixedExponent = 0.
In MATLAB with fi objects, you can use the function reinterpretcast and stripscaling.
In Simulink, you can use the Data Type Conversion block with
parameter: Input and output to have equal: Stored Integer (SI)
When in this mode, the block icon will contain the telltale label (SI).
Simulink also provides a Data Type Strip Scaling block, but I would not recommend that for HDL applications because it will also change the word length to be the smallest choice of 8, 16, 32, or 128, that is greater or equal to the input.
The attached Library ReinterpExampleLib.slx contains an example of a Strip Scaling Block where the word length is never changed.
Example Reusing Raw Integer Module
The attached model reinterp_example.slx shows an example of reusing a raw integer "module" for inputs with different scalings.
The raw module does uint32 times uint32 put into a uint64 product register. Then shifts right by 16 bits, thus dropping the least signifcant 16 bits from the ideal product. Finally, the shifted product is downcast to uint32 thus dropping the 16 most significant bits from the original 64 bit ideal product.
To reuse this module, the first step is to perform Strip Scaling. Next a regular cast is used to change the raw integer inputs to the word length required by the raw multiplication module. Depending on your application, you might be able to stop there.
This example went further and showed how to get the raw product back to scaling that gives a correct Real World Value. Again, a Reinterpret Scaling Cast is the key operation. We just need to feed the correct scaling to the output of that Reinterpret Scaling Cast. The Data Type Propagation block is used to get the desired scaling which is
slopeOut = slopeIn1 * slopeIn2 * 2^16
The desired data type gets automatically set on the Prop port of the Data Type Propagation block. During Simulink's data type propagation phase the Prop port data type information flows backwards to the Reinterpret Scaling Cast output port. The Reinterpret Scaling Cast has set its output data type as "Inherit via back propagation." So the Reinterpret Scaling Cast has been waiting for Simulink to propagate that type, and when it arrives the Reinterpret Scaling Cast says "Great, Thank You, I will use that data type." That's the meaning and point of "Inherit via back propagation."
The attached parent model exercises the example reuse of the raw multiply module. If you look closely at the two pairs of inputs and corresponding outputs, you can see that both the output Stored Integer hex and output Real World Values are as expected.
fp = fipref;
fp.NumericTypeDisplay = 'short';
u1 = fi(17.3505859375,0,29,18)
u2 = fi(256.00390625,0,32,17)
yIdeal1 = u1 * u2
yIdeal1_hex_str = yIdeal1.hex
yIdeal1 =
4441.81777572632
yIdeal1_hex_str =
'00008ace8ace0000'
Keep in mind that the last four hex "digits" are dropped, then the remaining least significant 8 hex "digits" are returned in the final output.
fp = fipref;
fp.NumericTypeDisplay = 'short';
u3 = fi(43108,0,25,3)
u4 = fi(17180262400,0,30,-5)
yIdeal2 = u3 * u4
yIdeal2_hex_str = yIdeal2.hex
yIdeal2 =
740606751539200
yIdeal2_hex_str =
'00a864fc960000'
More examples of using Data Type Propagation Block
To learn more about the capabilities of the Data Type Propagation Block, the shipping library fixpt_dtprop.slx provides many examples. Look under the mask of each block to study what it is doing.

More Answers (0)

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!