SimdScope

Links:

TODO

SimdScope is the user-facing "front" behind which SimdSignal is entirely and transparently hidden. Aside from using it, the goal and its purpose is that developers should under no circumstances have to know that their HDL, which was initially written as scalar nmigen HDL, is behaving entirely transparently as full SIMD capable HDL. There are a few caveats to that: some capabilities such as LHS assignment to an ast.Part are so complex in a SIMD context that SimdSignal in its first version does not implement it. Array is out at the moment as well. Over time this may change.

SimdScope is used as follows:

m = Module()
elwid = Signal(2)
vec_el_counts = { 0b00: 1, 0b01: 2, 0b10: 4, 0b11: 8}
with SimdScope(m, elwid, vec_el_counts, scalar=pspec.scalar) as s:
    a = s.Signal(64)
    b = s.Signal(32)

with m.If(a > 2):
    m.d.comb += b.eq(a[:32])

Note that the scalar parameter is selected from a runtime/compiletime configuration parameter which can alter the context between scalar and SIMD.

When set to scalar, SimdScope.Signal simply re-routes directly to nmigen.ast.Signal and in this way sets the mandatory expectation that under no circumstances shall SimdScope or SimdSignal alter the fundamental language behavioural characteristics of Type 1 (AST) or Type 2 (dsl.Module)

Note that under some circumstances, particularly temporary intermediate results, it may be necessary to introduce explicit SimdShape instances containing elwid-specific element widths. Relevant examples here include exponent and mantissa for IEEE754FP

m = Module()
elwid = Signal(2)
vec_el_counts = { 0b00: 1, 0b01: 2, 0b10: 4, 0b11: 4}
with SimdScope(m, elwid, vec_el_counts, scalar=pspec.scalar) as s:
    expshape = SimdShape(part_shape={0b00: 11, # FP64
                                     0b01: 8,  # FP32
                                     0b10: 5,  # FP16
                                     0b01: 8}  # BF16
    exp = s.Signal(expshape)

Here, because SimdShape derives from Shape, things still work because SimdShape works out that its maximum scalar size is 11, and sets Shape.width to 11 when SimdScope is set in scalar mode. When scalar=False, full SIMD is activated and the resultant HDL combines vec_el_counts with expshape as part of an ALU with inputs that can be 1xFP64, 2xFP32, 4xFP16, 4xBF16, where the exponents are 1x11, 2x8, 4x5, 4x8 respectively.

Behind the scenes, when calling SimdShape.Signal in SIMD mode, the elwid and vec_el_counts parameters from the context are combined with the SimdShape passed in to SimdScope.Signsl, as inputs to create a layout() that is "Element-width aware" (ElwidPartType). With the full information being passed in to SimdSignals, the actual use of the SimdSignals need not be inside the Context Manager.