One topic per concept, word for word as wtf explains it: :help <topic> shows one in the window, and an agent reads it with the help tool. The tour and the recipes show them at work.

names

Naming signals: paths, bits, slices, VHDL forms, scope, streams.

A signal is named by its full path (top.dut.s_axi_awaddr) or by the end of a path if only one signal ends that way (s_axi_awaddr); an ambiguous name is an error listing the candidates.

  • One bit: data[3]. A slice tdata[63:32] and a concatenation {a, b} are signals too, as is a name made with command signal op = cmd[7:0].
  • VHDL or Verilog forms both: any case, gen(4).x or gen[4].x, data(7 downto 4) or data[7:4].
  • A scope (command scope top.dut, or workspace scope) makes names resolve under it first in every tool: s_axi_awvalid is top.dut.s_axi_awvalid. scope with no path: none.
  • A radix goes with a name wherever tools take signals: awaddr:dec (help radix).
  • A decoded stream is a signal (bus.wr, its value the record's number #n), and so is each of its fields (bus.wr.addr, z between records), for find, values and rows alike.
  • A struct, record or array, or part of one (pkt, pkts[1], grid[1]), is a signal of its whole value: its fields joined, the first the most significant (pkt == 0x5A5, pkt[10]); with a text field (an nvc enum) text, '{valid:1, state:busy, pair:'{hi:A, lo:5}}. value_at adds a line per field; signals lists it as one line, its fields with pkt.**.

times

Time units, the workspace's unit and rounding.

