Loops
Kathryn’s loop HDBs re-launch their body until an exit condition is met. Every iteration is real hardware: the loop variable is a register or counter in your design, and each iteration takes clock cycles.
The while family
Section titled “The while family”Three related blocks share a while-style body, distinguished by when the condition is checked:
#define cwhile(expr) for(auto kathrynBlock = new FlowBlockWhile(expr, CWHILE); kathrynBlock->doPrePostFunction(); kathrynBlock->step())#define swhile(expr) for(auto kathrynBlock = new FlowBlockWhile(expr, SWHILE); kathrynBlock->doPrePostFunction(); kathrynBlock->step())#define cdowhile(expr) for(auto kathrynBlock = new FlowBlockDowhile(expr, DOWHILE); kathrynBlock->doPrePostFunction(); kathrynBlock->step())cwhile(cond)— c for combinational: checkscondcombinationally before each iteration (its condition node is aPseudoNode), so the check costs no cycle — each iteration costs only the body.swhile(cond)— s for state: the check happens from a clockedStateNode, spending one extra cycle per iteration but seeing the settled value.cdowhile(cond)— runs the body first, then checkscondcombinationally after each iteration, so the body always runs at least once and the check costs no cycle.
flowchart TB
subgraph CW["cwhile - combinational check, no extra cycle"]
CC{"condition"} -->|"true"| CB["body runs<br/>(its own cycle cost)"]
CB --> CC
CC -->|"false"| CX["loop exits"]
end
subgraph SW["swhile - state check, one extra cycle per iteration"]
SS["check state<br/>(one cycle)"] --> SC{"condition"}
SC -->|"true"| SB["body runs<br/>(its own cycle cost)"]
SB --> SS
SC -->|"false"| SX["loop exits"]
end
subgraph DW["cdowhile - body first, check after"]
DB["body runs<br/>(at least once)"] --> DC{"condition"}
DC -->|"true"| DB
DC -->|"false"| DX["loop exits"]
end
Over LC iterations of a body that costs two sequential cycles,
cwhile/cdowhile spend 2*LC cycles but swhile spends 3*LC — the
state check adds its cycle every time around.
A cdowhile, from the repository Readme.md:
seq{ a <<= i; par{ cdowhile(a < 8){ a <<= a + 1; c <<= c + 1; } cdowhile(b < 8){ b <<= b + 1; d <<= d + 1; } } d <<= c + d;}cloop — fixed-count loop with a loop variable
Section titled “cloop — fixed-count loop with a loop variable”cloop runs its body a fixed number of times using a generated hardware
counter, and exposes the count as a readable loop variable. Its macro takes
two arguments — the loop-variable name and the count:
#define cloop(kathrynLoopName, loopNumber) \ for(auto kathrynBlock = new FlowBlockLoop(loopNumber); ...) \ for (Operable& kathrynLoopName = kathrynBlock->getLoopId(); ...)From autoSim simAutoTest71, where bid is the loop variable:
seq{ cloop(bid, 10){ syWait(_cyclesPerBit - 1); zif (bid != 9){ shiftReg <<= g(one, (shiftReg)(1, 10)); } }}Exiting with sbreak
Section titled “Exiting with sbreak”To leave a loop from inside its body, use sbreak — the HDB-aware break. A
native C++ break does not describe hardware control flow and must not be
used inside an HDB body.
#define sbreak for(auto kathrynBlock = new FlowBlockSCBreak(); kathrynBlock->doPrePostFunction(); kathrynBlock->step()){}From autoSim simAutoTest19, sbreak fires from inside a cif when a count is
reached:
cwhile(a <= 48) { seq{ b <<= 5; a <<= a + 1; cif(a == 16) { par{ sbreak; seq{ b <<= 15; } } } }}Choosing a loop
Section titled “Choosing a loop”- Fixed, build-time count with an index you want to read →
cloop(name, n). - Data-dependent count, speed matters →
cwhile. - Data-dependent count, exit must see the settled value →
swhile. - Body must run at least once →
cdowhile.
Loop bodies nest freely with par,
conditionals,
waits, and further loops.