Combinatorial Logic — Control Systems/Logic And Bit Operations
Control_Systems/Logic_And_Bit_Operations/Combinatorial_Logic · 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.
Combinatorial Logic
Control Systems / Logic And Bit Operations
Reads its input as a binary word and outputs the matching row of a truth table:
index = Σ over k of (u[k] is nonzero) · 2(n-1-k), and y = row index of the table.
The first element of the input is the most significant bit and the index is 0-based, so a four-element input of [1 0 1 1] selects row 11. True means nonzero, not "equals one" – a negative element is true. Both are Simulink's conventions, measured rather than assumed.
Ports
- Input – the word u. It must carry exactly n elements, where the truth table has 2n rows; a mismatch stops the run rather than padding or truncating. Elements are read first-to-last (row-major), so either vector orientation reads the same.
- Output – y, the selected row as a column of m entries, where m is the table's COLUMN count. Its size comes from the table, not from the input, so this is one of the few blocks whose output size does not follow its input's.
Parameters
- Truth Table – the table itself, one row per input combination. Its row count must be a power of two (2, 4, 8, 16, …) and that is what fixes the input width. Rows run from the all-false combination downwards, so row 0 is the answer for all-zero input and the last row the answer for all-nonzero. Entries are ordinary numbers – nothing restricts them to 0 and 1. The default is [0; 1]: one input bit, one output, answering "is the input nonzero". Simulink's own default is a wider table, and the difference is deliberate – the value always crosses the bridge explicitly, and a narrow default is the one that works the moment the block is dropped on a canvas and fed a scalar.
- 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. The table is baked in at export time rather than exposed as a tunable parameter: its shape fixes the block's port widths, so it could not be retuned on a deployed core without re-generating it.
The targets divide in two. The seven software targets embed the table as an array and index it. The three HDL targets and PLC Structured Text emit one branch per row instead, because a fixed-point table has to become source literals and there is no array to index at run time. Both compute the same index from the same nonzero tests. The consequence worth knowing before choosing a wide table: on those four targets the generated code grows with the ROW COUNT, so an eight-bit table is 256 branches. The HDL cores are otherwise fully synthesizable – the only arithmetic is a comparison against zero.
Simulink bridge
Import and export, mapped to simulink/Logic and Bit Operations/Combinatorial Logic.
"Truth Table" maps to TruthTable, and "Sampling Time (s)" to
SampleTime, as on every block. The mapping is 1:1 and lossless.
One difference is worth stating because it does not cross and cannot: Simulink's block requires a boolean input port and refuses a double outright, so a Simulink model feeding it from arithmetic needs a Data Type Conversion in front. Here every signal is a matrix of doubles and the nonzero test does that job, which is why the two agree numerically without agreeing about types.
Notes
- Algebraic, with no state: the output depends only on the current sample.
- Deliberately carries no state space. A table lookup keyed on thresholded inputs is not a linear map, so model reduction reports the block as unmergeable rather than absorbing it.
- On the three HDL targets an input element within one Q16.16 quantum (about 1.5×10-5) of zero can be carried across the boundary by the port's own quantization and flip that bit – and one flipped bit selects a different row. This is the window every block in this family carries: it is a property of testing a pre-quantized value against a threshold, not a fault in the generated code, and the seven software targets are exact everywhere.
Code facts#
| Fact | Value |
|---|---|
| registered type | Control_Systems/Logic_And_Bit_Operations/Combinatorial_Logic |
| family | Control_Systems/Logic_And_Bit_Operations |
| solver environment class | ICoreBlock_0_Control_Systems_1_Logic_And_Bit_Operations_2_Combinatorial_Logic |
| source | src/ICoreBlocks/ICoreBlockLibrary/Blocks/Control_Systems/Logic_And_Bit_Operations/Combinatorial_Logic/ICoreBlock_0_Control_Systems_1_Logic_And_Bit_Operations_2_Combinatorial_Logic.cpp |
| header | src/ICoreBlocks/ICoreBlockLibrary/Blocks/Control_Systems/Logic_And_Bit_Operations/Combinatorial_Logic/ICoreBlock_0_Control_Systems_1_Logic_And_Bit_Operations_2_Combinatorial_Logic.h |
| default size on canvas | 80 × 80 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 |
|---|---|---|
Truth Table | [0; 1] | TruthTable |
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/Combinatorial Logic |
| port-count rule | PortsParam::None |
SampleTime parameter | yes |
| ICore config | Simulink parameter | Value translation |
|---|---|---|
Truth Table | TruthTable | passes through |
Caveat (shown to the user): Simulink's block REQUIRES a boolean input port and refuses a double, so a model on that side needs a Data Type Conversion in front of it; here the nonzero test does that job and the two agree numerically without agreeing about types
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).
Combinatorial Logic -- a truth table looked up by the input read as a binary word See the header for the three measured facts that decide the block: the FIRST element is the most significant bit, true means NONZERO, and the output is a whole ROW whose width comes from the table rather than from the input.
ONE PLACE DECIDES THE INDEX, ELEVEN IMPLEMENTATIONS AGREE ON IT. rowIndex() computes it in C++ for the live run; the generators below emit the same rule as target-language text. The two are written next to each other in this file's private helper so that a change to one is visibly a change to the other.
THE TEN BACKENDS SPLIT IN TWO, ON PURPOSE:
- The seven software targets embed the table as a literal ARRAY and index it. That is
O(rows x cols) of data and a constant amount of code, which is what a table wants.
- The three HDL targets and PLC Structured Text emit an if / else-if CHAIN, one arm per
row. They have no array the fixed-point framework can index at run time -- every table entry has to become a to_fx() literal in the source -- so the selection has to be in the control flow instead. It costs one arm per row, which is why a wide table is a hardware decision and the description says so.
Both shapes compute the same index from the same nonzero tests, so a table that disagreed between them would have to disagree in the ONE place that builds the condition text.
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.