Skip to content

Examples Gallery

Kathryn ships 39 worked examples under test/model/, named tc1tc40 (the numbering has one gap — there is currently no tc36). Every file is self-contained: it describes the model, provides a build() function that emits Verilog, and carries its own cocotb simulation that asserts the intended behaviour end-to-end through a real simulator. They are the ground truth for how each feature behaves — when a tutorial page and your intuition disagree, run the example.

Each entry links to the tutorial page that covers its feature.

#ExampleWhat it showsTutorial
1tc1_seq_simpleA single sequential block: x <= simple_val, then y <= x.Seq & Par
2tc2_parParallel auto-sync: x and y assigned in two branches, both settle the same cycle.Seq & Par
15tc15_reset_defaultReg reset values and wire defaults, fed as direct int literals (one wider than 64 bits).Reset & Defaults
26tc26_int_operand_autowrapInt literals as operands/sources auto-wrap into width-matched vals; every overloaded operator exercised.Expressions
27tc27_asm_resizeAssignment-source auto-resize: narrower sources zero-extend, wider sources drop MSBs (with warnings).Conversion & Resize
37tc37_mem_blkmem_blk + mem_ele: gated clocked write port, same-cycle combinational read, and hierarchical preload of the memory array from the testbench.Signals
#ExampleWhat it showsTutorial
3tc3_sifSequential if: x <= 42 only when cond_in is high (condition sampled sequentially).Conditionals
4tc4_cifCombinational if: same as tc3 but the condition costs zero extra cycles, so x latches earlier.Conditionals
5tc5_zifZero-cycle if: wires driven combinationally; outputs reflect sources the very cycle conditions go high.Conditionals
6tc6_cloopCounter loop: two explicit resets then x incremented 4 times via cloop(3).Loops
7tc7_cwhileCombinational while: x incremented each iteration while x < 3, zero-cycle condition checks.Loops
8tc8_swhileSequential while: like tc7 but the condition costs one extra clock per iteration.Loops
9tc9_cdowhileDo-while: the body runs at least once, then repeats while x < 3.Loops
10tc10_zswitchZero-cycle switch: an out wire driven combinationally from sel across three cases.State Machines
11tc11_waitWait blocks: sywait (fixed cycles) and scwait (condition) delaying the next assignment.Waits
14tc14_zif_chain_same_regzif/zelif/zelse chain writing one reg three values — lowers to a single clocked priority mux.Conditionals
22tc22_pickPick block: a multi-way select that is NOT mutex-chained — every matching pif fires; pidef is the default.Pick
38tc38_forever_scwaitThe “processor loop” pattern: an endless cwhile handshaking with the outside world through scwait, plus always-on bare comb logic beside the loop.Waits
#ExampleWhat it showsTutorial
12tc12_par_same_priorityThree parallel writes to the same reg at the SAME priority: stable sort keeps program order, the last wins.Write Priority
13tc13_par_diff_prioritySame three writes at three DIFFERENT priorities: the highest-priority write wins even when declared first.Write Priority
#ExampleWhat it showsTutorial
16tc16_pip_zync_baseline3-stage pip/zync pipeline chained through shared arbiters, free-running with no stall, flush, or guard.Pip/Zync Basics
17tc17_pip_zync_cond_stallA stage-2 conditional one-shot stall: a cif guard fires sywait(5) once, stalling the pipe 5 cycles.Stalls & Bubbles
18tc18_pip_zync_stall_bubbleA one-cycle stall bubble: arb.stall() pulsed once punches a single bubble into the pipeline.Stalls & Bubbles
19tc19_pip_zync_flush_deadlockA one-shot arb.flush() holds the arbiter’s reset high, jamming the pipe permanently at (5, 4, 4).Flush & Hazards
20tc20_pip_zync_multi_assign_orderThe same register assigned twice in one clocked block — probes which write wins (last-write override).Multi-Assign Ordering
21tc21_pip_zync_multi_assign_prioritytc20’s double write wrapped in priority(...) — the higher-priority (first-declared) write wins instead.Multi-Assign Ordering
23tc23_zync_fanoutOne producer fires TWO consumer pipelines in lockstep via a multi-arb zync with mode="all".Fanout
24tc24_zync_parity_fanoutConditional fan-out: per-bind conditions route the producer to a different consumer by parity (mode="any").Fanout

The tc16 baseline: three stages chained through shared arbiters, free-running:

flowchart LR
    S1["stage 1"] --> A1["arbiter"]
    A1 --> S2["stage 2"]
    S2 --> A2["arbiter"]
    A2 --> S3["stage 3"]

And the tc23 fanout: one producer driving two consumer pipelines in lockstep via a multi-arb zync with mode="all":

flowchart LR
    P["producer"] --> Z["zync<br/>(mode=all)"]
    Z --> C1["consumer pipeline 1"]
    Z --> C2["consumer pipeline 2"]
#ExampleWhat it showsTutorial
25tc25_karray_regfileA 4-entry Karray as a tiny register file: field-wise writes and whole-element {field: source} writes.Conversion & Resize
28tc28_karray_to_karrayKarray-to-karray region copy: fields paired by name+width; non-matching fields skipped with a warning.Conversion & Resize
29tc29_karray_dynamic_indexDynamic element reads: binary addresses at all four indices, plus a one-hot oh(...) select.Indexing
30tc30_karray_reduceCallback-driven reduce: plain max, and a valid-gated max proving the callback consumes multiple fields.Reduce
31tc31_karray_reduce_advancedAdvanced reduce: nested per-dimension select fns, request_index winner coordinates, and carried extras.Reduce
32tc32_karray_dynamic_assignDynamic element writes: binary, one-hot, and whole-element map — each landing on exactly one element.Dynamic Writes
33tc33_karray_cus_dynamic_assigncus_dynamic_assign: custom write-enables built from view.coord, including a multi-element range write.Dynamic Writes

The tc25 register file: a 4-entry Karray (Hardware Aggregator, Table and Slot) addressed by index, each entry holding named fields:

flowchart TB
    K["Karray regfile<br/>(4 entries)"] --> E0["entry 0"]
    K --> E1["entry 1"]
    K --> E2["entry 2"]
    K --> E3["entry 3"]
    E0 --> F["fields<br/>(per-field or whole-element write)"]
#ExampleWhat it showsTutorial
34tc34_lib_bitsAll kathryn.lib bit helpers — zext, sext, cat, replicate, or_reduce/and_reduce, mux — driven and checked in the same cycle.Bit Utilities
35tc35_lib_bundle_handshakeBundle + Decoupled: consumer/producer IO marking, fire(), a connect_from relay chain, and backpressure.Bundles & Handshake
#ExampleWhat it showsTutorial
39tc39_hier_basicTop + one child: cross-module routing both ways, plus implicit clk/mrst forwarding into the child’s clocked flow.Modules
40tc40_hier_deep_siblingDeep hierarchy Top { ChildA { GrandChild }, ChildB }: 2-level input/output chains, sibling routing through the LCA, and IoWire reuse.Modules

Each file registers itself into a shared cocotb pool; cocotb_pool.run_all() drives every registered example (there is no per-test Makefile). Each build() follows the standard pipeline — reset(), construct the module, build_model(...), emit_verilog(...) — described in Building & Emitting, and the emitted Verilog for each example lands in test/.model_output/<tcname>/top.v.