Multiport Switch — Control Systems/Signal Routing
Control_Systems/Signal_Routing/Multiport_Switch · 4 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.
Multiport Switch
Control Systems / Signal Routing
Passes one of several data inputs through, chosen on every sample by a control input: y = d[trunc(k) − base], where k is the control value, d the list of data inputs and base is 0 or 1 according to Data Port Order. An index outside the list selects the last data input.
Ports
- k – the control, and it is the FIRST port. It must be a scalar [1,1]. A non-integer value is truncated TOWARD ZERO, so −0.9, −0.5 and −0.1 all give 0.
- d1 … dN – the data inputs, one per remaining port. The count is editable: add or remove input ports and the list grows or shrinks with them. All of them must be the same size [m,n], except that a [1,1] input is broadcast to that size.
- Output – y, the selected data input unchanged, of size [m,n]. With exactly ONE data input the output is a scalar [1,1] instead – see the note on element selection below.
Parameters
- Data Port Order – what index the FIRST data input answers to.
This shifts the whole chain rather than retuning it, so each option is a
separate code path.
- One-based contiguous – the first data input is 1, the second 2, and so on. The default, as in Simulink.
- Zero-based contiguous – the first data input is 0.
- 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 port order and the number of data inputs are
structural, so the whole branch chain is baked into the generated body at export
time rather than exposed as a tunable parameter; the control is the only thing
the core evaluates. Each branch is emitted as the interval of control values
that truncates to that branch's index – a pair of comparisons –
rather than as an integer conversion, because no integer conversion in the three
HDL targets truncates toward zero (their fx_to_int is a shift, i.e.
a floor). The HDL targets are fully synthesizable: a comparison of two Q16.16
words needs no arithmetic.
Simulink bridge
Import and export, mapped to simulink/Signal Routing/Multiport
Switch. "Data Port Order" to DataPortOrder, one option for one
option, so that round trip is lossless. The number of DATA inputs crosses as
Inputs, derived from the ICore input-port list minus its control
port rather than from a config variable. DataPortForDefault is
always written as Last data port and
DiagnosticForDefault as None: this block always falls
back to the last data input and never stops the run for an out-of-range index,
so pinning both is what keeps the two sides comparing the same thing.
AllowDiffInputSizes is pinned off for the same reason.
Simulink's third order, Specify indices, is not offered – a block
using it is reported on import rather than mapped onto a contiguous chain that
would answer differently. "Sampling Time (s)" to SampleTime, as on
every block.
simulink/Signal Routing/Index Vector is the SAME Simulink block under a second library path, preset to one data input and zero-based order (measured). It folds onto this block on import, with both presets replayed; an export re-emits it as a Multiport Switch, which is the same block.
Notes
- Algebraic, with no state: the output depends only on the current sample.
- ONE data input means element selection, not port selection. With a single data input the control indexes INTO that input's signal, in column-major order, and the output is the single selected entry. That is what Simulink's Index Vector is, and it is the same block.
- An index outside the list selects the last data input rather than stopping the run. Simulink offers a diagnostic there instead; this block does not, and the bridge pins the Simulink parameter to match.
- Not linear – the output is a branch on the control – so the block deliberately carries no state space and model reduction reports it as unmergeable.
- An HDL core sees its control already quantized to one part in 1.5×10⁻⁵, so a control lying within a quantum of a whole number can truncate to the neighbouring index – and selecting a different data input changes the whole output rather than nudging it. Drive the control with a signal that is already integral where that matters; whole numbers are exact in Q16.16.
- To choose between exactly two inputs on a threshold, use Signal Routing / Switch; to choose with no control signal at all, use Signal Routing / Manual Switch.
Code facts#
| Fact | Value |
|---|---|
| registered type | Control_Systems/Signal_Routing/Multiport_Switch |
| family | Control_Systems/Signal_Routing |
| solver environment class | ICoreBlock_0_Control_Systems_1_Signal_Routing_2_Multiport_Switch |
| source | src/ICoreBlocks/ICoreBlockLibrary/Blocks/Control_Systems/Signal_Routing/Multiport_Switch/ICoreBlock_0_Control_Systems_1_Signal_Routing_2_Multiport_Switch.cpp |
| header | src/ICoreBlocks/ICoreBlockLibrary/Blocks/Control_Systems/Signal_Routing/Multiport_Switch/ICoreBlock_0_Control_Systems_1_Signal_Routing_2_Multiport_Switch.h |
| default size on canvas | 80 × 100 px |
| ports at insert | 4 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 | k |
| 2 | in | ICoreDouble | d1 |
| 3 | in | ICoreDouble | d2 |
| 4 | in | ICoreDouble | d3 |
| 5 | 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 |
|---|---|---|
Data Port Order | One-based contiguous%~%Zero-based contiguous~~One-based c… | DataPortOrder |
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/Signal Routing/Multiport Switch |
| port-count rule | PortsParam::MultiPortSwitchInputs |
SampleTime parameter | yes |
| always set | DataPortForDefault = Last data port, DiagnosticForDefault = None, AllowDiffInputSizes = off |
| ICore config | Simulink parameter | Value translation |
|---|---|---|
Data Port Order | DataPortOrder | One-based contiguous → One-based contiguous, Zero-based contiguous → Zero-based contiguous |
Caveat (shown to the user): the control is the FIRST port and the data ports follow it; a non-integer control is truncated TOWARD ZERO and an out-of-range index selects the LAST data port, both measured against R2026a. Simulink's "Specify indices" order is not offered
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:
B0Ports lists 3 entries for 5 ports (4 in, 1 out), and the 3 they cover does not reconcile — grouped, or one undocumented? a reader must sayB0no 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).
Multiport Switch block -- one of N data inputs, chosen per sample by a control input y = d[trunc(k) - base], with k the control on the FIRST input port, d the data inputs that follow it, and base 0 or 1 per "Data Port Order". An index outside the list selects the LAST data port. With exactly ONE data port the block indexes INTO that port's signal instead of choosing between ports -- Simulink ships that arrangement as
Index Vector, and this block serves both.EVERYTHING ABOUT THE INDEX WAS MEASURED IN R2026a, because every one of these is a silent wrong answer if it is assumed the other way round:
trunc, NOT floor. Zero-based, three data ports, control -0.9 / -0.5 / -0.1: all three selected the FIRST data port. A floor would have sent every one of them out of range and onto the last port instead. Simulink's own RndMeth on this block reads "Floor". Out of range -> the LAST data port. Control 0, 4 and -1 against three one-based ports all gave the last one, with DiagnosticForDefault set to None. One data port -> element selection. Data [10 20 30], zero-based, control 0/1/2 gave 10/20/30; control 2 with THREE data ports gave the third port's whole signal.
Code export: the port order and the port COUNT are both structural, so the branch chain is emitted at export time and the control is the only thing the core evaluates. Every backend gets the same chain -- a comparison per branch against the interval that truncates to that branch's index -- rather than an integer conversion, which is what keeps the three HDL targets synthesizable without an integer scratch and makes the truncation rule identical in all eleven implementations.
HDL: fully synthesizable. Comparing two Q16.16 words is a signed compare. The caveat is the usual one for a block that DISCRETIZES its input: the control arrives already quantized to 1.5e-5, so a control sitting within a quantum of a whole number can truncate to the neighbouring index, and picking a different data port is a whole-signal difference rather than a small one. Stated in the description; a control that is already integral is exact, because integers are exact in Q16.16.
Algebraic and stateless. No state space -- see the header.
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.