Extract Bits — Control Systems/Logic And Bit Operations
Control_Systems/Logic_And_Bit_Operations/Extract_Bits · 1 input / 1 output port(s) at insert · exports to Python, MATLAB, Java, Rust, C, C++, VHDL, Verilog, SystemVerilog, PLC Structured Text
Description#
The block's own DESCRIPTION_HTML, rendered verbatim — the same text the config dialog's info panel and the library navigator show. Fix a wrong sentence in the block's .cpp (R-D9), never here.
Extract Bits
Control Systems / Logic And Bit Operations
Reads its input as a whole number held in a word of W bits and answers a contiguous field of n of those bits, taken from bit low upwards: y = (floor(u) mod 2W ÷ 2low) mod 2n, optionally multiplied by 2low to leave the field at its original weight. Bit 0 is the LEAST significant bit. Applied entry by entry, so a matrix signal is treated element for element and the signal's size is unchanged.
Ports
- Input – the word u, of any size [m,n]. It is read as a whole number: the fractional part is discarded by floor, and a value outside [0, 2W) is wrapped into that range, which is what a negative input does.
- Output – y, of the SAME size [m,n] as the input, carrying the extracted field as an ordinary real signal.
Parameters
- Bits to Extract – which field is taken. This selects the field rather than
retuning it, so each option is a separate code path.
- Upper half – the top half of the word: low = W÷2 rounded DOWN, n = W − W÷2. The default, as in Simulink.
- Lower half – the bottom half: low = 0, and the same width as the upper half. On an ODD word that means the two halves are each (W+1)÷2 bits and they OVERLAP on the middle bit – measured, not rounded away.
- Range starting with most significant bit – the top Number of Bits bits: low = W − Number of Bits. A count larger than the word makes low negative, which shifts the whole word UP rather than being an error.
- Range ending with least significant bit – the bottom Number of Bits bits: low = 0, n = Number of Bits.
- Range of bits – the field named by Bit Index Range.
- Number of Bits – a positive whole number, read only by the two Range … with … bit options. Defaults to 8, as in Simulink.
- Bit Index Range – a two-entry vector [low high], read only by Range of bits. Both ends are INCLUSIVE and indices count from bit 0 at the least significant end, so [3 9] is a seven-bit field. Defaults to [0 7], as in Simulink. A reversed pair gives a one-bit field at low, which is what Simulink answers.
- Output Scaling Mode – what weight the extracted field carries.
- Preserve fixed-point scaling – the field keeps its place in the word, i.e. the answer is multiplied by 2low. The default, as in Simulink.
- Treat bit field as an integer – the field is brought down to bit 0.
- Input Word Length (bits) – W, a whole number from 1 to 53. This block has no data types, so the word length is a parameter here where in Simulink it is the width of the input signal's integer type; it decides where the halves fall, what a range off the top reads and where a negative input wraps to. Defaults to 16.
- Sampling Time (s) – zero or less inherits the solver's rate; a positive value runs the block at that period.
Code export
All ten targets: Python, MATLAB, Java, Rust, C,
C++, VHDL, Verilog, SystemVerilog and PLC Structured Text.
Every choice is structural and is baked into the generated body at export time rather than
exposed as a tunable parameter: the field is emitted as the two exact powers of two that shift
and mask it. The four whole-number targets carry a narrower word than the other six.
The three HDL cores turn the input into a whole number with a 32-bit integer and hand the
answer back through a Q16.16 port, and PLC Structured Text builds its floor from
TRUNC, which yields a DINT – so a word longer than 30 bits, or a
configuration whose largest possible output exceeds 32767, is refused by those four with
a message naming the limit, rather than exported as something that silently overflows. The
seven software targets carry the block to the full 53 bits.
Simulink bridge
Import and export, mapped to simulink/Logic and Bit Operations/Extract Bits. "Bits to
Extract" to bitsToExtract and "Output Scaling Mode" to
outScalingMode, one option for one option, so both round trips are lossless;
"Number of Bits" to numBits and "Bit Index Range" to bitIdxRange as
plain pass-through values. "Input Word Length (bits)" does NOT cross and is reported: on
the Simulink side that number is the width of the INPUT SIGNAL's integer data type, not a
parameter of the block, so no set_param can carry it – a model crossing
either way needs a Data Type Conversion of the matching width in front of the block.
The Simulink block defines no SampleTime parameter, so
"Sampling Time (s)" does not cross – a block left at the inheriting
default loses nothing, and one given an explicit period is reported rather than
silently dropped.
Notes
- Algebraic, with no state: the output depends only on the current input.
- Not linear – floor, a wrap and a mask are not a linear map – so the block deliberately carries no state space and model reduction reports it as unmergeable.
- The input is read with floor, not rounding, which is the same direction the HDL
targets'
fx_to_inttakes and is what keeps the ten backends agreeing on a value that is not already whole. Feed the block whole numbers if the distinction matters. - A field that runs off the top of the word reads zeros there rather than raising an error, and a Range starting with most significant bit whose count exceeds the word shifts the word UP instead. Both are what Simulink answers, measured.
- On an odd word the two halves overlap on the middle bit, because each of them is (W+1)÷2 bits wide rather than one being the remainder of the other. Measured against Simulink on a 5-bit word.
- Simulink's counterpart is a pass-through on a floating-point signal – it reads a stored integer – so a model crossing the bridge needs a Data Type Conversion to the matching integer type in front of it. This block reads its own input as a whole number instead, which is what lets it stand in an all-real signal path.
- To extract the exponent, mantissa or sign of a floating-point value rather than a field of an integer word, that is a different block – this one reads its input as a whole number.
Code facts#
| Fact | Value |
|---|---|
| registered type | Control_Systems/Logic_And_Bit_Operations/Extract_Bits |
| family | Control_Systems/Logic_And_Bit_Operations |
| solver environment class | ICoreBlock_0_Control_Systems_1_Logic_And_Bit_Operations_2_Extract_Bits |
| source | src/ICoreBlocks/ICoreBlockLibrary/Blocks/Control_Systems/Logic_And_Bit_Operations/Extract_Bits/ICoreBlock_0_Control_Systems_1_Logic_And_Bit_Operations_2_Extract_Bits.cpp |
| header | src/ICoreBlocks/ICoreBlockLibrary/Blocks/Control_Systems/Logic_And_Bit_Operations/Extract_Bits/ICoreBlock_0_Control_Systems_1_Logic_And_Bit_Operations_2_Extract_Bits.h |
| default size on canvas | 90 × 70 px |
| ports at insert | 1 in, 1 out |
| code generators implemented | Python, MATLAB, Java, Rust, C, C++, VHDL, Verilog, SystemVerilog, PLC Structured Text |
Ports#
| # | Direction | Signal type | Description label |
|---|---|---|---|
| 1 | in | ICoreDouble | — |
| 2 | out | ICoreDouble | — |
Ports the constructor creates. A block whose port list changes with its configuration adds or removes ports at load time; the count above is the one a freshly inserted block has.
Configuration variables#
| Config variable | Default | Simulink parameter |
|---|---|---|
Bits to Extract | Upper half%~%Lower half%~%Range starting with most signif… | bitsToExtract |
Number of Bits | 8 | numBits |
Bit Index Range | [0 7] | bitIdxRange |
Output Scaling Mode | Preserve fixed-point scaling%~%Treat bit field as an inte… | outScalingMode |
Input Word Length (bits) | 16 | not crossed |
Every block also carries Sampling Time (s) from ICoreBlockSolverEnvironment: zero or less inherits the solver's rate, a positive value runs the block at that period.
Simulink bridge#
| support | Support::Both |
| Simulink path | simulink/Logic and Bit Operations/Extract Bits |
| port-count rule | PortsParam::None |
SampleTime parameter | no — the counterpart defines none; the rate stays on the ICore side |
| deliberately not crossed | Input Word Length (bits) |
| ICore config | Simulink parameter | Value translation |
|---|---|---|
Bits to Extract | bitsToExtract | Upper half → Upper half, Lower half → Lower half, Range starting with most significant bit → Range starting with most significant bit, Range ending with least significant bit → Range ending with least significant bit, Range of bits → Range of bits |
Number of Bits | numBits | passes through |
Bit Index Range | bitIdxRange | passes through |
Output Scaling Mode | outScalingMode | Preserve fixed-point scaling → Preserve fixed-point scaling, Treat bit field as an integer → Treat bit field as an integer |
Caveat (shown to the user): "Input Word Length (bits)" has no Simulink parameter behind it -- there the word length is the width of the input signal's integer data type, so a model crossing either way needs a Data Type Conversion of the matching width in front of the block; the Simulink block has NO SampleTime parameter, so "Sampling Time (s)" does not cross either
Catalog contract: src/ICoreBlocks/ICoreCoder/ICoreCommandSystem/SimulinkBridge/ICoreSimulinkBlockCatalog.h
Description vs code#
The checker has a blind spot here — it could not resolve something (a grouped port bullet, a computed config name), which is reported and never counted as a pass. A reader has to settle it:
B0no sample under docs/generated/samples/ — nothing to cross-check (P8.1)
The verdict above is
tools/docs/check_block_descriptions.py(P7.1), which compares LISTS. It cannot read a sentence: "stateless" on a block with a state, an initial-value semantic the recursion does not implement, a "not synthesizable" caveat the HDL banner contradicts. That is the agent audit (P7.3) on BLOCK_DESCRIPTION_AUDIT.md, and this tool's green is not a substitute for one.
File banner (developer view)#
The top comment of the block's .cpp — the maths, the realization and the export strategy, addressed to whoever changes it. It must not contradict the description above (P7.5).
Extract Bits -- a contiguous slice of an input read as a whole-number WORD See the header for the arithmetic. Everything below follows from four things measured against R2026a rather than assumed, and each one is a silent wrong answer taken the other way:
- BIT 0 IS THE LEAST SIGNIFICANT BIT and a "Bit Index Range" is INCLUSIVE at both ends.
Measured on a uint16 [3 9]: a 7-bit field, (u >> 3) & 127, so 255 answered 31 and 65280 answered 96.
- THE TWO SCALING MODES DIFFER BY A SHIFT, NOT BY A MASK. "Treat bit field as an integer"
brings the field down to bit 0; "Preserve fixed-point scaling" leaves it at its original weight, i.e. multiplies the same field by 2^low. Measured: [3 9] over a uint16 answered 31 and 248 on the same sample, and 248 = 31 * 8.
- A RANGE MAY RUN OFF THE TOP OF THE WORD, and the bits above it simply read ZERO rather
than being an error. Measured: [3 20] on a uint16 is (u >> 3) with nothing masked away, because the input has no bits above 15 to mask.
- A RANGE MAY RUN OFF THE BOTTOM, which is what "Range starting with most significant
bit" does when its count exceeds the word:
lowgoes NEGATIVE and the field is the word shifted UP. Measured: numBits 20 over a uint16 answered u * 16, i.e. low = -4.
- BOTH HALVES ARE ceil(W/2) BITS, so on an ODD word they OVERLAP on the middle bit.
This one was found the hard way: the obvious reading -- lower half floor(W/2), upper half the rest -- passes every even word and is wrong on every odd one. Measured on a 5-bit word, where the lower half answered 5 for the word 5, which a two-bit mask cannot do, and Simulink typed BOTH outputs ufix3.
AND THE BLOCK MEANS NOTHING ON A FLOATING-POINT SIGNAL. Measured: fed a
double, Simulink's Extract Bits is a PASS-THROUGH -- 3.75 came back 3.75 and -5 came back -5, in every mode. It reads a stored integer, so a model on that side needs a Data Type Conversion to the integer type whose width matches "Input Word Length (bits)" in front of it. That is the same sentence the bridge notes carry, measured rather than assumed.ONE FORMULA, ELEVEN IMPLEMENTATIONS. The block's private
extract()helper is the C++ reference, and every generator below emits the same four steps -- floor, wrap, shift-and-mask, rescale -- as target-language text. The shift is written as a MULTIPLICATION by 2^(-low) rather than a division by 2^low precisely so that the negative-low case above needs no second code path in any of the ten languages: both are exact, because both factors are powers of two.THE FOUR NON-FLOATING TARGETS ARE LIMITED BY THEIR WHOLE-NUMBER TYPE, and the block says so rather than emitting something that overflows in silence. The three HDL cores carry a whole number through
fx_to_int, whose result is a 32-bit integer, and hand the answer back
Sample results#
No sample run is committed for this block. Samples come from the headless harness (DOCS_PLAN.md P8.1) into docs/generated/samples/; until one exists this block's behaviour is witnessed by the parity and export-verification suites, not by a plot here.