TM
Block Preview

Introduction

Principle of Operation

This is the time-multiplexed twin of Polarity Invert. A TM bus carries TM Factor consecutive samples side by side in one clock; this block instantiates one inverter per lane and applies the same operation to all of them in parallel, still with zero latency.

For every lane $i = 0 \ldots \mathrm{TM} - 1$, when INVERT = 1:

Input sign operation in words
UNSIGNED $y_i = (2^{N_{\rm eff}} - 1) - x_i$ reflection about full scale — the bitwise complement
SIGNED $y_i = -x_i \pmod{2^{N_{\rm eff}}}$ two’s-complement negation

and when INVERT = 0 every lane passes through (truncated to $N_{\rm eff}$ = Effective # bits).

Lane layout

The bus is a plain concatenation and the lane pitch is Input bits, i.e. the port width — not Effective # bits. For a TM factor of 4 and Input bits = 16:

   bit  63        48 47        32 31        16 15         0
     ┌────────────┬────────────┬────────────┬────────────┐
 IN  │  lane 3    │  lane 2    │  lane 1    │  lane 0    │
     └────────────┴────────────┴────────────┴────────────┘
  

Lane $i$ occupies bits $[(i+1)\cdot A - 1 : i\cdot A]$ with $A$ = Input bits, and OUT uses the identical layout. Inside each lane only the low Effective # bits take part in the arithmetic. (This spacing is the subject of the core’s own revision note, “Corrected TM spacing” — earlier revisions packed the lanes at the effective width instead.)

One control for all lanes

INVERT is a single bit shared by every lane, and it is a scalar pin, not a TM pin: there is no way to invert some lanes and not others. That is almost always what you want, because the lanes of a TM bus are consecutive samples of one detector channel, not different channels.

Pin Description

a Input InputSize bit TM
Input TM bus (IN on the canvas). Input bits per lane × Time Mux lanes, lane $i$ at bits $[(i+1)\cdot\text{Input bits}-1 : i\cdot\text{Input bits}]$. Only the low Effective # bits of each lane take part in the arithmetic; the rest are discarded.
Default: Must be connected
pol Input 1 bit BIT

Invert control (INVERT on the canvas), a single scalar bit shared by every lane — this pin is not time-multiplexed.

  • 0 → every lane passes through (truncated to Effective # bits)
  • 1 → every lane is inverted, per Input sign

It has no default: drive it from a register or a constant.

b Output InputSize bit TM
Output TM bus (OUT on the canvas), same width, same lane pitch and same TM factor as IN. Valid in the same clock period — no pipeline register. In SIGNED mode the per-lane result is sign-extended to the lane pitch.

Properties

Property window

Input bits InputSize

Set the number of bits of the input

Width in bits of one lane of IN and OUT; the total bus width is Input bits × Time Mux. It is also the lane pitch used to slice the bus, so it must match the pitch of whatever produces the TM stream.

Range: 2 to 2048. Changing it rebuilds the symbol.

Default: 16

Default: 16

Range: 2 – 2048

Effective # bits EffSize

Set the effective number of significative bits in the data. For example for 14 bit ADC board set this number to 14

Effective # bits — the significant bits inside each lane, and the width the inversion is computed in. Set it to the real ADC resolution so the UNSIGNED reflection mirrors about the right full-scale value.

Must be ≤ Input bits (the core slices a_slice(EffSize-1 downto 0); a larger value will not elaborate). Bits above it are discarded in every lane.

Range: 2 to 2048.

Default: 16

Default: 16

Range: 2 – 2048

Input sign InputSign

Select the sign/unsign of the input

How each lane is interpreted, and therefore what “invert” means.

value inversion overflow behaviour widening to lane pitch
UNSIGNED $y = (2^{N_{\rm eff}}-1) - x$, i.e. bitwise NOT cannot overflow zero extension
SIGNED $y = -x$ in two’s complement $-2^{N_{\rm eff}-1}$ wraps onto itself sign extension

Fixed at synthesis; only INVERT is switchable at runtime.

Default: UNSIGNED

Default: UNSIGNED

Options: UNSIGNED SIGNED

Time Mux TimeMultiplexing

Set number of samples for each clock cycle

Time Mux — the number of lanes carried per clock, i.e. how many inverter instances are built and how wide IN / OUT are. It must match the TM factor of the nets you connect.

Allowed: 2, 4, 8, 16, 32. Logic cost and total bus width scale linearly with it.

Default: 4

Default: 4

Options: 2 4 8 16 32

⚙️ Detailed Operation

Datapath

Resources/Code/polinvert_tm.vhd is a for … generate over TMFactor, with one of two bodies selected at elaboration by the SIGN generic. Per lane:

  a[(i+1)*A_SIZE-1 : i*A_SIZE] ──► slice to AN_SIZE bits ──► invert ──► resize to A_SIZE ──► b[...]
                                                              ▲
                                                   INVERT ─────┘ (shared)
  

with A_SIZE = Input bits, AN_SIZE = Effective # bits, SIGN = Input sign, TMFactor = Time Mux. There is no interaction of any kind between lanes and no sequential element anywhere in the file: the whole block is combinational.

  • INVERT = 1, UNSIGNED → A_MAX_UNSIGNED - a_slice, where A_MAX_UNSIGNED is AN_SIZE ones. Subtracting from all-ones never borrows, so this is the bitwise NOT of the lane.
  • INVERT = 1, SIGNED → 0 - a_slice in AN_SIZE-bit signed arithmetic.

The one thing people get wrong: the most negative value

As in the scalar block, the SIGNED negation is modulo $2^{N_{\rm eff}}$ and is never clamped. The file declares A_MAX_SIGNED and A_MIN_SIGNED constants but never reads them; there is no saturation logic.

$$ -2^{N_{\rm eff}-1} ;\longmapsto; 0 - \left(-2^{N_{\rm eff}-1}\right) \equiv -2^{N_{\rm eff}-1} $$

With Effective # bits = 16, a lane holding 0x8000 (−32768) comes out holding 0x8000 — that lane is not inverted while all the others are.

Difference from the scalar block: sign extension

When Effective # bits is smaller than Input bits, the result has to be widened back to the lane pitch. This block does it correctly for both modes: the unsigned branch uses resize(unsigned(...), A_SIZE) and the signed branch uses resize(signed(...), A_SIZE), so a negative result is sign-extended into the unused top bits of its lane.

The scalar Polarity Invert zero-extends in both modes, which is wrong for SIGNED with Effective # bits < Input bits. If you are moving a design between the scalar and TM versions with that combination of settings, the two will not produce the same numbers — the TM one is the one to trust.

Effective # bits truncates

Each lane is sliced to its low AN_SIZE bits before anything happens, so bits above Effective # bits are discarded even when INVERT = 0. Set Effective # bits to the real ADC resolution (14 for a 14-bit ADC carried in a 16-bit lane) so that the UNSIGNED reflection mirrors about $2^{14}-1$ rather than about $2^{16}-1$. Effective # bits must be ≤ Input bits: a larger value produces an out-of-range slice and the design will not elaborate.

Configuration

Input bits, Effective # bits, Input sign and Time Mux all become VHDL generics and are fixed at synthesis. Only INVERT is live. Drive it from a Register block to make the polarity software-selectable:

  TM ADC bus ─────────► IN  ┌──────────────────┐
                          │ Polarity Invert  │──► OUT ──► TM shaper / TM trigger
Register (1 bit) ──► INVERT      (TM)        │
                          └──────────────────┘
  

The TM factor of IN and OUT is whatever Time Mux says, and the Sci-Compiler editor will refuse to connect them to TM nets of a different factor.

Timing and cost

quantity value
latency 0 clocks (combinational)
throughput TM Factor samples per clock
clock / reset none — no sequential elements
logic cost TM Factor independent Effective # bits-wide subtract/mux pairs

Cost grows linearly with Time Mux: 32 lanes of a 16-bit inverter is 32 copies of the scalar logic. In UNSIGNED mode each copy reduces to a row of XOR gates against the shared INVERT bit, which is very cheap; the SIGNED path needs a real subtractor per lane and is where a wide, high-factor instance starts to cost carry chains — and, being combinational, it lands entirely inside the timing path of the surrounding registers.

Resources & Timing

  • Latency: 0 clocks — purely combinational, no clock or reset pin

  • Throughput: TM Factor samples per clock

  • One Effective # bits-wide subtractor and multiplexer per lane; in UNSIGNED mode each degenerates to a row of XOR gates.
  • No memory-mapped registers are generated.
  • The SIGNED path here sign-extends to the lane pitch, whereas the scalar Polarity Invert zero-extends; the two agree only when Effective # bits = Input bits.