Times take units: 120ns, 1.5us, 2595ps; a plain number is file ticks.

  • Answers use one unit per workspace, so they compare across calls: once a search names a clock (@clk, also in a protocol or a decode), the unit is the largest that keeps that clock's shortest phase at 1 or more (ns for a 10 ns or a 200 MHz clock). command unit ns sets it, unit auto goes back to the clocks'. A call's unit argument overrides it for that call.
  • Times are rounded to a thousandth of the unit (2595ns for 2595.000001ns); unit: "fs" gives them exactly. A time given back stands for every tick that rounds to it: value_at reads after them all (as find show and records sample), and says a change among them (data = 0x5 (0x4 earlier in 2595ns)); from / to take them all, and find from a match starts after it.
  • Durations a decoder works out (a pair's delay) are times: shown in the unit, and compared with a time in where (delay > 40ns).

radix

Radixes and colours of values and rows.

Radixes: hex, bin, dec, sdec (signed), oct, ascii, float, fixed point like q4.12, and enum (the names the file gives values, as state READ). The default is enum where the file names values, otherwise hex; 1-bit signals always show 0 / 1 / X / Z.

  • A call's radix sets it for all its signals; data:dec for one signal.
  • Rows (help workspace) take a radix and a colour: awaddr:dec, wvalid:red, awaddr:hex:red. Colours: red orange yellow green cyan blue magenta gray (off removes it).

expressions

Search expressions for find: operators, arithmetic, values, @clk, past / rose / fell / stable.

valid && ready && data == 0x40, state == 3 || state == 5, !rst.

  • Operators: == != < <= > >= (unsigned numbers), &&, ||, !, ?: and parentheses. A bare signal is true when 1 (some bit 1, none unknown). * / % bind tighter than + -; ?: is lowest.
  • Arithmetic, written as in SystemVerilog but stricter: + - * / % & | ^ ~ << >> and signed(x). Values are exact integers: nothing wraps unless sliced, so a 32-bit add is (a + b)[31:0]; signed(x) reads x as two's complement (signed(imm[11:0]) < 0), and signed(x)[31:0] is its sign extension to 32 bits. / truncates toward zero, % takes the dividend's sign; dividing by zero is x.
  • Ternary c ? a : b is a value; a nested one needs parentheses: rd != (a < b ? 1 : 0). An unknown bit in c makes the result x.
  • &, |, ^ need parentheses beside another operator, << and >> beside arithmetic: (x & 3) == 0, wmask != 1 << addr[1:0]. A comparison or !x is a value, 1 or 0. A field's bits are b[4:0], as a signal's, on either side of a comparison. An unknown operand makes the result x. Operands up to 64 bits; an error shows each fix.
  • Values: 0x40, 64, 0b1000000, -12, SV numbers (8'h40, 'd64, 4'b10x0, '1), x (unknown), z (high impedance), a name the file gives a value, a time (40ns), or another signal (mi_addr != reg_waddr, data != past(data)). Two events at different times (a request and its response) are compared as records instead: a stream of each, matched with pair (help decode), their fields in records where.
  • Without a clock, a match is where the expression becomes true, so back-to-back handshakes are one match: use @clk to see each cycle.
  • @clk first (a clock signal): a match is each clock cycle whose ending rising edge samples the expression true, as a flip-flop does, reported at the cycle's starting edge. Consecutive matching cycles are one row (from, last, cycles).
  • Over time: past(x) is x one cycle earlier (without a clock, one tick); rose(x), fell(x) and stable(x) compare x with it. So a protocol check is a search for its violations: @clk fell(valid) && !past(ready).
  • find show lists signals' values on each match, so @clk awvalid && awready with show ["awaddr", "wdata"] is a table of the writes, a row per cycle; count_only counts them.

decode

Decoding interfaces into records: built-in protocols, protocol, frame, pair, check.

Decode first: records are exact and their handshake checks built in. open and info list the interfaces a built-in protocol decodes, each with its line; command runs it:

decode bus axilite clock=aclk prefix=s_axi_

The answer lists the streams made (bus.wr, bus.rd, ...) with their counts, and the violations (bus.errors, bus.wr.unmatched). protocols lists the protocols, protocols <name> each one's roles, params, streams and fields.

  • decode <name> <protocol> clock=<clk> <role>=<signal>... <param>=<value>...: built in axis, axilite, axi4, and without a clock spi (mode=0) and uart (baud=115200). prefix=s_axi_ plays each role not given by <prefix><role>. A value runs to the next key=, so it can have spaces; in quotes it runs to the closing one (when="x=1").
  • An interface of the design's own: protocol <name> roles=<a,b> when=<expr> <field>=<expr>... defines a protocol on its roles, no signals: a record per clock cycle where when holds (help expressions), the fields sampled with it. decode <name> <protocol> clock=<clk> <role>=<signal>... puts it on signals, as a built-in: protocol hs roles=valid,ready,data when=valid && ready d=data then decode rx hs clock=clk valid=rx_valid ready=rx_ready data=rx_data. A field is any expression of roles without past: next=pc + 4, imm=signed(insn[31:20]) (a field that can be negative is signed, shown in decimal); later fields and when can name it (f3=insn[14:12] ok=f3 == 0).
  • On streams: decode f frame input=rx.beat last=tlast groups records into frames; decode m pair request=axi.wr response=mi matches requests with responses (by order, or id= / req_id= and resp_id=), each record both sides with its delay; decode c check clock=clk dropped=fell(valid) && !past(ready) is a violation record, field rule, per cycle where a rule holds.
  • signal <name> = <expr> names a computed signal (help names). Decoding doesn't touch the rows. Read a stream with records (help records).

records

Reading streams: where, n, field comparisons, group_by, count_only.

records lists a stream as a table: n (the record's number), start, end and a field per column, headed 20 of 157. stream may name a set: a decode (bus: its results and violations, not the streams they are made from), a glob (bus.*) or several (bus.wr bus.rd); their records come in order of start with a stream column, fields of the same name and kind sharing a column, empty where a stream has none. start is the rising edge that starts the record's first clock cycle, as find @clk reports a match; end is the edge that samples its last. With more than one record long values are shortened (a frame's data to 8 bytes and its size); count: 1 with from shows one whole.

  • from / to pick records by their start; count how many (default 20).
  • where keeps the records a search expression over the fields holds for, the fields named bare and evaluated on each record: addr != 0x1C && resp != 0, rule == dropped, delay > 40ns. past(x) is x of the record before; n is the record's number (n == 138, a testbench's packet #138); a field compares with another field (req_addr != resp_addr, a pair's two sides, as a scoreboard checks them). On a set it keeps the streams having every field it names.
  • group_by names fields and answers a line per distinct value, with how many records have it and the first and last start: 128 × addr=0x1C data=0x3 (2.975us .. 69.015us).
  • Fields show in hex; radix gives another for every number field (dec) or for one (len:dec, several with commas). Times stay in the unit.
  • count_only only counts, with the first and last start.

workspace

Showing evidence: the workspace declaration, view, render, present.

To show the user evidence, declare the workspace, check it with view / render, then present it into the user's wtf windows on the trace (they can undo with u). With none open, present writes a session file that wtf <trace> shows when the user opens the trace: tell them so. The user also sees each query and change you make as a step (:trail), with its time, so ask what you mean to show. workspace replaces everything at once, as one undo step:

  • rows, top to bottom: "name", "name:radix", "name:radix:colour" (help radix), or a group {"group": "write", "rows": ["awaddr", "awvalid"], "collapsed": false}. Groups hold signals only. A struct or array is one row ("pkts"); {"signal": "pkts", "open": ["pkts", "pkts[1]"]} opens levels of it, each named from the row's name; "fields": ["pkts[1].pair.hi:dec:red"] gives lines under a row a radix and colour of their own.
  • cursors by number, {"1": "80ns", "2": "390ns"}: 1 is the cursor, where values are read; 2 - 9 are marks on the events to show. The user jumps to a mark with 'N. Say what a mark shows with {"time": "390ns", "name": "first bad write", "note": "AW before W, so the address latched is stale"}: the name stands on the ruler, the note on the user's status line when they jump there.
  • range: the visible range, ["60ns", "480ns"]; default the whole trace.
  • scope (help names); signals: computed signals, ["op = cmd[7:0]"].
  • protocols: {name, roles, when, fields: ["op = data[7:0]"]}, as protocol defines them; decode: {name, protocol, clock, signals: ["tvalid = rx_tvalid"], params: ["prefix = rx_"]}, as decode does (help decode). Streams can then be rows. Every name, radix and time is checked first and all the errors come back at once. command edits the workspace step by step instead (help commands).

commands

The : commands command runs.

command runs one of wtf's : commands, without the colon, on the workspace.

  • Rows: add <path|pattern>... (below the selected row, joining its group; a scope becomes a group of its direct signals, a struct or array one row), rm <path|pattern>... (rm ** clears), select <row> [<last row>] (the rows the next commands act on), group <name>, rename <name>, ungroup, radix <radix>, color <colour|off> (help radix), names <signal> <value>=<name>... (names for its values, as an FST enum table gives them; off removes them), undo, redo. The answer lists the rows added and removed.
  • Cursors and view: cursor <1-9> [time|off] [name=<text>] [note=<text>] (without a time or keys, jump to that mark; name= / note= say what a mark shows), <time> (moves the cursor), zoom <time per column>, fit [<from> <to>] (all, or between cursors '2 '3 or times).
  • Names and times: scope <path> (help names), unit <ns|ps|...|auto> (help times).
  • Decoding: decode, protocol, signal (help decode).