Skip to content

seq and par

seq and par are the two composition HDBs. They differ only in when their contents run: seq runs its CCOs and sub-HDBs one after another; par runs them all at once.

Inside a seq block, every CCO and nested HDB executes sequentially — the second statement’s State Node depends on the first’s completion, and so on down the block. This is the default reading order you expect from top-to-bottom code, made cycle-accurate.

seq{ /// all sub element run [seq]uentialy
a <<= i;
par{ /// all sub element run parallelly
cdowhile(a < 8){ a <<= a + 1; c <<= c + 1; }
cdowhile(b < 8){ b <<= b + 1; d <<= d + 1; }
}
d <<= c + d;
}

Here a <<= i completes, then the par block runs, and only when the par finishes does d <<= c + d fire.

Inside par, all sub-blocks launch on the same cycle and run concurrently. Each of the two cdowhile loops above advances its own registers in lockstep, independently of the other.

flowchart TD
    START["par launch"] --> A["sub-block 1<br/>cdowhile a &lt; 8"]
    START --> B["sub-block 2<br/>cdowhile b &lt; 8"]
    A --> SY["Synchronize Node<br/>tracks completion"]
    B --> SY
    SY --> EXIT["par exits when both done"]

When a par’s sub-blocks all have a statically known cycle count, the block knows in advance when they all finish. But when a sub-block’s cycle usage cannot be statically determined — for example a data-dependent loop like the cdowhile above — par inserts a Synchronize Node. The Synchronize Node adds auxiliary hardware that tracks each sub-block’s completion and joins them without spending extra cycles, so the par exits in the exact cycle its slowest branch finishes.

The default par builds this join automatically:

#define par for(auto kathrynBlock = new FlowBlockParAuto(); kathrynBlock->doPrePostFunction(); kathrynBlock->step())
#define parMan for(auto kathrynBlock = new FlowBlockParNoSync(); kathrynBlock->doPrePostFunction(); kathrynBlock->step())

parMan — parallel without a synchronizer

Section titled “parMan — parallel without a synchronizer”

parMan (FlowBlockParNoSync) launches its sub-blocks in parallel exactly like par, but does not build a Synchronize Node. Use it when you will manage completion yourself — for instance when the surrounding structure already provides the join, or when the branches are known to finish together and the automatic synchronizer would be redundant hardware.

seq and par nest freely and mix with every other HDB. The example above puts a par inside a seq, and each par branch is itself a loop. Any block may contain conditionals, waits, or further seq/par composition.