The timing table sta.rbin (STA v1): read-only view and builder (crates/core/rusteda-workspace/src/sta.rs)¶
The static timing analysis tool of the suite commits its results as the workspace table sta.
The other tools read that table without depending on the timing engine: the synthesis tool
resolves path<N> handles to the cell instances of a ranked path, and the workbench lists
endpoints and paths. This specification describes the format as far as these readers need it,
the validation the shared reader performs, and a small builder of valid tables. The timing tool
owns the semantics of the values it writes (slack, arrival, required time); this module only
reads and writes them.
| Section | Requirements |
|---|---|
| Container and sections | WS-REQ-0126, WS-REQ-0127 |
| Validation | WS-REQ-0128, WS-REQ-0129 |
| Names | WS-REQ-0130 |
| Queries | WS-REQ-0131 to WS-REQ-0134 |
| Builder | WS-REQ-0135, WS-REQ-0136 |
Container and sections¶
WS-REQ-0126 The timing table is the table sta of a revision, the file sta.rbin: an rbin
container (WS-REQ-0030) of kind STA and format version 2 (the reader accepts 1..=2; a newer
version is SCHEMA_TOO_NEW, WS-REQ-0039) with exactly the 24 sections below, in id order, with
these element sizes (a version 1 table has the sizes in parentheses):
| Id | Section | Element bytes | Content |
|---|---|---|---|
| 1 | STR_BYTES |
1 | UTF-8 bytes of all strings |
| 2 | STR_OFFS |
4 | u32 offsets into STR_BYTES, one per string plus one; string 0 is empty |
| 3 | META |
64 | one record of counts and modes |
| 4 | CORNERS |
16 | one record per corner |
| 5 | CLOCKS |
48 | one record per clock |
| 6 | TAGS |
16 | one record per launch tag |
| 7 | DISABLED_ARCS |
16 | one record per disabled timing arc |
| 8 | NODE_REC |
152 | timing values per (corner, node), full mode only |
| 9 | TAG_EXTRA_PTR |
4 | row pointer per (corner, node) into TAG_EXTRA, full mode only |
| 10 | TAG_EXTRA |
56 | arrivals of further launch tags, full mode only |
| 11 | ENDPOINTS |
36 (32) | one record per checked endpoint |
| 12 | EP_SLACK |
16 | setup and hold slack per (corner, endpoint) |
| 13 | EP_ORDER |
4 | endpoint rows sorted by slack per (corner, setup or hold) |
| 14 | PATH_RANK |
12 (8) | one record per ranked path, in rank order |
| 15 | PATH_CHAIN_PTR |
8 (4) | u64 (u32) row pointer per ranked path into PATH_CHAIN |
| 16 | PATH_CHAIN |
4 | the steps of every ranked path |
| 17 | PATHS |
56 | the header of each materialized path |
| 18 | PATH_POINTS |
32 | the points of the materialized paths |
| 19 | NAME_HASH |
4 | open-addressed table of node names |
| 20 | INST_HASH |
4 | open-addressed table of instance names |
| 21 | SUMMARY |
80 | one record per (corner, path group) |
| 22 | UNCONSTRAINED |
12 | one record per unconstrained endpoint |
| 23 | NOTES |
16 | aggregated notes of the analysis |
| 24 | SCOPE |
1 | the scope of the analysis as a JSON object |
StaTable::open_rev(rev) maps the table through Revision::open_rbin, which validates the rbin
header and the upstream map of meta.json (WS-REQ-0037, WS-REQ-0038); a revision without the
table is MISSING_TABLE. StaTable::from_bytes opens table bytes in memory and
StaTable::from_rbin an rbin opened otherwise. Opening does not hash the content;
StaTable::verify_hash does (WS-REQ-0034), and a tool that derives a change of the design from
the table calls it before it uses the table.
WS-REQ-0127 Records are little-endian with these fields, in byte order (u32 unless
stated; NO_INDEX = 0xFFFF_FFFF marks an absent index; time in ns):
- META: num_nodes, num_port_bits, num_arcs, num_cells, num_startpoints,
num_disabled_arcs, num_corners, num_clocks, num_tags, num_endpoints,
num_ranked_paths, num_top_k_paths, num_path_groups, store_mode (0 full, 1 summary),
backend_str, precision (0 f64, 1 f32). Nodes are numbered with the port bits first
(0..num_port_bits), then the instance pins.
- CORNERS: name_str, lib_count, flags, reserved. CLOCKS: name_str, source_node,
master_clock, flags, then f64 period_ns, rise_edge_ns, fall_edge_ns, then f32
setup and hold uncertainty. TAGS: clock_id, u8 launch edge, u8 flags, u16 exception
state, launch_source_node, path_group_str.
- NODE_REC: [[f64; 2]; 2] transition, required time and slack, each indexed
[rise, fall][early, late]; u32 primary tag and the node's NAME_HASH bucket (or
NO_INDEX); [[f64; 2]; 2] arrival of the primary tag; [[u32; 2]; 2] predecessors. Row
corner * num_nodes + node.
- ENDPOINTS: data_node, clock_node, capture_clock, path_group_str, check arc,
kind_flags (bits 0 to 7: kind 0 flip-flop, 1 latch, 2 output port, 3 recovery/removal pin,
4 clock gate; bits 8 and 9: capture edge 0 rise, 1 fall, 2 none; bits 10 to 31 zero), the
rank of the endpoint's worst setup-family and hold-family ranked path (or NO_INDEX), and the
data node's NAME_HASH bucket plus one, or 0. EP_SLACK: f64 setup and hold slack, NaN when
absent, row corner * num_endpoints + endpoint. EP_ORDER: bucket
(corner * 2 + hold) * num_endpoints holds the endpoint rows by ascending slack.
- PATH_RANK: f32 slack, u32 endpoint row, u16 corner, u8 flags (bit 0: hold family,
bit 1: end transition fall, bits 2 and 3: check 0 setup, 1 hold, 2 recovery, 3 removal, bit 7:
materialized), u8 padding.
- PATH_CHAIN slice of a ranked path: required time and check value as f64 word pairs (low
word first), then per step three words: the node, the step word (bit 0 transition fall, bits 1
and 2 point kind 0 port, 1 net, 2 cell, 3 clock launch, bits 3 to 31 tag slot) and the node's
NAME_HASH bucket.
- Format version 1 differs in three records, which the reader converts to the version 2 values:
ENDPOINTS has no ninth word and keeps the NAME_HASH bucket plus one in bits 10 to 31 of
kind_flags; PATH_RANK is f32 slack, u16 bits 0 to 15 of the endpoint row, u8 corner
in bits 0 to 3 and bits 16 to 19 of the endpoint row in bits 4 to 7, u8 flags; a chain step
is two words, the step word (bits 0 to 23 node, bit 24 transition fall, bits 25 and 26 point
kind, bits 27 to 31 tag slot) and the node's NAME_HASH bucket, so a step names only the low
24 bits of its node, whose whole value the bucket holds.
- PATHS: f64 slack, arrival, required time and check value; rank, endpoint row, launch
clock, capture clock, first and end index into PATH_POINTS. PATH_POINTS: f64 arrival,
increment and transition time; node, u8 transition (0 rise, 1 fall), u8 point kind,
u16 padding.
- SUMMARY: f64 setup WNS, setup TNS, hold WNS, hold TNS; corner, group_str, setup
violating and setup endpoints, hold violating and hold endpoints, transition-limit and
capacitance-limit violations, total and unconstrained endpoints, two reserved words. A WNS
without endpoints is written as 0.
Validation¶
WS-REQ-0128 Opening a table validates its structure in time independent of the table size,
and fails with CORRUPT_TABLE unless: the kind is STA; the directory has exactly the 24
sections with ids 1 to 24 and the element sizes of WS-REQ-0126; the file ends at the end of the
last section rounded up to 8 bytes; META holds one record with store mode and precision 0 or
1, num_port_bits <= num_nodes and num_top_k_paths <= num_ranked_paths; STR_OFFS starts
at 0 and ends at the length of STR_BYTES; the counts of CORNERS, CLOCKS, TAGS,
DISABLED_ARCS, ENDPOINTS, PATH_RANK and PATHS equal those of META, EP_SLACK holds
num_corners * num_endpoints records, EP_ORDER twice as many and SUMMARY
num_corners * num_path_groups; PATH_CHAIN_PTR holds num_ranked_paths + 1 entries from 0
to the length of PATH_CHAIN; in the full mode NODE_REC holds num_corners * num_nodes
records and TAG_EXTRA_PTR one more entry from 0 to the length of TAG_EXTRA, in the summary
mode the three are empty; NAME_HASH and INST_HASH hold whole 4-word buckets, zero or a
power of two of them; SCOPE holds at least 2 bytes. Products of counts are computed without
overflow.
WS-REQ-0129 Every index read from the table is checked before it is used: string ids
(range, byte range, UTF-8), NAME_HASH buckets (range, occupied, node below num_nodes),
nodes of chain steps and points, corners and endpoint rows of rank records (the hold-family
bit agreeing with the check), endpoint kinds and capture edges, ranks named by endpoints,
EP_ORDER buckets (a permutation of the endpoint rows), the inner entries of PATH_CHAIN_PTR
(a slice of at least the four header words and whole steps), the rank, endpoint and point range
of a materialized path, the transition and kind of its points, and the corner of a summary
row. A failure is CORRUPT_TABLE. No input makes a query panic, and every allocation is
bounded by the lengths of the sections: a name found by node uses the bucket the table records
for it (in the record, the endpoint flags or the chain step) and otherwise one map of the
occupied NAME_HASH buckets.
Names¶
WS-REQ-0130 A NAME_HASH bucket holds four words: the low word of the xxh3-64 hash of the
node name (at least 1; 0 marks an empty bucket), the node, the prefix string and the leaf
string. A port bit (node below num_port_bits) has no prefix (NO_INDEX) and its name is the
leaf; an instance pin has the instance name as prefix and its name is prefix/leaf; any other
combination is CORRUPT_TABLE. A name is found by probing from bucket
(hash >> 32) & (buckets - 1) linearly until an empty bucket (StaTable::node_by_name). The
instance of a pin is its prefix string, never a part of the joined name, so instance names that
contain / are kept whole. An INST_HASH bucket holds the low hash word of the instance name,
the instance string, the cell string in bits 0 to 19 with the pin count (at most 4095) in bits
20 to 31, and the first pin node of the instance.
Queries¶
WS-REQ-0131 StaTable::summary returns every SUMMARY row and corner_summary(c) the
row at c * num_path_groups, which belongs to corner c and aggregates its endpoints (the path
group **), with corner and group names; a WNS is reported as absent, not 0, when its
endpoint count is 0. corner_names, clocks (name, period, setup uncertainty), counts,
store_mode and scope (the SCOPE JSON object; anything else is CORRUPT_TABLE) complete
the summary queries. A corner index outside the table is UNKNOWN_HANDLE.
WS-REQ-0132 StaTable::endpoints(c) returns the endpoints in ENDPOINTS order with the
name and instance of their data node, their kind, their setup and hold slack in corner c
(absent when NaN) and the rows of their worst setup-family and hold-family ranked paths;
endpoint(i, c) returns one of them (UNKNOWN_HANDLE outside the table) and
endpoint_order(c, hold) the EP_ORDER bucket of corner c.
WS-REQ-0133 Ranked paths are addressed by row: the handle path<N> is row N - 1 of
PATH_RANK (WS-REQ-0022), in the rank order the table records. StaTable::path_ranks returns
the rank records (check, corner, endpoint row, end transition, f32 slack) and
StaTable::path(row) the path with its points; a row outside the ranked paths is
UNKNOWN_HANDLE naming path<row + 1>.
WS-REQ-0134 The first num_top_k_paths ranked paths are materialized: PATHS[row] (whose
rank and endpoint must be those of the rank record) gives the exact f64 slack and its point
range gives the points with their arrival times; the chain of the same row, when it has steps,
has one step per point with the same node (in a version 1 table, the step's 24 bits are the low
bits of the point's node) and gives each point's name bucket (without steps the name is found by
node, WS-REQ-0129). A ranked path beyond those is read from its chain alone: its points have the
names of their buckets (whose node must agree with the step's node, or its 24 bits in version 1),
kinds and transitions but no
arrival times, and its slack is the f32 of the rank record (slack_exact false). Both hold in
the full and the summary mode.
StaTable::path_required(row) returns the required time and check value of the chain header.
RankedPath::instances lists the instances of the pins on the path, each once, in path order.
Builder¶
WS-REQ-0135 StaTableBuilder writes a valid STA v2 table from ports, instance pins (with
optional cell names), corners, clocks, endpoints with their per-corner slacks and ranked paths
with their points; it analyzes nothing, and every slack and arrival is the caller's. It numbers
the port bits first, then the pins instance by instance; writes string 0 empty and shares equal
strings; sizes NAME_HASH and INST_HASH to the next power of two of at least twice their
entries and 16 (0 buckets when empty); sorts endpoints by node; ranks paths setup family first,
then by slack, corner, endpoint row and end transition, ties in the order given; materializes
the first top_k ranked paths (default all); writes one path group **, one launch tag, no
disabled arcs, unconstrained endpoints or notes, a SCOPE with wire_model none,
clock_model ideal and backend builder, and in the full mode absent values in NODE_REC
except the arrivals of path points. A path that does not end at an endpoint, an unknown corner
or node, a non-finite time, no corner, more than 16 corners, 2^32 - 1 endpoints or nodes, more
than 4095 pins of one instance or a cell name past string 2^20 - 1 (the fields of INST_HASH)
is INTERNAL. StaTableBuilder::stage(txn, upstream) adds the table as
sta (sta.rbin) with upstream in its header (WS-REQ-0038) and sets the summary values
setup_wns_ns, setup_tns_ns, setup_violating_endpoints, hold_wns_ns, hold_tns_ns,
hold_violating_endpoints, the design-rule values of WS-REQ-0137, total_endpoints,
unconstrained_endpoints and corners, and the status timing (met or violated), of the
timing table; to_bytes(upstream) returns the bytes.
WS-REQ-0136 The builder is deterministic: equal inputs give byte-identical tables, -0.0 is
written as +0.0 and NaN as the quiet NaN 0x7ff8_0000_0000_0000, and every table it writes
passes the validation of WS-REQ-0128 and WS-REQ-0129 and reads back with the queries of
WS-REQ-0131 to WS-REQ-0134.
WS-REQ-0137 The builder checks no design rule: it sets the summary values
max_trans_violating and max_cap_violating to null and drv_status to "unchecked", never
to zero, and its SUMMARY rows hold no design-rule counts.