Structural RTL fallback: z-blocks
The HDBs express a broad range of control flow,
but not everything expressible in Verilog. For the rest, Kathryn provides a
structural RTL (Verilog-style) fallback built from z-prefixed blocks.
These are zero-time, combinationally-resolved blocks: they describe the logic
that drives a resource within a single evaluation, and they integrate with the
higher-level HDBs so structural RTL and cycle-accurate control flow coexist in
one model.
zif / zelif / zelse
Section titled “zif / zelif / zelse”zif is the combinational conditional; zelif and zelse chain onto it (from
cond/zif.h and cond/zelif.h):
#define zif(expr) for(auto kathrynBlock = new FlowBlockZIF(expr); kathrynBlock->doPrePostFunction(); kathrynBlock->step())#define zelif(expr) for(auto kathrynBlock = new FlowBlockZELIF(expr); kathrynBlock->doPrePostFunction(); kathrynBlock->step())#define zelse for(auto kathrynBlock = new FlowBlockZELIF(); kathrynBlock->doPrePostFunction(); kathrynBlock->step())From autoSim simAutoTest11, zif/zelif/zelse nesting inside a cwhile:
cwhile(cond){ zif(a > b){ a <<= a + one; } zelif(a < b){ a <<= a + two; zif(a > b){ b <<= b - one; }zelse{ b <<= b - two; } }}ztate / zcase / zcasedef
Section titled “ztate / zcase / zcasedef”ztate(sel) is the structural selector — a Verilog case — with zcase(v)
branches and a zcasedef default (from state/ztate.h and state/zcase.h):
#define ztate(identState) for(auto kathrynBlock = new FlowBlockZtate(identState); kathrynBlock->doPrePostFunction(); kathrynBlock->step())#define zcase(caseValue) for(auto kathrynBlock = new FlowBlockZCase(caseValue); kathrynBlock->doPrePostFunction(); kathrynBlock->step())#define zcasedef for(auto kathrynBlock = new FlowBlockZCase(); kathrynBlock->doPrePostFunction(); kathrynBlock->step())From autoSim simAutoTest62, a ztate selecting on switchVal, with a nested
zif inside a case:
ztate(switchVal){ zcase(0b100){ a <<= 9; b <<= 24; zif(subCheck){ b <<= 48; } } zcase(0b001){ a <<= 10; b <<= 107; } zcasedef{ b <<= 404; }}flowchart TD
subgraph K["Kathryn z-blocks"]
ZIF["zif / zelif / zelse"]
ZT["ztate / zcase / zcasedef"]
end
subgraph V["generated Verilog"]
ALW["always block<br/>(single clock edge)"]
IFE["if / else if / else"]
CASE["case / default"]
end
ZIF --> IFE
ZT --> CASE
IFE --> ALW
CASE --> ALW
Intentional constraints
Section titled “Intentional constraints”The structural-RTL fallback is deliberately restricted. Three constraints favor modeling simplicity and simulation performance:
- A resource is sensitive to a single clock edge (registers, memory) or to all dependent sources (wires).
- Clock-edge-sensitive elements use non-blocking semantics.
- Advanced constructs — multiple clock domains, latches, and tri-state ports — are unsupported.
Use z-blocks when you need exact Verilog-style structure or zero cycle cost for a piece of combinational logic, and keep the cycle-accurate control flow in the HDBs around them.