Ethernet · Module 22
TSN in a Vehicle Backbone
At 100 Mb/s the guard band is 121.5 µs and three hops miss a millisecond deadline on the bounded terms alone — and a node that loses PTP keeps passing every one of its own assertions.
Module 17 built time-aware shaping and preemption at 1 Gb/s and above. A vehicle runs them at 100 Mb/s. Every number changes and two of them change the design.
| 1 Gb/s (Module 17) | 100 Mb/s (a vehicle) | |
|---|---|---|
| bounded latency per hop, MTU worst case | 36.70 µs | 366.03 µs |
| three hops | 110.1 µs | 1 098.1 µs |
| guard band, no preemption | 12.192 µs | 121.488 µs |
| shortest cycle that delivers any bandwidth | 61.0 µs | 607.4 µs |
| guard band with preemption | 0.560 µs | 5.168 µs |
| shortest cycle with preemption | 2.8 µs | 25.8 µs |
Row two is the chapter's first result and it is a failure. Chapter 17.1 §4 computed 37.12 µs of bounded latency per hop at 1 Gb/s and observed that five hops is 185.6 µs against a 1 ms deadline, with room to spare. At 100 Mb/s over a three-hop vehicle backbone the bounded terms alone come to 1 098 µs — the deadline is missed before any interference or queueing is considered at all.
Row four is the second result. A 121.488 µs guard band is subtracted from every window in every cycle, so a schedule whose window is shorter than that delivers nothing. At 100 Mb/s with a 20% window, any cycle below 607 µs gives the scheduled class zero bandwidth — which rules out the fast control loops that were the reason for scheduling in the first place.
Rows five and six are the fix, and it is the same fix Module 17 found for a different reason.
| Value | |
|---|---|
| express 64-octet frame, per hop at 100 Mb/s, no preemption | 133.39 µs |
| the same with preemption | 17.07 µs |
| three hops | 400.2 µs → 51.2 µs |
| improvement | 7.8× |
Chapter 17.3 presented preemption as a way to recover bandwidth a guard band was eating. At automotive rates it is the mechanism that makes the deadline reachable at all, and Section 10 argues it should be treated as mandatory rather than as an option.
And one number that has nothing to do with bandwidth.
Two free-running clocks 200 ppm apart consume a 5.168 µs guard band in 25.8 milliseconds, a 100 µs window in half a second, and a whole 1 ms cycle in five seconds.
That is what losing Chapter 16.2 costs a schedule, and Section 12 shows the failure has a property nothing else in this track has: every local assertion about the schedule keeps passing while it happens.
1. Scope — Module 17's Mechanisms, on a 100 Mb/s Link and a Three-Hop Topology
Scope: what changes when Module 17's time-aware shaping and frame preemption are deployed on a vehicle's links and topology, and what to do about it.
Not in scope: how any of it works. Chapter 17.1 derived the seven latency terms and which two are unbounded; Chapter 17.2 built the gate-control list, the cycle timer, the guard band and the atomic installation; Chapter 17.3 built the two MACs, the SMD codes, the mCRC and the reassembly machine. None of it is re-taught. This chapter changes two parameters — the line rate and the topology — and follows the consequences.
The two parameters, stated precisely.
| Module 17's assumption | A vehicle | |
|---|---|---|
| line rate | 1 to 100 Gb/s | 100 Mb/s and 1 Gb/s |
| segment length | 100 m | 15 m |
| hops | five | three |
| deadline | 1 ms, illustrative | 1 ms, and it is a safety requirement |
| the clock | Chapter 16.2, assumed present | the same, and it can be lost |
Rows one and three pull in opposite directions and row one wins by a wide margin. The vehicle's topology is shallower — three hops against five — which helps by a factor of 1.67. The line rate is ten times lower, which hurts by a factor of nearly ten. The net is a factor of six against, and Section 6 is the arithmetic.
Row two barely matters and is worth dismissing explicitly. Chapter 17.1 §4 priced propagation over 100 m at 0.50 µs; over an automotive 15 m segment at 0.66c it is 0.0758 µs. Both are negligible against a 121 µs serialisation term, so shortening the cable — which Chapter 22.1 showed does a great deal for the physical layer — does almost nothing for latency.
Row four is the one that changes the engineering stance. In a data centre a missed deadline is a retransmission, a stutter, or a tail-latency complaint. In a vehicle a missed deadline on a brake-by-wire or steering command is a safety event, which means the schedule is not a performance optimisation — it is a mechanism that has to be argued to be correct, including under fault. Sections 12 and 14 are that argument.
And one thing this chapter adds that Module 17 did not need.
What the schedule does when the clock goes away, and how anyone finds out.
A data centre's TSN deployment loses PTP and somebody's dashboard goes red within a minute. A vehicle's loses PTP on a cold morning, and the only consequence anyone observes is that a control loop started missing its deadline — with every gate still opening and closing exactly as programmed, on a timer that is internally perfect and globally wrong.
2. The Vehicle Backbone, and Why It Is Only Three Hops Deep
Derive the topology before applying any mechanism to it, because the hop count is half of every latency number in the chapter.
A zone architecture, which is the arrangement most current vehicle networks converge on.
| Element | Count | Link rate |
|---|---|---|
| sensors and actuators | tens to hundreds | 100 Mb/s single pair |
| zone controllers | 4 — one per quadrant | 100 Mb/s down, 1 Gb/s up |
| central compute / gateway | 1 or 2 | 1 Gb/s, sometimes 2.5 or 10 |
| maximum switch hops, edge to edge | 3 | — |
The three hops are: zone controller, backbone switch, zone controller. A sensor on the front-left quadrant sending to an actuator on the rear-right traverses its own zone's switch, the central one, and the destination zone's switch — three switching elements, and there is no arrangement in a vehicle that needs more, because the physical extent is under five metres and the number of zones is four.
That is a genuinely favourable difference from a data centre and it is worth stating why it exists. Chapter 23.1's fabric is deep because it must scale to thousands of endpoints with uniform bandwidth between any pair. A vehicle has a fixed, small, known set of endpoints and a traffic matrix that is decided years before the vehicle is built — so the topology can be shallow, asymmetric, and specialised, and nothing is lost.
The traffic, which is the other half of the problem.
| Class | Period or rate | Frame size | Deadline |
|---|---|---|---|
| control — chassis, powertrain | 1 to 10 ms | small, often under 100 octets | hard, one period |
| sensor — camera | 30 to 60 frames/s | large, bursty, megabytes per frame | soft, tens of ms |
| sensor — radar, lidar | 10 to 50 Hz | medium, steady | firm |
| diagnostics and software update | whenever | large | none |
| audio and infotainment | continuous | small, isochronous | firm, low jitter |
Rows one and two sharing a link is the entire problem. A camera frame is megabytes; at 100 Mb/s a single megabyte takes 80 milliseconds to serialise, and the control frame behind it has a one-millisecond deadline. Chapter 17.1 §11 identified interference and queueing as the two unbounded terms; this is what they look like in a vehicle, and the shape is far worse than a data centre's because the size ratio between the two classes is four orders of magnitude.
Which gives the chapter's framing in one table.
| Data centre | Vehicle | |
|---|---|---|
| what is scheduled | a minority class, for tail latency | the class the vehicle steers with |
| what it shares the link with | other network traffic | a camera stream 4 000× its size |
| link rate | 10 to 400 Gb/s | 100 Mb/s to 1 Gb/s |
| consequence of a miss | a retry | a safety event |
| who notices | a monitoring system | nobody, until it matters |
Every column moves in the same direction, which is unusual and is why the automotive case needs its own chapter rather than a paragraph.
3. RTL 1 — The Vehicle Schedule Package and the Zone Topology
// ---------------------------------------------------------------------
// vsched_pkg -- Module 17's mechanisms, with a vehicle's parameters.
//
// Nothing here is a new mechanism. Everything here is a constant that
// moved, and the chapter is what the movement does. The two that
// matter are the line rate, which fell by ten, and the sync error,
// which did not move at all.
// ---------------------------------------------------------------------
package vsched_pkg;
// ---- rates present in a vehicle -------------------------------------
localparam int RATE_EDGE_MBPS = 100; // sensor and actuator links
localparam int RATE_BACKBONE_MBPS = 1000; // zone to central
// ---- frame sizes, in octets -----------------------------------------
localparam int L_MTU = 1518;
localparam int L_MTU_WIRE = 1538; // plus preamble and interframe gap
localparam int L_EXPRESS = 64; // a control frame
localparam int L_FRAGMENT = 84; // a minimum fragment, on the wire
// ---- the one term that does NOT scale with rate ----------------------
// Chapter 17.2 Section 8's band at 1 Gb/s is 12.192 us and Chapter 17.3
// Section 16's is 0.560 us; the difference between them is the frame,
// and what is left over -- 48 ns -- is the synchronisation error.
localparam int SYNC_ERROR_NS = 48;
// us in tenths of a nanosecond, to keep integers exact
function automatic int serialise_ns_x10(int octets, int rate_mbps);
return (octets * 8 * 10000) / rate_mbps; // ns x 10
endfunction
function automatic int guard_band_ns_x10(int l_uninterruptible,
int rate_mbps);
return serialise_ns_x10(l_uninterruptible, rate_mbps)
+ (SYNC_ERROR_NS * 10);
endfunction
// ---- topology --------------------------------------------------------
localparam int HOPS_MAX = 3;
localparam int SEGMENT_M = 15;
localparam int PROP_NS_X10 = 758; // 15 m at 0.66c
localparam int FABRIC_NS_X10 = 300; // lookup, from 17.1 Section 4
// ---- traffic classes -------------------------------------------------
typedef enum logic [2:0] {
TC_CONTROL = 3'd0, // 1-10 ms period, hard deadline
TC_AUDIO = 3'd1,
TC_RADAR = 3'd2,
TC_CAMERA = 3'd3, // megabytes, bursty
TC_DIAG = 3'd4,
TC_BEST_EFF = 3'd5
} vclass_e;
// Only the first is express. Chapter 17.3 Section 4's split, made a
// vehicle decision: everything with a hard deadline preempts
// everything without one.
localparam logic [5:0] EXPRESS_SET = 6'b00_0001;
// ---- what a deadline is ---------------------------------------------
typedef struct packed {
logic [15:0] period_us;
logic [15:0] deadline_us;
logic [2:0] hops;
} vstream_t;
endpackageClassification: a parameter package in which one constant refuses to scale and that is the whole chapter.
What it teaches: that SYNC_ERROR_NS is rate-independent and every other term is not. Chapter 17.2 §8's 12.192 µs band at 1 Gb/s and Chapter 17.3 §16's 0.560 µs differ by exactly the frame — 1 518 octets against 64 — and the 48 nanoseconds left over is the synchronisation term. Chapter 17.3 §16 observed that this term becomes 89.4% of the band at 100 Gb/s; at 100 Mb/s it is 0.04%, and it is the only thing in this chapter that gets easier as the rate falls.
And it teaches that EXPRESS_SET is one bit wide in practice. Chapter 17.3 §4 allowed express and preemptable to be assigned per class; a vehicle's assignment is trivial — everything with a hard deadline is express and everything else is not — because the size ratio between the classes is four orders of magnitude and there is nothing in the middle to argue about.
Deliberately simplified: the whole package works in tenths of a nanosecond as integers, which keeps the arithmetic exact and makes every expression harder to read. FABRIC_NS_X10 is a single constant where Chapter 17.1 §4's lookup term depends on table size and hit rate. vstream_t has no source or destination, so it cannot express a path. And HOPS_MAX is a constant rather than a property of a route, which is correct for a fixed vehicle topology and would be wrong anywhere else.
Production implication: the rate-independence of the sync term is worth carrying into a specification, because it inverts the usual advice. At data-centre rates the guidance is: improve the clock, because it dominates the band. At 100 Mb/s the clock contributes 48 nanoseconds out of 121 488 and improving it is worthless — the entire band is the frame, so the only lever is preemption. A vehicle programme that spends effort on sub-nanosecond synchronisation is optimising 0.04% of the quantity it cares about, and Section 12 shows the sync budget matters enormously for a completely different reason: not the band's size, but what happens when the clock is gone.
// ---------------------------------------------------------------------
// zone_topology_model -- a vehicle's path, which is short, fixed, and
// mixed-rate.
//
// Section 5's accountant prices a uniform path. A real vehicle path is
// 100 Mb/s up from a sensor, 1 Gb/s across the backbone, and 100 Mb/s
// down to an actuator, and the middle hop costs a tenth of the outer
// two. Pricing the whole path at the slowest link overstates it by
// nearly a third.
// ---------------------------------------------------------------------
module zone_topology_model
import vsched_pkg::*;
#(
parameter int PREEMPTION = 1
)(
input logic clk,
input logic rst_n,
input logic [1:0] src_zone,
input logic [1:0] dst_zone,
input logic [15:0] frame_octets,
output logic [2:0] hops,
output logic [31:0] path_ns_x10,
output logic crosses_backbone,
output logic [31:0] uniform_model_ns_x10,
output logic [15:0] overstatement_pct
);
localparam int L_BLOCK = (PREEMPTION != 0) ? L_FRAGMENT : L_MTU_WIRE;
function automatic int hop_ns_x10(int octets, int rate_mbps);
return 2 * serialise_ns_x10(octets, rate_mbps)
+ serialise_ns_x10(L_BLOCK, rate_mbps)
+ PROP_NS_X10 + FABRIC_NS_X10;
endfunction
always_comb begin
crosses_backbone = (src_zone != dst_zone);
// Same zone: one switch. Different zones: zone, backbone, zone.
hops = crosses_backbone ? 3'd3 : 3'd1;
if (crosses_backbone)
path_ns_x10 = 32'(hop_ns_x10(int'(frame_octets), RATE_EDGE_MBPS))
+ 32'(hop_ns_x10(int'(frame_octets), RATE_BACKBONE_MBPS))
+ 32'(hop_ns_x10(int'(frame_octets), RATE_EDGE_MBPS));
else
path_ns_x10 = 32'(hop_ns_x10(int'(frame_octets), RATE_EDGE_MBPS));
uniform_model_ns_x10 =
32'(hop_ns_x10(int'(frame_octets), RATE_EDGE_MBPS)) * 32'(hops);
overstatement_pct = (path_ns_x10 == 0) ? 16'd0
: 16'(((uniform_model_ns_x10 - path_ns_x10) * 100) / path_ns_x10);
end
endmoduleClassification: a path model with exactly two cases, because a vehicle has exactly two.
What it teaches: that overstatement_pct is a real number and it is large. A 64-octet control frame with preemption costs 17.07 µs on a 100 Mb/s hop and 1.80 µs on the 1 Gb/s backbone hop, so the true three-hop path is 35.94 µs against the uniform model's 51.2 — the uniform model overstates by 42.5%. A design that budgets from the slow link may buy faster edge links it does not need.
And it teaches that a vehicle's path length has two values and no others. Same zone is one hop; different zones is three. There is no four-hop path, no routing decision, and no variability — which is why Chapter 17.1 §10's N-hop worst case, general and parameterised, collapses here into a two-entry table.
Deliberately simplified: zones are two-bit identifiers with no notion of which ports connect them, so a topology error is inexpressible. The backbone is one hop where a larger vehicle may have two central switches. hop_ns_x10 uses the same frame size at every hop, which is correct for a store-and-forward path and wrong if any hop is cut-through. And nothing here represents the schedule's wait, which Chapter 17.2 §10 showed is cycle − window and is usually the largest term of all.
Production implication: the missing schedule wait is the omission that matters most, because it dominates. A 1 ms cycle with a 200 µs window has a worst-case schedule wait of 800 µs, against a 35.94 µs transport path — the wait is 22 times the transport. So a vehicle's end-to-end latency budget is almost entirely when the window opens, not how fast the link is, and the correct response to a missed deadline is usually a shorter cycle rather than a faster link — which is exactly what Section 8 shows preemption makes possible.
4. Module 17's Per-Hop Latency, Recomputed at 100 Mb/s
Chapter 17.1 §4's seven terms, with the rate divided by ten and the cable shortened by 6.7.
| Term | At 1 Gb/s, 100 m | At 100 Mb/s, 15 m | Ratio |
|---|---|---|---|
| serialisation, 1 518 octets | 12.14 µs | 121.44 µs | 10× |
| propagation | 0.50 µs | 0.076 µs | 0.15× |
| lookup and fabric | 0.03 µs | 0.03 µs | 1× |
| store-and-forward | 12.14 µs | 121.44 µs | 10× |
| blocking, 1 538 octets on the wire | 12.30 µs | 123.04 µs | 10× |
| bounded subtotal | 37.12 µs | 366.03 µs | 9.86× |
Three of the five terms scale exactly with the rate and they are 99.97% of the total. Propagation falls and the fabric term is unchanged, and neither is large enough to matter — which is the quantitative reason Chapter 22.1's short cable, so decisive for the physical layer, is irrelevant here.
Then the hop count, which is where the vehicle gets something back.
| 1 Gb/s, 5 hops | 100 Mb/s, 3 hops | |
|---|---|---|
| per hop | 37.12 µs | 366.03 µs |
| path | 185.6 µs | 1 098.1 µs |
| against a 1 ms deadline | 18.6% of it | 109.8% of it |
The topology saves a factor of 1.67 and the rate costs a factor of 9.86, so the net is 5.9× worse — and the last row is the finding: the bounded terms alone exceed the deadline.
One more comparison, because it is the one a system architect will reach for.
| Configuration | Per hop | Three hops | Fits 1 ms? |
|---|---|---|---|
| 100 Mb/s edge links | 366.03 µs | 1 098.1 µs | no |
| 1 Gb/s throughout | 36.70 µs | 110.1 µs | yes, with 89% spare |
| 100 Mb/s, express 64-octet frame, no preemption | 133.39 µs | 400.2 µs | yes, with 60% spare |
| 100 Mb/s, express frame, with preemption | 17.07 µs | 51.2 µs | yes, with 95% spare |
Rows one and three are the same link carrying different frames, and the difference is the whole point of a traffic class. Row one prices a maximum-size frame's journey; row three prices a 64-octet control frame's, where serialisation and store-and-forward are its own small length and only the blocking term still carries the MTU — because a maximum-size frame may already be transmitting when the control frame becomes ready.
So the deadline is met or missed depending entirely on one term, and that term is Chapter 17.1 §4's row five: blocking by a frame already in progress, 123.04 µs at 100 Mb/s, and 92.2% of the express frame's per-hop latency. Chapter 17.3 exists to shrink exactly that term, and Section 10 is what it does here.
5. RTL 2 — The Three-Hop Path Accountant
// ---------------------------------------------------------------------
// three_hop_accountant -- Chapter 17.1 Section 3's latency accountant,
// with a vehicle's hop count and rates, and with the blocking term
// broken out because it is the one that decides everything.
//
// The block's purpose is to make the deadline's failure explicit at
// elaboration rather than in a lab: a configuration that cannot meet
// the deadline should say so before anyone builds it.
// ---------------------------------------------------------------------
module three_hop_accountant
import vsched_pkg::*;
#(
parameter int RATE_MBPS = RATE_EDGE_MBPS,
parameter int HOPS = HOPS_MAX,
parameter int FRAME_OCTETS = L_EXPRESS,
parameter int PREEMPTION = 0
)(
input logic clk,
input logic rst_n,
input logic [15:0] deadline_us,
output logic [31:0] serialise_ns_x10_o,
output logic [31:0] store_fwd_ns_x10_o,
output logic [31:0] blocking_ns_x10_o,
output logic [31:0] per_hop_ns_x10,
output logic [31:0] path_ns_x10,
output logic [15:0] deadline_used_pct,
output logic deadline_met,
output logic blocking_dominates,
output logic [15:0] blocking_share_pct
);
localparam int L_BLOCK = (PREEMPTION != 0) ? L_FRAGMENT : L_MTU_WIRE;
always_comb begin
serialise_ns_x10_o = 32'(serialise_ns_x10(FRAME_OCTETS, RATE_MBPS));
store_fwd_ns_x10_o = serialise_ns_x10_o; // the same length
blocking_ns_x10_o = 32'(serialise_ns_x10(L_BLOCK, RATE_MBPS));
per_hop_ns_x10 = serialise_ns_x10_o + store_fwd_ns_x10_o
+ blocking_ns_x10_o
+ 32'(PROP_NS_X10) + 32'(FABRIC_NS_X10);
path_ns_x10 = per_hop_ns_x10 * HOPS;
// deadline_us to ns x 10 is a factor of 10 000.
deadline_used_pct = (deadline_us == 0) ? 16'hFFFF
: 16'((path_ns_x10 * 100) / (32'(deadline_us) * 10000));
deadline_met = (path_ns_x10 <= (32'(deadline_us) * 10000));
blocking_share_pct = (per_hop_ns_x10 == 0) ? 16'd0
: 16'((blocking_ns_x10_o * 100) / per_hop_ns_x10);
// Chapter 17.1 Section 4's row five, made a verdict: when blocking is
// most of the hop, preemption is the only lever that matters.
blocking_dominates = (blocking_share_pct > 16'd50);
end
endmoduleClassification: a combinational accountant whose outputs are a verdict and the reason for it.
What it teaches: that blocking_share_pct is the output that chooses the remedy. At 100 Mb/s with a 64-octet control frame and no preemption, blocking is 123.04 of 133.39 microseconds — 92.2% of the hop — so every other optimisation is arguing over the remaining 8%. With preemption the same term is 6.72 µs and the hop is 17.07, of which blocking is 39.4%. The block does not recommend preemption; it reports which term is large, and the recommendation follows.
And it teaches that store_fwd_ns_x10_o equals serialise_ns_x10_o and that this is not double counting. Chapter 17.1 §4 made the argument: a store-and-forward switch serialises the frame in and then out, and both intervals are real. A cut-through switch would remove the second, which at 100 Mb/s on a small frame saves 5.12 µs per hop — worth having, and an order of magnitude less than preemption is worth.
Deliberately simplified: the accountant prices one frame's path and has no representation of interference from other frames, which Section 6 shows is the term that actually breaks a vehicle. PREEMPTION is a compile-time parameter where Chapter 17.3 §13's verify/response handshake means it is a negotiated, run-time property that can be withdrawn. HOPS is uniform, so a path crossing a 100 Mb/s edge link and then a 1 Gb/s backbone is not expressible — which is exactly the real vehicle path.
Production implication: the missing mixed-rate path is the single most useful extension and it changes the answer materially. A real sensor-to-actuator path is 100 Mb/s, then 1 Gb/s, then 100 Mb/s, so the middle hop costs a tenth of the outer two. With preemption that path is 17.07 + 1.80 + 17.07 = 35.94 µs rather than the uniform model's 51.2 — 30% better, and entirely because the backbone is faster. A design that prices the whole path at the slowest link overstates its latency by nearly a third and may buy faster edge links it does not need.
6. Strict Priority Bounds the Wrong Term
Before reaching for a schedule, establish what strict priority already does — because it does more than people expect and less than a vehicle needs.
Start with the traffic that frightens everybody: a camera.
| Value | |
|---|---|
| a compressed camera stream | 25 Mb/s |
| at 30 frames per second | 833 333 bits per frame |
| as octets | 104.2 kB |
| serialised at 100 Mb/s | 8.33 ms |
| link utilisation | 25% |
A control frame with a 1 ms deadline, arriving behind that burst in a first-in-first-out queue, waits up to 8.33 milliseconds — eight deadlines. That is the scenario every automotive networking talk opens with, and strict priority solves it completely.
Chapter 17.1 §8 built the strict-priority interference term and the bound is one maximum frame per hop.
| Per hop | Three hops | |
|---|---|---|
| FIFO, behind a camera burst | up to 8.33 ms | up to 25 ms |
| strict priority, no preemption | 123.04 µs | 369.1 µs |
| strict priority with preemption | 6.72 µs | 20.2 µs |
Strict priority turns 8.33 milliseconds into 123 microseconds, because a high-priority frame waits only for the frame already in progress and never for the queue behind it. So the camera is not the problem, and a chapter that stops here has explained nothing that Module 17 did not.
The problem is the express class interfering with itself.
| Control streams converging on one uplink | Express load per ms | Worst-case same-priority wait |
|---|---|---|
| 10 | 67.2 µs — 6.7% | 67.2 µs |
| 25 | 168.0 µs — 16.8% | 168.0 µs |
| 50 | 336.0 µs — 33.6% | 336.0 µs |
| 100 | 672.0 µs — 67.2% | 672.0 µs |
Each stream is a 64-octet frame every millisecond — 84 octets on the wire, 6.72 µs at 100 Mb/s — and a zone controller aggregating fifty sensors and actuators onto one uplink carries fifty of them. Chapter 17.1 §11 named same-priority queueing as one of the two terms with no bound, and this is it: strict priority says nothing about how long a frame waits behind frames of its own priority.
Priority bounds the interference from below. It says nothing about the interference from beside, and in a vehicle the traffic beside is the same safety-critical class.
And the worst case is not an average. Fifty streams at 33.6% utilisation sounds comfortable; the worst case is all fifty arriving in the same microsecond, which is not a pathological assumption in a vehicle — they are periodic, they were started by the same power-on event, and nothing in the system deliberately spreads them. Periodic streams that share an origin align, and once aligned they stay aligned.
That is the argument for a schedule rather than a priority.
| Mechanism | Bounds | Does not bound |
|---|---|---|
| strict priority | interference from lower classes — one frame | same-class queueing |
| preemption | that one frame, down to a fragment | same-class queueing |
| a time-aware schedule | same-class queueing, by giving each stream its own window | — |
Row three is Chapter 17.2's mechanism doing the thing it exists for, and the reason it is needed in a vehicle and often not in a data centre is row one of Section 2's traffic table: the safety-critical class has fifty members, not one.
7. RTL 3 — The Guard Band at Automotive Rates
// ---------------------------------------------------------------------
// automotive_guard_band -- Chapter 17.2 Section 7's band, computed at
// 100 Mb/s, and the verdict it implies about a cycle length.
//
// The band is subtracted from EVERY window in EVERY cycle. At 1 Gb/s
// it is 12.192 us and a 12.5 us window still delivers 0.308. At
// 100 Mb/s it is 121.488 us and a 100 us window delivers NOTHING --
// the window is shorter than the band.
// ---------------------------------------------------------------------
module automotive_guard_band
import vsched_pkg::*;
#(
parameter int RATE_MBPS = RATE_EDGE_MBPS,
parameter int PREEMPTION = 0
)(
input logic clk,
input logic rst_n,
input logic [31:0] cycle_us,
input logic [7:0] window_pct, // window as a fraction of cycle
output logic [31:0] band_ns_x10,
output logic [31:0] window_ns_x10,
output logic [31:0] usable_ns_x10,
output logic [15:0] usable_link_pct_x100,
output logic window_shorter_than_band,
output logic [31:0] min_viable_cycle_us,
output logic [15:0] sync_share_pct_x100
);
localparam int L_UNINT = (PREEMPTION != 0) ? L_EXPRESS : L_MTU;
always_comb begin
band_ns_x10 = 32'(guard_band_ns_x10(L_UNINT, RATE_MBPS));
window_ns_x10 = (cycle_us * 10000 * 32'(window_pct)) / 100;
window_shorter_than_band = (window_ns_x10 <= band_ns_x10);
usable_ns_x10 = window_shorter_than_band ? 32'd0
: (window_ns_x10 - band_ns_x10);
usable_link_pct_x100 = (cycle_us == 0) ? 16'd0
: 16'((usable_ns_x10 * 10000) / (cycle_us * 10000));
// The cycle at which the window exactly equals the band. Below it
// the scheduled class gets nothing at all.
min_viable_cycle_us = (window_pct == 0) ? 32'hFFFF_FFFF
: (band_ns_x10 * 100) / (32'(window_pct) * 10000);
// Chapter 17.3 Section 16 showed this reaching 89.4% at 100 Gb/s.
// At 100 Mb/s it is four hundredths of one per cent.
sync_share_pct_x100 = 16'((32'(SYNC_ERROR_NS) * 10 * 10000)
/ band_ns_x10);
end
endmoduleClassification: a combinational band calculator whose most useful output is a minimum cycle length.
What it teaches: that min_viable_cycle_us is a hard floor and it is large. With a 20% window and no preemption, the band's 121.488 µs needs a window at least that long, so the cycle must be at least 607.4 µs — and any schedule with a shorter cycle delivers the scheduled class zero bandwidth while remaining perfectly correct. Chapter 17.2 §8 found the same collapse at 1 Gb/s, at a 61.0 µs cycle; at 100 Mb/s it has moved up by exactly ten.
And it teaches how completely sync_share_pct_x100 inverts. Chapter 17.3 §16 observed that at 100 Gb/s with preemption the band is 89.4% synchronisation error, so the next improvement is the clock's. At 100 Mb/s without preemption it is 0.04% — the band is the frame, entirely — and no clock improvement changes anything at all.
Deliberately simplified: window_pct is one number for the whole cycle, where a real gate-control list has several windows of different lengths, each paying its own band. usable_link_pct_x100 assumes the band is pure loss, which is Chapter 17.2 §7's conservative model — a real port may transmit a frame that fits entirely within the band. And L_UNINT switches on a compile-time parameter where preemption is negotiated at run time and can be withdrawn by the partner.
Production implication: the negotiability of preemption is the detail that turns this block into a hazard. Chapter 17.3 §13's verify/response handshake means preemption is only active if the link partner confirmed it, and a partner replaced in service — or one that boots slowly — may leave the link without it. The schedule, meanwhile, was designed against the 5.168 µs band. The moment preemption is unavailable the band becomes 121.488 µs, every window shorter than that delivers nothing, and the control traffic stops — on a correctly programmed schedule, on a healthy link, with no counter moving. The guard band must be recomputed from the negotiated state, and a schedule must have a defined behaviour when the assumption under which it was built is withdrawn.
8. 121.488 Microseconds, and the Cycle It Forbids
The band is subtracted from every window in every cycle. This section is the table that follows, and it has a hole in it.
First, the arithmetic reproduced against Chapter 17.2 §8, as a check. With a window of 20% of the cycle and a band of 12.192 µs at 1 Gb/s, the usable fraction of the link is (window − band) ÷ cycle:
| Cycle | Chapter 17.2 §8's published value | Recomputed here |
|---|---|---|
| 250 µs | 15.12% | 15.12% |
| 125 µs | 10.25% | 10.25% |
| 62.5 µs | 0.49% | 0.49% |
The model reproduces the published table exactly, which is what licenses using it at a rate that chapter did not cover.
Now 100 Mb/s, with a 20% window.
| Cycle | Window | No preemption (band 121.488 µs) | With preemption (band 5.168 µs) |
|---|---|---|---|
| 10 ms | 2 000 µs | 18.79% | 19.95% |
| 5 ms | 1 000 µs | 17.57% | 19.90% |
| 2 ms | 400 µs | 13.93% | 19.74% |
| 1 ms | 200 µs | 7.85% | 19.48% |
| 500 µs | 100 µs | 0.00% | 18.97% |
| 250 µs | 50 µs | 0.00% | 17.93% |
| 125 µs | 25 µs | 0.00% | 15.87% |
| 62.5 µs | 12.5 µs | 0.00% | 11.73% |
Four zeros in the third column, and they start at a 500 microsecond cycle.
At 100 Mb/s without preemption, a schedule with a cycle shorter than 607 µs delivers the scheduled class no bandwidth whatsoever. The gates open and close exactly as programmed, the bound is honoured, and nothing is transmitted.
That rules out the control periods a vehicle actually wants. A 1 ms control loop wants a cycle of 1 ms or shorter; the table says 1 ms delivers 7.85% and anything faster delivers nothing. The scheduled class is the class the vehicle steers with, so a schedule that cannot run faster than 607 µs is a schedule that cannot serve its purpose.
With preemption the column has no zeros at all.
| No preemption | With preemption | |
|---|---|---|
| usable at a 1 ms cycle | 7.85% | 19.48% |
| usable at a 250 µs cycle | 0.00% | 17.93% |
| collapse point | 607.4 µs | 25.8 µs |
| ratio of collapse points | — | 23.5× |
The collapse moves by a factor of 23.5, which is the ratio of the two bands — 121.488 to 5.168 — because the collapse point is linear in the band. Chapter 17.3 §16 found 21.8× at 1 Gb/s for the same reason, and the small difference between 21.8 and 23.5 is the 48 ns sync term, which is a larger fraction of the gigabit band than of the hundred-megabit one.
And the practical reading of the whole table is one line.
| At 100 Mb/s | Conclusion |
|---|---|
| cycle ≥ 5 ms, no preemption | workable — 17.6% of the link |
| cycle 1 ms, no preemption | marginal — 7.85% |
| cycle < 607 µs, no preemption | impossible |
| any cycle ≥ 26 µs, with preemption | workable — 12% to 20% |
Row four is why Section 10 argues preemption is not an option in a vehicle. It is not recovering bandwidth at the margin; it is the difference between a schedule that can express a 250-microsecond control period and one that cannot.
9. RTL 4 — The Express Path and the Preemption Decision
// ---------------------------------------------------------------------
// express_path_model -- Chapter 17.3 Section 10's preemption decision,
// with the vehicle's class assignment and one addition: the block must
// know whether preemption is actually NEGOTIATED, not merely enabled.
//
// Chapter 17.3 Section 13's verify/response handshake is what makes the
// difference, and Section 7's production note is what happens when a
// schedule is built assuming it and the handshake later fails.
// ---------------------------------------------------------------------
module express_path_model
import vsched_pkg::*;
(
input logic clk,
input logic rst_n,
input logic express_ready,
input vclass_e express_class,
input logic preemptable_in_progress,
input logic [15:0] preemptable_remaining_octets,
input logic preemption_verified, // 17.3's handshake result
input logic preemption_enabled, // local configuration
output logic preempt_now,
output logic must_wait,
output logic [31:0] wait_ns_x10,
output logic band_assumption_broken,
output logic [31:0] effective_band_ns_x10,
output logic [31:0] c_preemptions,
output logic [31:0] c_waits_full_frame
);
// Chapter 17.3 Section 11: a fragment must leave at least 60 octets
// behind, so a frame close to its end is not worth preempting.
localparam int MIN_REMAINING = 60;
logic active;
assign active = preemption_enabled && preemption_verified;
always_comb begin
preempt_now = active && express_ready && preemptable_in_progress &&
(preemptable_remaining_octets > MIN_REMAINING) &&
((6'b1 << express_class) & EXPRESS_SET) != 6'b0;
must_wait = express_ready && preemptable_in_progress && !preempt_now;
wait_ns_x10 = must_wait
? 32'(serialise_ns_x10(int'(preemptable_remaining_octets),
RATE_EDGE_MBPS))
: 32'd0;
// THE important output. A schedule built for the preempting band
// and running without preemption is silently wrong.
effective_band_ns_x10 = active
? 32'(guard_band_ns_x10(L_EXPRESS, RATE_EDGE_MBPS))
: 32'(guard_band_ns_x10(L_MTU, RATE_EDGE_MBPS));
band_assumption_broken = preemption_enabled && !preemption_verified;
end
always_ff @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
c_preemptions <= '0; c_waits_full_frame <= '0;
end else begin
if (preempt_now) c_preemptions <= c_preemptions + 32'd1;
if (must_wait && !preempt_now) c_waits_full_frame <= c_waits_full_frame + 32'd1;
end
end
endmoduleClassification: a preemption decision, and one output that reports a schedule's premise being false.
What it teaches: that band_assumption_broken is the most important signal in the block and it has nothing to do with preempting. A vehicle's schedule is computed offline, months before the vehicle ships, against a guard band of 5.168 µs that assumes preemption. Chapter 17.3 §13's handshake means preemption is only active if the partner confirmed it, and a partner that boots slowly, or a replacement part with it disabled, leaves the link with a 121.488 µs band and a schedule whose windows are 50 µs long.
And it teaches that MIN_REMAINING costs real cases. Chapter 17.3 §11's minimum fragment means a preemptable frame with fewer than 60 octets left cannot be interrupted, so the express frame waits — up to 60 octets, 4.8 µs at 100 Mb/s. That is the residual blocking term preemption cannot remove, and it is why Section 4's preempting blocking term is 6.72 µs rather than zero.
Deliberately simplified: RATE_EDGE_MBPS is baked into wait_ns_x10 rather than parameterised, so the block is 100 Mb/s only. c_waits_full_frame counts a decision rather than accumulating the time waited, which is the more useful quantity. The class test constructs a one-hot mask inline rather than using a function. And there is no hysteresis on preemption_verified, so a handshake that flaps toggles the effective band every time.
Production implication: the flapping case is the one to design for, because the schedule cannot follow. Chapter 17.2 §13's atomic installation exists precisely so a schedule changes at a defined instant; a band that changes because a link partner's handshake failed is not a schedule change and nothing re-plans. The defensible behaviour is to treat loss of verified preemption as a fault, not as a degraded mode: raise it, log it, and let the safety layer decide — because the alternative is a control loop that silently stops being served while every gate still opens on time.
10. Preemption Is Not Optional at 100 Mb/s
Module 17 presented preemption as a way to recover bandwidth. At automotive rates it is what makes the mechanism usable at all, and the case is arithmetic rather than rhetorical.
Four separate results, each independently sufficient.
| # | Result | Without | With |
|---|---|---|---|
| 1 | the express frame's per-hop latency | 133.39 µs | 17.07 µs |
| 2 | three-hop worst case | 400.2 µs | 51.2 µs |
| 3 | shortest usable cycle | 607.4 µs | 25.8 µs |
| 4 | usable link at a 1 ms cycle | 7.85% | 19.48% |
Result 2 is the one that decides. A 1 ms hard deadline with a three-hop worst case of 400.2 µs leaves 60% of the budget — which sounds adequate until Section 6's same-priority queueing is added: fifty converging control streams contribute up to 336 µs, and 400.2 + 336 is 736 µs, before any margin for the schedule's own wait. With preemption the same sum is 51.2 + 336 = 387 µs, and there is room.
Result 3 is the one that decides differently. Even with a comfortable latency budget, a schedule that cannot express a cycle shorter than 607 µs cannot serve a 1 ms control loop with any margin at all — the loop's period and the schedule's cycle would be within a factor of 1.6, and Chapter 17.2 §10's schedule wait is cycle − window, which at 607 µs is 486 µs of wait on its own.
So the recommendation is unambiguous, and it has three parts.
| Requirement | |
|---|---|
| 1 | every scheduled port in a vehicle supports preemption |
| 2 | the schedule is computed against the preempting band and the design says so |
| 3 | loss of verified preemption is a reportable fault, not a degraded mode |
Part three is the one that gets left out and Section 9's band_assumption_broken exists for it. A schedule built on a 5.168 µs band and run on a link with a 121.488 µs one is not slightly worse — for every window shorter than 121.488 µs it delivers nothing, and the symptom is a control loop that stops while every visible mechanism reports health.
One honest qualification, because preemption is not free.
| Cost | From |
|---|---|
| two MACs on one PHY | Chapter 17.3 §3 |
| SMD codes and fragment framing | Chapter 17.3 §5 |
| a second CRC — the mCRC | Chapter 17.3 §7 |
| a reassembly state machine | Chapter 17.3 §12 |
| a verify/response handshake | Chapter 17.3 §13 |
| a fragment/corruption discriminator | Chapter 17.3 §8 |
Six mechanisms, priced in Chapter 17.3 §18, and in a vehicle they are bought not for throughput but to make a deadline expressible. That is a different justification from the one Module 17 gave, it produces the same decision, and the difference matters when somebody proposes removing preemption to save area — because the argument against is no longer you will lose bandwidth but the control loop will not be schedulable.
11. RTL 5 — The Cycle Timer and Its Time Source
// ---------------------------------------------------------------------
// vehicle_cycle_timer -- Chapter 17.2 Section 5's cycle timer, with the
// one addition a vehicle needs: it knows where its time came from and
// how long ago.
//
// Chapter 17.2 Section 6 established that the cycle's start comes from
// the synchronised clock. What that chapter did not need -- because a
// data centre notices within a minute -- is what the timer should do
// when the clock stops arriving.
// ---------------------------------------------------------------------
module vehicle_cycle_timer
import vsched_pkg::*;
#(
parameter int TICK_NS = 8, // local timer resolution
parameter int PPM_BUDGET = 200 // 4.4 Section 2's two-ended figure
)(
input logic clk,
input logic rst_n,
input logic [31:0] cycle_us,
input logic ptp_time_valid,
input logic [63:0] ptp_time_ns,
input logic ptp_update, // a fresh servo correction landed
output logic cycle_start,
output logic [31:0] cycle_phase_ns,
output logic [31:0] ns_since_ptp_update,
output logic [31:0] drift_bound_ns, // worst case since the last update
output logic in_holdover,
output logic drift_exceeds_band,
output logic drift_exceeds_window,
output logic drift_exceeds_cycle,
output logic [31:0] c_cycles,
output logic [31:0] c_holdover_cycles
);
localparam int BAND_NS_X10 = guard_band_ns_x10(L_EXPRESS, RATE_EDGE_MBPS);
logic [31:0] phase;
always_ff @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
phase <= '0; cycle_start <= 1'b0; c_cycles <= '0;
ns_since_ptp_update <= '0; c_holdover_cycles <= '0;
end else begin
cycle_start <= 1'b0;
// The timer free-runs. It does not know the clock is gone; it is
// internally perfect either way, which is Section 20's whole
// point.
phase <= phase + TICK_NS;
if (phase + TICK_NS >= (cycle_us * 1000)) begin
phase <= '0;
cycle_start <= 1'b1;
c_cycles <= c_cycles + 32'd1;
if (in_holdover) c_holdover_cycles <= c_holdover_cycles + 32'd1;
end
if (ptp_update) ns_since_ptp_update <= '0;
else ns_since_ptp_update <= ns_since_ptp_update + TICK_NS;
end
end
assign cycle_phase_ns = phase;
assign in_holdover = !ptp_time_valid;
// Worst-case accumulated error: 200 ppm of elapsed time.
assign drift_bound_ns = (ns_since_ptp_update / 1_000_000) * PPM_BUDGET;
assign drift_exceeds_band = (drift_bound_ns * 10) > BAND_NS_X10;
assign drift_exceeds_window = (drift_bound_ns) > ((cycle_us * 1000) / 5);
assign drift_exceeds_cycle = (drift_bound_ns) > (cycle_us * 1000);
endmoduleClassification: a free-running cycle timer with three thresholds on a quantity it computes rather than measures.
What it teaches: that drift_bound_ns is a bound rather than a measurement, and that is the only honest thing available. A node in holdover cannot know its own error — knowing it would require the reference it has lost. What it can know is how long it has been free-running, and Chapter 4.4 §2's ±100 ppm per end gives a worst-case rate. The bound is computable and the error is not, which is the correct shape for a safety argument.
And it teaches that the three thresholds are three different failures. drift_exceeds_band means the schedule's guard band no longer covers the misalignment — the bound is void. drift_exceeds_window means a transmission intended for this window may land in the next one. drift_exceeds_cycle means the node is now serving a different cycle from its neighbours entirely. Section 12 puts times on all three.
Deliberately simplified: the timer advances by a constant TICK_NS with no fractional accumulator, so any cycle length not a multiple of 8 ns drifts by construction. PPM_BUDGET is the standard's worst case where a real holdover estimate would use the oscillator's measured rate against its last known good offset — which is far tighter and needs a history the block does not keep. in_holdover is !ptp_time_valid with no hysteresis. And drift_exceeds_window assumes a 20% window as a literal division by five.
Production implication: using the standard's ±100 ppm as the holdover bound is very conservative and the conservatism is expensive. An oscillator whose frequency offset was measured at 12 ppm against the grandmaster five seconds ago will still be near 12 ppm now — temperature moves it slowly — so a holdover bound built from the servo's own last frequency estimate is often an order of magnitude tighter than 200 ppm. That converts Section 12's 25.8 millisecond band budget into roughly a quarter of a second, which is the difference between a system that declares a fault on every momentary PTP hiccup and one that rides through. Keep the servo's frequency estimate and use it; Chapter 16.4 §3 already computes it.
12. What Happens When PTP Is Lost
A schedule is a statement about time that several nodes must agree on. This section prices losing the agreement, and the prices are alarmingly short.
The arithmetic is one line. Two clocks with a worst-case relative offset of 200 ppm — Chapter 4.4 §2's figure, which is the standard's and not an estimate — diverge by 2 × 10⁻⁴ of elapsed time.
time to accumulate an error of E = E ÷ 2 × 10⁻⁴
| Error accumulated | Time to reach it at 200 ppm |
|---|---|
| the preempting guard band, 5.168 µs | 25.8 ms |
| the non-preempting band, 121.488 µs | 607 ms |
| a 200 µs window (1 ms cycle, 20%) | 1.00 s |
| a whole 1 ms cycle | 5.00 s |
| a whole 10 ms cycle | 50.0 s |
Row one is the number to carry. A vehicle that loses PTP has twenty-six milliseconds before the schedule's guard band — the entire margin the design allowed for synchronisation error — is consumed by drift alone. After that the bound Chapter 17.1 computed is no longer proven, even though nothing has visibly changed.
Row four is worse in a different way. After five seconds of holdover a node's cycle has slipped by a whole cycle relative to its neighbours — so it is transmitting in what its neighbour considers a different window, and the traffic that was scheduled to have the link to itself now collides with whatever the neighbour scheduled there. The schedule has not failed; it has become a different schedule.
And here is the property this failure has that nothing else in this track does.
Every assertion about the schedule keeps passing. The gate-control list is applied correctly. The cycle timer's period is exact. The guard band is subtracted from every window. Transmission eligibility is computed correctly. Locally, everything is right — and the guarantee the mechanism exists to provide is gone.
That is because every one of those properties is evaluated against the node's own clock, and the node's own clock is the thing that went wrong. Section 20's rejected class is this observation made formal.
Which raises the question of who does notice, and the answer is a short list.
| Observer | Sees it? | After how long |
|---|---|---|
| the node's own schedule assertions | no — ever | — |
| the PTP servo | yes, immediately | one lost Sync interval |
ns_since_ptp_update | yes | immediately |
| the far end's receive counters | eventually | when frames start colliding |
| a missed control deadline | yes | when the vehicle is already in trouble |
Rows two and three are the only useful ones and they are both trivial to implement. The servo already knows — Chapter 16.4 §5's whole subject is the offset it is correcting — and a counter of nanoseconds since the last correction costs 32 flops. The entire detection problem is solved by wiring something that already exists to something that costs nothing, and the reason it gets missed is that the schedule's own verification passes.
What the node should do, in order.
| Elapsed holdover | Action |
|---|---|
| 0 to one lost Sync interval | nothing — a lost message is normal |
| up to the guard band's budget | raise a warning; the bound still holds |
| beyond it | the latency bound is no longer proven — tell the safety layer |
| beyond a window | stop claiming the scheduled class is scheduled |
| beyond a cycle | the node is misaligned; a defined degraded mode, not silence |
Row three is the line that matters for a safety argument. A latency bound that depends on a synchronised clock is conditional on that clock, and a system that asserts the bound unconditionally has asserted something it cannot support. The honest design publishes the bound together with the condition, and the condition is ns_since_ptp_update.
And Section 11's production note makes the budget far more generous than 200 ppm suggests. Using the servo's measured frequency offset — typically single-digit ppm — rather than the standard's worst case multiplies every row of the first table by ten or more, turning 25.8 milliseconds into roughly a quarter of a second. The conservative bound is correct and the measured one is useful, and a vehicle needs both: the conservative one in the safety case, the measured one in the runtime decision.
13. RTL 6 — The Holdover Monitor
// ---------------------------------------------------------------------
// holdover_monitor -- the block that notices what none of the
// schedule's own assertions can.
//
// Section 12: every local property about the gate-control list, the
// cycle timer and the guard band keeps passing while the network-wide
// guarantee disintegrates. This block watches the ONE quantity that
// changes -- how long since the clock was corrected -- and converts it
// into the four verdicts a safety layer needs.
// ---------------------------------------------------------------------
module holdover_monitor
import vsched_pkg::*;
#(
parameter int TICK_NS = 8,
parameter int PPM_WORST = 200, // the standard's two-ended figure
parameter int SYNC_INTERVAL_US = 125 // a typical PTP Sync period
)(
input logic clk,
input logic rst_n,
input logic ptp_update,
input logic ptp_time_valid,
input logic [15:0] servo_ppm_abs, // 16.4's measured offset, if trusted
input logic servo_ppm_valid,
input logic [31:0] cycle_us,
input logic [7:0] window_pct,
input logic preemption_active,
output logic [31:0] holdover_ns,
output logic [31:0] drift_worst_ns,
output logic [31:0] drift_measured_ns,
output logic [2:0] severity,
output logic bound_still_proven,
output logic schedule_claim_withdrawn,
output logic [31:0] c_holdover_entries,
output logic [31:0] c_longest_holdover_ns
);
localparam int SEV_OK = 3'd0;
localparam int SEV_BLIP = 3'd1; // one lost Sync -- normal
localparam int SEV_WARN = 3'd2; // drift approaching the band
localparam int SEV_UNBOUND = 3'd3; // the latency bound is not proven
localparam int SEV_WINDOW = 3'd4; // transmissions may land next window
localparam int SEV_CYCLE = 3'd5; // this node is on a different cycle
logic [31:0] band_ns;
logic [31:0] window_ns;
logic prev_valid;
always_comb begin
band_ns = preemption_active
? 32'(guard_band_ns_x10(L_EXPRESS, RATE_EDGE_MBPS)) / 10
: 32'(guard_band_ns_x10(L_MTU, RATE_EDGE_MBPS)) / 10;
window_ns = (cycle_us * 1000 * 32'(window_pct)) / 100;
drift_worst_ns = (holdover_ns / 1_000_000) * PPM_WORST;
drift_measured_ns = servo_ppm_valid
? (holdover_ns / 1_000_000) * 32'(servo_ppm_abs)
: drift_worst_ns;
// The severity ladder of Section 12's second table.
if (ptp_time_valid) severity = SEV_OK;
else if (holdover_ns < (SYNC_INTERVAL_US*1000)) severity = SEV_BLIP;
else if (drift_worst_ns < (band_ns / 2)) severity = SEV_WARN;
else if (drift_worst_ns < band_ns) severity = SEV_UNBOUND;
else if (drift_worst_ns < window_ns) severity = SEV_WINDOW;
else severity = SEV_CYCLE;
// The two verdicts a safety layer consumes. Note that the WORST
// case gates the safety claim and the MEASURED one may be used for
// the runtime decision -- Section 11's production note.
bound_still_proven = (severity <= SEV_WARN);
schedule_claim_withdrawn = (severity >= SEV_WINDOW);
end
always_ff @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
holdover_ns <= '0; c_holdover_entries <= '0;
c_longest_holdover_ns <= '0; prev_valid <= 1'b1;
end else begin
prev_valid <= ptp_time_valid;
if (ptp_update || ptp_time_valid) begin
if (holdover_ns > c_longest_holdover_ns)
c_longest_holdover_ns <= holdover_ns;
holdover_ns <= '0;
end else begin
holdover_ns <= holdover_ns + TICK_NS;
end
if (prev_valid && !ptp_time_valid)
c_holdover_entries <= c_holdover_entries + 32'd1;
end
end
endmoduleClassification: a severity ladder over a single elapsed time, and it is the only block in the chapter that can detect the chapter's worst failure.
What it teaches: that bound_still_proven uses drift_worst_ns and not drift_measured_ns, deliberately. A safety claim must rest on a bound the design can defend, and the servo's measured offset is an estimate whose own validity depends on the reference that has been lost. The measured figure is an order of magnitude more useful for deciding what to do — Section 11 showed it turns 25.8 milliseconds into roughly a quarter of a second — and it is not what a safety case may rest on. The block computes both and uses each in its place.
And it teaches why SEV_BLIP exists as a distinct level. A single lost Sync message is normal; PTP runs at a Sync interval of order 125 µs and messages are lost. A design that enters holdover on the first missed message raises a fault every few seconds, which trains everybody to ignore it. The ladder's first rung is there to keep the later rungs credible.
Deliberately simplified: c_longest_holdover_ns captures on exit, so a holdover still in progress is not reflected. The severity thresholds are fractions of the band with no hysteresis, so a marginal case oscillates. servo_ppm_abs is trusted without any check on its age — a frequency estimate from an hour ago is not evidence about now. And the holdover_ns division by a million per evaluation is a real divider in a combinational path and would be restructured as a shift-based approximation.
Production implication: the missing age check on servo_ppm_abs is the one that could make this block dangerous rather than merely incomplete. A stale frequency estimate makes drift_measured_ns small and comforting, and if anything downstream uses it for a safety decision the system will ride through a drift it should have flagged. Timestamp the servo estimate, and fall back to PPM_WORST whenever it is older than a few seconds — the fallback is conservative, it is exactly the behaviour the safety case already assumes, and it costs one comparison.
14. What a Vehicle Schedule Must Never Do
Five prohibitions, each derived from something earlier in the chapter rather than asserted.
One — never compute a schedule against a guard band that preemption has not been confirmed to provide.
| Band | A 50 µs window delivers | |
|---|---|---|
| preemption verified | 5.168 µs | 44.8 µs — 89.7% of the window |
| preemption not verified | 121.488 µs | nothing |
Section 9's band_assumption_broken is the required output and Section 7's production note is the reason. The schedule was computed offline; the handshake happens at run time; nothing re-plans.
Two — never claim a latency bound without publishing the clock condition it depends on.
Section 12: every local property about the schedule keeps passing in holdover. So a bound asserted unconditionally is asserted on the basis of evidence that cannot distinguish the bound holding from the bound being void. The condition is ns_since_ptp_update and it costs 32 flops.
Three — never let a schedule's cycle approach the guard band.
| At 100 Mb/s, no preemption | Usable |
|---|---|
| 1 ms cycle, 200 µs window | 7.85% |
| 700 µs cycle, 140 µs window | 2.64% |
| 607.4 µs cycle, 121.5 µs window | 0.00% |
The collapse is not gradual near the edge, it is a hard zero, and the cycle at which it happens depends on a band that can change at run time — which is prohibition one, arriving from the other direction.
Four — never schedule a class whose members can align.
Section 6: fifty control streams started by the same power-on event stay aligned, and fifty aligned 84-octet frames at 100 Mb/s are 336 µs of same-priority queueing. A schedule that gives the class one window has not separated its members; separating them needs per-stream windows or per-stream shaping, and the gate-control list's length grows with the number of streams rather than with the number of classes.
Five — never treat a missed deadline as the detector.
| Detector | Cost | When it fires |
|---|---|---|
ns_since_ptp_update | 32 flops | immediately |
| the servo's own offset | already computed | immediately |
band_assumption_broken | one comparison | at negotiation |
c_waits_full_frame | 32 flops | when preemption stops working |
| a missed control deadline | free | when the vehicle is already in trouble |
Rows one to four cost about a hundred flip-flops between them — 0.7% of Chapter 19.7 §19's 14 166-flop datapath — and row five is the one most vehicles rely on.
Every failure in this chapter is detectable before it matters, by something that already exists or costs under a hundred flops. The reason they get missed is that the schedule's own verification passes throughout.
15. RTL 7 — Vehicle Schedule Telemetry
// ---------------------------------------------------------------------
// vsched_telemetry -- what a scheduled vehicle port knows about
// itself, snapshotted, with the clock condition attached to every
// latency claim.
//
// Chapter 17.2 Section 15 built schedule telemetry for a data centre. The
// addition here is the holdover state, because Section 12 showed that
// without it every other field is a claim with an unstated premise.
// ---------------------------------------------------------------------
module vsched_telemetry
import vsched_pkg::*;
(
input logic clk,
input logic rst_n,
input logic snapshot,
input logic [31:0] i_cycles,
input logic [31:0] i_holdover_cycles,
input logic [31:0] i_holdover_ns,
input logic [31:0] i_longest_holdover_ns,
input logic [31:0] i_holdover_entries,
input logic [2:0] i_severity,
input logic [31:0] i_preemptions,
input logic [31:0] i_waits_full_frame,
input logic [31:0] i_path_ns_x10,
input logic [15:0] i_deadline_used_pct,
input logic [15:0] i_usable_link_pct_x100,
input logic i_preemption_verified,
input logic i_band_assumption_broken,
input logic i_window_shorter_than_band,
input logic i_deadline_met,
output logic [31:0] o_cycles,
output logic [31:0] o_holdover_cycles,
output logic [31:0] o_longest_holdover_ns,
output logic [31:0] o_holdover_entries,
output logic [2:0] o_severity,
output logic [31:0] o_preemptions,
output logic [31:0] o_waits_full_frame,
output logic [31:0] o_path_ns_x10,
output logic [15:0] o_deadline_used_pct,
output logic [15:0] o_usable_link_pct_x100,
output logic [3:0] o_caveats,
output logic o_latency_claim_valid,
output logic [15:0] o_holdover_fraction_ppm
);
localparam int C_HOLDOVER = 0;
localparam int C_NOPREEMPT= 1;
localparam int C_BANDBROKE= 2;
localparam int C_WINDOWDEAD=3;
always_ff @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
o_cycles <= '0; o_holdover_cycles <= '0;
o_longest_holdover_ns <= '0; o_holdover_entries <= '0;
o_severity <= '0; o_preemptions <= '0; o_waits_full_frame <= '0;
o_path_ns_x10 <= '0; o_deadline_used_pct <= '0;
o_usable_link_pct_x100 <= '0; o_caveats <= '0;
o_holdover_fraction_ppm <= '0;
end else if (snapshot) begin
o_cycles <= i_cycles;
o_holdover_cycles <= i_holdover_cycles;
o_longest_holdover_ns <= i_longest_holdover_ns;
o_holdover_entries <= i_holdover_entries;
o_severity <= i_severity;
o_preemptions <= i_preemptions;
o_waits_full_frame <= i_waits_full_frame;
o_path_ns_x10 <= i_path_ns_x10;
o_deadline_used_pct <= i_deadline_used_pct;
o_usable_link_pct_x100 <= i_usable_link_pct_x100;
// The field a workshop and a fleet-data pipeline both want: what
// fraction of this vehicle's operating time was spent without a
// proven latency bound.
if (i_cycles != 0)
o_holdover_fraction_ppm <= 16'((i_holdover_cycles * 1_000_000)
/ i_cycles);
o_caveats[C_HOLDOVER] <= (i_severity >= 3'd3);
o_caveats[C_NOPREEMPT] <= !i_preemption_verified;
o_caveats[C_BANDBROKE] <= i_band_assumption_broken;
o_caveats[C_WINDOWDEAD] <= i_window_shorter_than_band;
end
end
// A latency figure means nothing without the conditions under which
// it was measured. This is the whole point of the block.
assign o_latency_claim_valid = i_deadline_met &&
!o_caveats[C_HOLDOVER] &&
!o_caveats[C_BANDBROKE] &&
!o_caveats[C_WINDOWDEAD];
endmoduleClassification: a snapshot bank whose last output gates every other field.
What it teaches: that o_holdover_fraction_ppm is the field a fleet learns from. A single vehicle's holdover events are noise; a hundred thousand vehicles' holdover fractions, binned by model, temperature and mileage, locate a systematic problem — a grandmaster that restarts on a particular ECU's wake, a PHY that loses lock in the cold. Normalising to parts per million of cycles is what makes two vehicles with different operating hours comparable, which is Chapter 22.1 §15's argument applied one layer up.
And it teaches why o_latency_claim_valid is a conjunction over three caveats rather than a single flag. i_deadline_met is a statement about arithmetic — the terms add up inside the deadline. Holdover, a broken band assumption and a dead window each invalidate a different premise of that arithmetic, and any one of them makes the sum meaningless. A design that publishes the latency figure without the conjunction publishes a number that was true of a system that no longer exists.
Deliberately simplified: four caveat bits where Section 14 named five prohibitions — the aligned-streams case has no runtime detector here and would need per-stream arrival tracking. No read-clear, so a vehicle's cumulative counters need external differencing across diagnostic sessions. o_severity is snapshotted, so a brief excursion between snapshots is missed — the sticky maximum would be the right field and is not present.
Production implication: the missing sticky maximum is the field to add before shipping, because the failure this chapter is about is transient. A PTP outage that lasts 300 milliseconds during an ignition cycle voids the latency bound for 300 milliseconds and then everything returns to normal; a snapshot taken a month later shows severity zero. Latch the worst severity since the last read, alongside the current one — 3 flops — and the diagnostic session finds a fault that otherwise has to be caught in the act. c_longest_holdover_ns is already the same idea for a different quantity, and the pair of them is what makes an intermittent synchronisation fault findable at all.
16. RTL 8 — Conformance for a Vehicle Scheduled Port
// ---------------------------------------------------------------------
// vsched_conformance_monitor -- properties for a scheduled automotive
// port.
//
// Read the first ten and then read property 11. The first ten are
// entirely local and every one of them holds throughout the failure
// Section 12 describes. Property 11 is the only one that does not, and
// it is the only one whose subject is not the schedule.
// ---------------------------------------------------------------------
module vsched_conformance_monitor
import vsched_pkg::*;
(
input logic clk,
input logic rst_n,
input logic cycle_start,
input logic [31:0] cycle_phase_ns,
input logic [31:0] cycle_us,
input logic gate_open,
input logic in_guard_band,
input logic tx_start,
input logic [15:0] tx_octets,
input logic express_tx,
input logic preempt_now,
input logic preemption_verified,
input logic preemption_enabled,
input logic [15:0] preemptable_remaining_octets,
input logic window_shorter_than_band,
input logic band_assumption_broken,
input logic ptp_time_valid,
input logic [31:0] holdover_ns,
input logic bound_still_proven,
input logic latency_claim_valid
);
// 1. The cycle's phase never exceeds its length.
p_vs_phase_bounded: assert property (@(posedge clk) disable iff (!rst_n)
cycle_phase_ns < (cycle_us * 1000));
// 2. A cycle start zeroes the phase.
p_vs_start_zeroes: assert property (@(posedge clk) disable iff (!rst_n)
cycle_start |=> (cycle_phase_ns < 32'd16));
// 3. Nothing starts transmitting inside the guard band.
p_vs_no_tx_in_band: assert property (@(posedge clk) disable iff (!rst_n)
tx_start |-> !in_guard_band);
// 4. Nothing starts transmitting with the gate closed.
p_vs_gate_respected: assert property (@(posedge clk) disable iff (!rst_n)
tx_start |-> gate_open);
// 5. Preemption only when it is both enabled and verified.
p_vs_preempt_negotiated: assert property (@(posedge clk) disable iff (!rst_n)
preempt_now |-> (preemption_enabled && preemption_verified));
// 6. Never preempt a frame with less than a minimum fragment left.
p_vs_min_fragment: assert property (@(posedge clk) disable iff (!rst_n)
preempt_now |-> (preemptable_remaining_octets > 16'd60));
// 7. Only express classes preempt.
p_vs_express_only: assert property (@(posedge clk) disable iff (!rst_n)
preempt_now |-> express_tx);
// 8. A window shorter than the band transmits nothing.
p_vs_dead_window: assert property (@(posedge clk) disable iff (!rst_n)
window_shorter_than_band |-> !tx_start);
// 9. Enabling preemption without verification raises the flag.
p_vs_band_flag: assert property (@(posedge clk) disable iff (!rst_n)
(preemption_enabled && !preemption_verified) |-> band_assumption_broken);
// 10. Holdover is zero whenever the clock is valid.
p_vs_holdover_zero: assert property (@(posedge clk) disable iff (!rst_n)
ptp_time_valid |=> (holdover_ns < 32'd16));
// 11. THE ONE THAT MATTERS. A latency claim is never published while
// the clock condition it depends on is unmet. Every property
// above holds throughout a PTP outage; this one does not.
p_vs_claim_gated: assert property (@(posedge clk) disable iff (!rst_n)
latency_claim_valid |-> bound_still_proven);
// 12. And the bound's proof is itself gated on the clock.
p_vs_bound_needs_clock: assert property (@(posedge clk) disable iff (!rst_n)
bound_still_proven |-> (ptp_time_valid || (holdover_ns < 32'd25_840_000)));
endmoduleClassification: ten local properties, one that crosses the boundary, and one that encodes Section 12's 25.8 milliseconds as a literal.
What it teaches: that properties 1 through 10 are exactly the set a reviewer would ask for and are exactly the set that cannot detect the chapter's worst failure. Every one of them is evaluated against the local cycle timer, which is internally perfect during a PTP outage. Reading the list and noticing that its coverage looks complete is the experience Section 20's rejected class is about.
And it teaches that property 12's literal — 25 840 000 nanoseconds — is the guard band divided by 200 ppm, which makes an arithmetic result from Section 12 into a checkable condition. It is the only number in the monitor that came from outside the node, and that is the point: a property about a distributed guarantee has to import something the node did not compute.
Deliberately simplified: property 12's constant is baked for the preempting band at 100 Mb/s and for the standard's worst-case ppm — it should be computed from the negotiated band and the servo's estimate, which makes it a function rather than a literal. Property 8 forbids transmission in a dead window rather than requiring the schedule to be rejected at installation, which is where the error should be caught. And there is no property about the aligned-streams case of Section 6, because no local signal expresses it.
Production implication: property 11 is the one to insist on in a specification and it is the one that gets negotiated away, because it constrains a reported figure rather than a behaviour. A supplier can honestly claim conformance to properties 1 through 10 on a port that publishes a latency bound throughout a synchronisation outage. Ask for property 11 explicitly, name the signal the claim is gated on, and require the holdover counter in the telemetry — otherwise the integrator inherits a bound whose premise nobody is checking.
17. Mixing Control Traffic With Sensor Streams
Section 2's traffic table put a 64-octet control frame and a 104 kB camera frame on the same link. This section is what the schedule has to do about a size ratio of four thousand.
The ratio, stated precisely.
| Control | Camera frame | Ratio | |
|---|---|---|---|
| payload | ≈ 46 to 100 octets | 104 167 octets | ≈ 1 000 to 2 300× |
| frames on the wire | 1 | 69 at 1 518 octets | 69× |
| serialisation at 100 Mb/s | 6.72 µs | 8.33 ms | 1 240× |
| period | 1 ms | 33.3 ms | — |
| duty | 0.67% | 25% | — |
Row three is the one the schedule has to reconcile. A camera frame is not one long transmission — it is 69 maximum-size Ethernet frames back to back, which matters because the blocking term is per frame rather than per camera frame. Preemption interrupts at frame granularity and also mid-frame, so the control traffic never waits for the burst; it waits for a fragment.
Row five is the reason the naive schedule fails. A 25% duty cycle sounds like there is plenty of room, but the camera's 8.33 milliseconds arrive contiguously, and Section 8's table says a 1 ms cycle with a 20% window offers the scheduled class 19.48% of the link. 19.48% of 100 Mb/s is 19.5 Mb/s, which is far more than the control class needs — and the camera's 25% has to fit in the remaining 80% of each cycle, which it does, at 80 Mb/s of capacity against 25 Mb/s of demand.
So the bandwidth arithmetic works comfortably and the burst arithmetic is what needs care.
| Per 1 ms cycle | |
|---|---|
| camera demand, averaged | 25 kbit = 3.13 kB |
| camera transmit capacity outside the window | 800 µs × 100 Mb/s = 10 kB |
| margin | 3.2× |
| camera frames deliverable per cycle | 6.6 at 1 518 octets |
| cycles needed for one 104 kB camera frame | 10.5 |
A camera frame takes about ten and a half schedule cycles to cross a 100 Mb/s link, which adds 10.5 ms to its own latency — irrelevant for a 30 fps stream with a tens-of-milliseconds budget, and it is a real number that a sensor-fusion deadline has to include.
And the schedule's structure follows.
| Window | Length of a 1 ms cycle | Carries |
|---|---|---|
| express | 200 µs | the control class, guard band included |
| everything else | 800 µs | camera, radar, diagnostics, best effort |
That is a two-window gate-control list and it is all a vehicle edge port needs, because Section 2's traffic table has exactly two kinds of thing on it: traffic with a hard deadline and traffic without one. Chapter 17.2 §3's gate-control list supports eight gates and many entries; a vehicle edge port uses two gates and two entries, and the complexity that chapter built for is spent at the zone controller's uplink, where fifty streams converge and Section 6's alignment problem needs per-stream windows.
Which gives the asymmetry worth designing to.
| Port | Schedule complexity | Why |
|---|---|---|
| sensor or actuator edge port | two windows | one stream, two classes |
| zone controller downlink | two windows | the same |
| zone controller uplink | many windows | fifty streams that align |
| central gateway port | many windows | four zones' worth |
Rows three and four are where the gate-control list's length is spent, and the list's length is what Section 19 prices. A design that sizes every port's schedule table for the uplink's worst case pays for it on hundreds of edge ports that need two entries.
18. What the Schedule Assumes
Seven premises, and the last three are the ones a data centre never has to examine.
| Assumption | If it is false |
|---|---|
| the clock is synchronised | Section 12 — the bound is void in 25.8 ms and nothing local notices |
| preemption is negotiated | Section 7 — the band is 23.5× larger and short windows deliver nothing |
| the frame size is bounded by the MTU | the guard band is wrong, and a jumbo frame makes it 6× wrong |
| streams do not align | Section 6 — fifty aligned streams are 336 µs of same-class queueing |
| the topology is three hops | a fourth hop adds 17.07 µs with preemption, 133.39 without |
| every node runs the same schedule | a node with a stale gate-control list transmits into another's window |
| the schedule was installed atomically | Chapter 17.2 §14's window nobody can close |
Row three deserves a number because jumbo frames keep being proposed for camera streams. Chapter 5.7 priced what a larger MTU buys; here it costs the guard band directly. A 9 000-octet uninterruptible frame at 100 Mb/s is 720 µs of guard band, against 121.488 for 1 518 — a factor of 5.9 — and the minimum viable cycle moves from 607 µs to 3.6 ms. With preemption the band does not move at all, because the uninterruptible unit is the fragment rather than the frame, so jumbo frames are free on a preempting link and catastrophic on a non-preempting one. That is a sharp, useful rule.
Row six is the assumption that has no local evidence and it is the twin of row one. A vehicle's nodes are programmed with a schedule at build time; a node flashed with an older software version has an older gate-control list. Every property in Section 16 passes at both nodes, both are internally correct, and they disagree about which microsecond belongs to whom. The detection is the same shape as Section 12's: something has to be imported from outside the node — a schedule version number, exchanged and compared.
Row seven is Chapter 17.2 §14's result carried into a vehicle without modification. That chapter showed a schedule change has an installation window that cannot be closed; in a vehicle a schedule change happens during a software update, with the vehicle stationary, so the window is a design-time concern rather than a runtime one — which is one of the very few places in this chapter where the automotive setting makes something easier.
And one assumption that is usually stated and rarely checked.
That the deadline the schedule was designed against is the deadline the control loop actually has.
Section 4's arithmetic answers whether a path fits a stated deadline. It says nothing about whether the deadline in the network design document matches the one in the control engineer's model — and those two documents are written by different teams, in different tools, at different times. The commonest real failure in automotive networking is not a mechanism failing; it is a number that was copied wrong, and no property in this chapter can detect it.
19. The Cost, Accounted
Priced against Chapter 19.7 §19's 14 166-flop MAC receive datapath, as every chapter in Modules 19 to 22 has been.
| Block | Flops | Share of 14 166 |
|---|---|---|
three_hop_accountant | 0 — combinational | — |
automotive_guard_band | 0 — combinational | — |
express_path_model | 64 | 0.5% |
vehicle_cycle_timer | 128 | 0.9% |
holdover_monitor | 97 | 0.7% |
vsched_telemetry | 295 | 2.1% |
vsched_conformance_monitor | 0 — assertions | — |
| this chapter's additions | 584 | 4.1% |
Four point one per cent, and it buys the detection of every failure in the chapter. That is an unusually good ratio and it is worth saying why: the mechanisms themselves — the gate-control list, the cycle timer's schedule table, the two MACs, the reassembly machine — were all priced in Module 17 and are not re-charged here. What this chapter adds is the instrumentation that makes those mechanisms safe in a setting where nobody is watching.
The mechanisms, from Module 17, for completeness.
| Mechanism | Priced in |
|---|---|
| the gate-control list and cycle timer | Chapter 17.2 §18 |
| preemption's six blocks | Chapter 17.3 §18 |
| the latency accountant | Chapter 17.1 §18 |
And the gate-control list's size, which Section 17 showed is where the real area goes.
| Port | Entries | Flops at 64 bits per entry | Against 14 166 |
|---|---|---|---|
| an edge port — two windows | 2 | 128 | 0.9% |
| a zone uplink — 50 streams | 50 | 3 200 | 22.6% |
| a central gateway — 200 streams | 200 | 12 800 | 90.4% |
| and each needs a shadow copy for atomic installation | ×2 | 25 600 | 180.7% |
Row four is the number that decides a switch's architecture. Chapter 17.2 §13's atomic installation needs two copies of the table, so a central gateway supporting two hundred scheduled streams carries 25 600 flops of schedule state — nearly twice an entire MAC receive datapath — and that is per port. In silicon it is a dual-ported RAM rather than registers, which is the same observation Chapter 21.9 §19 and Chapter 22.1 §19 both reached: once a mechanism's state scales with the number of things rather than with the design, flops stop being the right unit.
The useful comparison to close on.
| Flops | Buys | |
|---|---|---|
| this chapter's detection | 584 | every failure mode in the chapter, named |
| a 50-stream uplink schedule, with shadow | 6 400 | the separation Section 6 needs |
| Chapter 22.1's whole PHY front end | 2 323 | the link itself |
Row one against row three is the sentence to keep. The instrumentation that makes a vehicle's latency guarantee checkable costs a quarter of what the physical layer under it costs, and it is the part most likely to be cut.
20. Properties Worth Asserting, and One Worth Refusing
Six groups. Read them all and then notice that thirty-three of the thirty-four keep passing during the failure Section 12 describes.
Group A — the cycle timer.
// A1. The phase never reaches the cycle length.
p_vs_phase: assert property (@(posedge clk) disable iff (!rst_n)
cycle_phase_ns < (cycle_us * 1000));
// A2. A cycle start zeroes the phase.
p_vs_start: assert property (@(posedge clk) disable iff (!rst_n)
cycle_start |=> (cycle_phase_ns < 32'd16));
// A3. Cycle starts are exactly one cycle apart.
p_vs_period: assert property (@(posedge clk) disable iff (!rst_n)
cycle_start |-> ##1 (!cycle_start throughout
(cycle_phase_ns < (cycle_us*1000 - 32'd16))[*1:$]));
// A4. The cycle counter increments exactly once per start.
p_vs_count: assert property (@(posedge clk) disable iff (!rst_n)
cycle_start |=> (c_cycles == $past(c_cycles) + 1));
// A5. Holdover is zero whenever the clock is valid.
p_vs_hold_zero: assert property (@(posedge clk) disable iff (!rst_n)
ptp_time_valid |=> (holdover_ns < 32'd16));
// A6. Holdover only ever grows while the clock is invalid.
p_vs_hold_grows: assert property (@(posedge clk) disable iff (!rst_n)
!ptp_time_valid |=> (holdover_ns >= $past(holdover_ns)));Group B — the gates and the guard band.
// B1. No transmission starts with the gate closed.
p_gate_closed: assert property (@(posedge clk) disable iff (!rst_n)
tx_start |-> gate_open);
// B2. No transmission starts inside the guard band.
p_band_respected: assert property (@(posedge clk) disable iff (!rst_n)
tx_start |-> !in_guard_band);
// B3. The band is the uninterruptible frame plus the sync error.
p_band_value: assert property (@(posedge clk) disable iff (!rst_n)
band_ns_x10 == (serialise_ns_x10(L_UNINT, RATE_MBPS) + SYNC_ERROR_NS*10));
// B4. A window at or below the band delivers nothing.
p_dead_window: assert property (@(posedge clk) disable iff (!rst_n)
window_shorter_than_band |-> (usable_ns_x10 == 0));
// B5. The usable figure never exceeds the window.
p_usable_bounded: assert property (@(posedge clk) disable iff (!rst_n)
usable_ns_x10 <= window_ns_x10);
// B6. The minimum viable cycle scales with the band.
p_min_cycle: assert property (@(posedge clk) disable iff (!rst_n)
(window_pct != 0) |->
(min_viable_cycle_us == ((band_ns_x10 * 100) / (window_pct * 10000))));Group C — preemption.
// C1. Preemption requires both enable and verification.
p_pre_negotiated: assert property (@(posedge clk) disable iff (!rst_n)
preempt_now |-> (preemption_enabled && preemption_verified));
// C2. Only express classes preempt.
p_pre_express: assert property (@(posedge clk) disable iff (!rst_n)
preempt_now |-> ((6'b1 << express_class) & EXPRESS_SET) != 6'b0);
// C3. The minimum fragment is respected.
p_pre_min_frag: assert property (@(posedge clk) disable iff (!rst_n)
preempt_now |-> (preemptable_remaining_octets > 16'd60));
// C4. Enabled but unverified raises the flag.
p_pre_flag: assert property (@(posedge clk) disable iff (!rst_n)
(preemption_enabled && !preemption_verified) |-> band_assumption_broken);
// C5. The effective band follows the negotiated state, not the
// configured one.
p_pre_band_follows: assert property (@(posedge clk) disable iff (!rst_n)
!preemption_verified |->
(effective_band_ns_x10 == guard_band_ns_x10(L_MTU, RATE_EDGE_MBPS)));
// C6. Preempting and waiting are mutually exclusive.
p_pre_exclusive: assert property (@(posedge clk) disable iff (!rst_n)
!(preempt_now && must_wait));Group D — the latency accounting.
// D1. Store-and-forward equals serialisation for the same frame.
p_lat_sf: assert property (@(posedge clk) disable iff (!rst_n)
store_fwd_ns_x10_o == serialise_ns_x10_o);
// D2. The path is the hop times the hop count.
p_lat_path: assert property (@(posedge clk) disable iff (!rst_n)
path_ns_x10 == (per_hop_ns_x10 * HOPS));
// D3. The deadline verdict agrees with the arithmetic.
p_lat_verdict: assert property (@(posedge clk) disable iff (!rst_n)
deadline_met == (path_ns_x10 <= (deadline_us * 10000)));
// D4. Blocking uses the fragment when preempting and the MTU when not.
p_lat_block: assert property (@(posedge clk) disable iff (!rst_n)
blocking_ns_x10_o == serialise_ns_x10(
(PREEMPTION != 0) ? L_FRAGMENT : L_MTU_WIRE, RATE_MBPS));
// D5. The blocking share is a fraction of the hop.
p_lat_share: assert property (@(posedge clk) disable iff (!rst_n)
blocking_share_pct <= 16'd100);Group E — holdover severity.
// E1. Severity is zero exactly when the clock is valid.
p_sev_ok: assert property (@(posedge clk) disable iff (!rst_n)
ptp_time_valid |-> (severity == 3'd0));
// E2. Severity is monotone in holdover within one outage.
p_sev_monotone: assert property (@(posedge clk) disable iff (!rst_n)
(!ptp_time_valid && $past(!ptp_time_valid)) |->
(severity >= $past(severity)));
// E3. The worst-case drift is 200 ppm of elapsed holdover.
p_sev_drift: assert property (@(posedge clk) disable iff (!rst_n)
drift_worst_ns == ((holdover_ns / 1_000_000) * PPM_WORST));
// E4. The measured drift never exceeds the worst case.
p_sev_measured: assert property (@(posedge clk) disable iff (!rst_n)
servo_ppm_valid && (servo_ppm_abs <= PPM_WORST) |->
(drift_measured_ns <= drift_worst_ns));
// E5. The safety verdict uses the worst case, never the measured one.
p_sev_safety_conservative: assert property (@(posedge clk) disable iff (!rst_n)
bound_still_proven |-> (drift_worst_ns < band_ns));
// E6. The longest holdover is monotone across the vehicle's life.
p_sev_longest: assert property (@(posedge clk) disable iff (!rst_n)
c_longest_holdover_ns >= $past(c_longest_holdover_ns));Group F — telemetry.
// F1. A latency claim requires every caveat clear.
p_tel_claim: assert property (@(posedge clk) disable iff (!rst_n)
o_latency_claim_valid |-> (o_caveats == 4'b0));
// F2. The holdover fraction is cycles in holdover over total cycles.
p_tel_fraction: assert property (@(posedge clk) disable iff (!rst_n)
(snapshot && (i_cycles != 0)) |=>
(o_holdover_fraction_ppm ==
16'(($past(i_holdover_cycles) * 1_000_000) / $past(i_cycles))));
// F3. Holdover cycles never exceed total cycles.
p_tel_subset: assert property (@(posedge clk) disable iff (!rst_n)
o_holdover_cycles <= o_cycles);
// F4. A dead window sets its caveat.
p_tel_dead: assert property (@(posedge clk) disable iff (!rst_n)
snapshot |=> (o_caveats[3] == $past(i_window_shorter_than_band)));
// F5. Preemptions never exceed express transmissions.
p_tel_pre_bounded: assert property (@(posedge clk) disable iff (!rst_n)
o_preemptions <= o_cycles);Thirty-four properties. Thirty-three of them hold, continuously and correctly, throughout a total loss of network synchronisation. The exception is E5, and it holds only because Section 13 imported a number the node did not compute.
21. Verification Scenarios
Fifty-eight scenarios. Groups 4 and 5 are the ones a single-node testbench cannot express, and that is the chapter's point restated as a test plan.
Group 1 — latency accounting (10).
| # | Scenario | Expect |
|---|---|---|
| 1 | 1 518-octet frame, 100 Mb/s, three hops | 1 098.1 µs — misses a 1 ms deadline |
| 2 | the same at 1 Gb/s | 110.1 µs — 11% of the deadline |
| 3 | 64-octet express frame, no preemption | 133.39 µs per hop; blocking is 92.2% |
| 4 | the same with preemption | 17.07 µs per hop; blocking is 39.4% |
| 5 | a mixed path — 100 M, 1 G, 100 M | 35.94 µs, 30% better than the uniform model |
| 6 | a fourth hop added | +17.07 µs with preemption, +133.39 without |
| 7 | cut-through instead of store-and-forward | −5.12 µs per hop on a 64-octet frame |
| 8 | deadline_us = 0 | deadline_used_pct saturates; no divide by zero |
| 9 | path forced longer than the deadline | deadline_met low |
| 10 | blocking forced above the hop total | p_lat_share fires |
Group 2 — the guard band and the cycle (10).
| # | Scenario | Expect |
|---|---|---|
| 11 | 1 Gb/s, 250 µs cycle, 20% window, no preemption | 15.12% — reproduces Chapter 17.2 §8 |
| 12 | 1 Gb/s, 62.5 µs cycle | 0.49% — the same table's last row |
| 13 | 100 Mb/s, 1 ms cycle, no preemption | 7.85% |
| 14 | 100 Mb/s, 500 µs cycle, no preemption | 0.00% — window shorter than band |
| 15 | 100 Mb/s, 500 µs cycle, with preemption | 18.97% |
| 16 | cycle swept from 10 ms to 62.5 µs, no preemption | collapse at 607.4 µs |
| 17 | the same with preemption | collapse at 25.8 µs |
| 18 | a 9 000-octet MTU, no preemption | band 720 µs; minimum cycle 3.6 ms |
| 19 | the same with preemption | band unchanged at 5.168 µs |
| 20 | window_pct = 0 | min_viable_cycle_us saturates |
Group 3 — preemption (10).
| # | Scenario | Expect |
|---|---|---|
| 21 | express ready, preemptable mid-frame, 800 octets left | preempt_now |
| 22 | the same with 40 octets left | must_wait; up to 4.8 µs — the minimum fragment |
| 23 | preemption enabled, not verified | band_assumption_broken; band reverts to 121.488 µs |
| 24 | verification lost mid-operation | band changes with no schedule change — the hazard |
| 25 | a schedule built on 5.168 µs, run on 121.488 | every window under 121.5 µs delivers nothing |
| 26 | a non-express class with a frame in progress | no preemption — C2 |
| 27 | verification flapping every 10 ms | the band oscillates; nothing re-plans |
| 28 | preemption disabled locally, verified remotely | no preemption; the band is the MTU's |
| 29 | preempt_now and must_wait both forced | p_pre_exclusive fires |
| 30 | preempting a frame with 50 octets left | p_pre_min_frag fires |
Group 4 — holdover, which needs a second clock (12).
| # | Scenario | Expect |
|---|---|---|
| 31 | PTP valid throughout | severity 0; holdover 0 |
| 32 | one Sync message lost | severity 1 — a blip, no fault |
| 33 | PTP lost for 10 ms | severity 2 — warning; bound still proven |
| 34 | PTP lost for 30 ms | severity 3 — the bound is no longer proven |
| 35 | PTP lost for 1.2 s | severity 4 — transmissions may cross windows |
| 36 | PTP lost for 6 s | severity 5 — a different cycle from the neighbour |
| 37 | throughout scenarios 33–36 | every property in groups A–D still passes |
| 38 | servo reports 12 ppm, holdover 200 ms | measured drift 2.4 µs; worst case 40 µs |
| 39 | the safety verdict during 38 | uses the worst case — E5 |
| 40 | a servo estimate one hour stale | used anyway — the known hole |
| 41 | PTP recovers after 6 s | holdover zeroes; longest is captured |
| 42 | holdover entered and exited 50 times | c_holdover_entries = 50 |
Group 5 — two nodes, which a single-node testbench cannot do (8).
| # | Scenario | Expect |
|---|---|---|
| 43 | two nodes, synchronised, same schedule | windows align; no cross-window transmission |
| 44 | node A in holdover 30 ms, node B synchronised | A's window has drifted 6 µs past B's guard band |
| 45 | the same at 5 s | A transmits inside B's scheduled window |
| 46 | both nodes in holdover, same direction | they stay aligned with each other and not with the rest |
| 47 | node A on schedule version 3, node B on version 4 | both locally correct; they disagree about the windows |
| 48 | an exchanged schedule version number | the disagreement is detected in one comparison |
| 49 | p_peers_agree with a peer timestamp | fires at scenario 44's 30 ms mark |
| 50 | the same property without a peer | not evaluable — which is the finding |
Group 6 — traffic and the schedule's shape (8).
| # | Scenario | Expect |
|---|---|---|
| 51 | a 25 Mb/s camera at 30 fps on a 100 Mb/s link | 8.33 ms bursts; 10.5 cycles per camera frame |
| 52 | a control frame arriving mid-burst, FIFO | up to 8.33 ms — eight deadlines |
| 53 | the same with strict priority | 123.04 µs per hop |
| 54 | the same with preemption | 6.72 µs per hop |
| 55 | 50 control streams, randomly phased | mean wait small; worst case still 336 µs |
| 56 | 50 control streams, all started at power-on | aligned; 336 µs every period, forever |
| 57 | the same with per-stream windows | separated — and the gate list is 50 entries |
| 58 | a 200-entry gate list with a shadow copy | 25 600 flops — 180.7% of a MAC datapath |
Scenario 37 is the one to run and read carefully, and scenario 50 is the one that cannot pass.
The directed test random stimulus will not produce
This test requires a network-wide failure and a locally perfect node, simultaneously, and it requires two nodes to express at all.
The arrangement:
| Step | Action |
|---|---|
| 1 | two scheduled ports, 100 Mb/s, 1 ms cycle, 20% window, preemption verified |
| 2 | both synchronised; the schedule runs correctly for 10 seconds |
| 3 | node A's PTP input is removed — the grandmaster is not reachable |
| 4 | node A's local oscillator is set 150 ppm fast; node B's is nominal |
| 5 | the run continues for 6 seconds of holdover |
| 6 | node A's full property set from Section 20's groups A–D is checked every cycle |
Random stimulus will not produce this for two reasons and the second is the interesting one. The first is mechanical: a randomised environment does not usually model two independent clock sources with a controlled frequency offset, because a testbench's clock is one clock. The second is that there is no failure to randomise toward. Node A is behaving correctly by every local definition; there is no illegal transition, no protocol violation, no out-of-range value, and no assertion to trip. A constrained-random generator directed at coverage of node A's state space reaches every state, including all of these, and reports full coverage of a node that has stopped working.
The oracle is in four parts and three of them are expected passes.
| Part | Signal | Required value | Why alone it is not enough |
|---|---|---|---|
| 1 — the node is locally perfect | groups A, B, C, D | all pass, every cycle | this is the failure, not the health |
| 2 — the jitter improves | measured cycle-to-cycle variation | lower than when synchronised | a free-running counter is more regular than a servo |
| 3 — the condition is visible | holdover_ns, severity | rising; reaches 5 at 5 s | only if something reads it |
| 4 — the peers have diverged | p_peers_agree | fires at 34.5 ms | needs node B; this is the finding |
Part 2 is the assertion that makes the test memorable. Require that node A's measured cycle jitter is lower during holdover than during synchronised operation — it will be, because a disciplined clock is continuously corrected and a free-running one is not — so every quality metric a local monitor computes gets better as the network-wide guarantee is destroyed. A test that passes on part 2 has demonstrated that local metrics are not merely insufficient, they point the wrong way.
Part 4 is computed from node B's cycle start and node A's. At 150 ppm relative the 5.168 µs band is consumed in 34.5 ms, and p_peers_agree fires there. Run the identical test with node B removed and part 4 simply cannot be written, which is the demonstration the chapter exists to make: one node's testbench can reach 100% coverage of a node whose guarantee is void.
22. Debugging a Vehicle Schedule
A procedure, and the first three steps are about the clock because the mechanisms below it are almost never what failed.
| Step | Do | Because |
|---|---|---|
| 1 | read holdover_ns, severity and c_longest_holdover_ns | Section 12 — the bound is void in 25.8 ms and nothing else says so |
| 2 | read o_holdover_fraction_ppm | an intermittent outage is invisible in a snapshot |
| 3 | read the servo's offset and its age | Chapter 16.4 §5 already knows |
| 4 | read preemption_verified and band_assumption_broken | a 23.5× band change with no schedule change |
| 5 | read window_shorter_than_band | a window that delivers nothing looks exactly like a link that is idle |
| 6 | compare the two ends' schedule version numbers | Section 18's row six has no local evidence |
| 7 | only now look at the gate-control list | it is almost always correct |
| 8 | check the deadline in the network design against the control model's | Section 18's last assumption, and the commonest real fault |
Step 7 being seventh is the inversion worth internalising. The gate-control list is static data, generated by a tool, verified offline; it is the least likely thing in the system to be wrong. The clock, the negotiated band and the two nodes' agreement are all runtime properties with no local detector, and they are where the failures are.
Four signatures.
| Signature | Cause |
|---|---|
| control deadline missed, every local property passing, jitter improved | holdover — Section 12 |
| control traffic stopped entirely, gates cycling normally | window shorter than the band — preemption not verified |
| occasional collisions in a scheduled window | the two ends disagree about the schedule or about time |
| deadline missed under load only, clock healthy | Section 6's aligned streams — the express class interfering with itself |
Row one's third clause is the diagnostic. Jitter that improves while a deadline is missed is a positive indication of holdover, because a free-running timer is more regular than a servo-corrected one. It is the only signature in this track where a metric getting better is evidence of a fault, and it is worth remembering for that reason alone.
Row four is the one that is most often misdiagnosed as a capacity problem. Fifty aligned control streams produce 336 µs of same-priority queueing on every period; the link is at 33.6% utilisation and looks comfortable, and adding bandwidth does not help because the problem is not bandwidth — it is that fifty periodic streams that started together stay together. The fix is per-stream windows or per-stream shaping, and it makes the gate-control list fifty entries long.
23. Misconceptions
Six, in wrong-model / what-it-costs / corrected-model form.
Misconception 1 — "TSN works, so it works in a car."
Wrong model: the mechanisms are rate-independent; a vehicle just runs them slower.
What it costs: the schedule. Section 8: at 100 Mb/s the guard band is 121.488 µs, so with a 20% window no cycle shorter than 607.4 µs delivers the scheduled class any bandwidth at all. A vehicle's control loops want cycles of 1 ms and faster; the mechanism as deployed at 1 Gb/s simply cannot express them.
Corrected model: everything scales with the line rate except the 48 nanoseconds of synchronisation error, and at 100 Mb/s the band is 99.96% frame. So the only lever is shrinking the uninterruptible frame, which is preemption — and Section 10's four independent results all point the same way.
Misconception 2 — "strict priority already protects the control traffic from the camera."
Wrong model: put control in the highest class and the 8.33 ms camera burst cannot delay it.
What it costs: half the problem, solved. Strict priority genuinely turns an 8.33 ms FIFO wait into 123.04 µs per hop, and with preemption into 6.72 µs. That part is correct.
Corrected model: priority bounds interference from below and says nothing about interference from beside. Fifty control streams converging on a zone uplink are 336 µs of same-priority queueing, and they are worse than random because periodic streams started by the same power-on event align and stay aligned. Chapter 17.1 §11 named same-priority queueing as one of the two unbounded terms; this is it, and a schedule with per-stream windows is what bounds it.
Misconception 3 — "a faster clock makes the guard band smaller."
Wrong model: the band is dominated by synchronisation error, so better sync is the lever.
What it costs: an engineering programme spent on the wrong term. Chapter 17.3 §16 showed the sync term reaching 89.4% of the band at 100 Gb/s, which makes this true there. At 100 Mb/s the same 48 nanoseconds is 0.04% of a 121 488-nanosecond band.
Corrected model: the sync term is absolute and everything else scales with the rate, so its share rises with rate and falls with slowness. At automotive rates the clock's contribution to the band is negligible — and Section 12 shows the clock matters enormously anyway, for a completely different reason: not the band's size, but what happens when the clock is gone.
Misconception 4 — "the schedule is correct, so the latency bound holds."
Wrong model: a verified gate-control list, a verified cycle timer and a verified eligibility check together prove the bound.
What it costs: the bound, silently. Section 12: a node that loses PTP free-runs, and thirty-three of Section 20's thirty-four properties keep passing throughout — with the measured jitter improving, because a free-running counter is more regular than a disciplined one. The bound is void 25.8 milliseconds in and the node's own verification says everything is perfect.
Corrected model: the guarantee is a relation between nodes and every local property is a statement about one node. The bound holds only while the clock condition holds, so the claim must be published together with ns_since_ptp_update — which costs 32 flops — and the only property that states the real guarantee needs a peer's timestamp.
Misconception 5 — "preemption is an optimisation we can drop to save area."
Wrong model: Chapter 17.3's six blocks buy bandwidth back, and bandwidth is not tight here.
What it costs: schedulability. Section 10's results: the three-hop express worst case goes from 51.2 µs to 400.2 µs, the shortest usable cycle from 25.8 µs to 607.4 µs, and the usable link at a 1 ms cycle from 19.48% to 7.85%. Add Section 6's 336 µs of same-priority queueing and the non-preempting budget is 736 µs of a 1 ms deadline before any margin.
Corrected model: in a data centre preemption recovers bandwidth; in a vehicle it is what makes a fast control period expressible at all. And because it is negotiated — Chapter 17.3 §13's handshake — losing it at run time changes the band by 23.5× with nothing re-planning, which is why Section 14 makes loss of verified preemption a reportable fault rather than a degraded mode.
Misconception 6 — "a single-node testbench that reaches full coverage has verified the port."
Wrong model: cover every state of the scheduled port and the port is verified.
What it costs: the entire failure class this chapter is about. Scenario 37: during a six-second synchronisation outage every state is reachable, every property passes, and coverage is complete — on a node that is transmitting into its neighbour's window.
Corrected model: coverage is a measure over the node's state space and the guarantee lives in the network's. The tests that matter are group 5's, they need two nodes with independent clocks, and one of them — p_peers_agree — cannot even be written in a single-node environment. That is Chapter 21.9 §6's two-point argument arriving for the third time: when a guarantee spans two places, one place cannot check it.
24. Interview Questions
Six, with what a strong answer contains.
1. Why does time-aware shaping get harder at 100 Mb/s than at 1 Gb/s?
Because the guard band is the uninterruptible frame, and the frame's duration scales with the rate. 1 518 octets is 12.192 µs at 1 Gb/s and 121.488 µs at 100 Mb/s, and the band is subtracted from every window in every cycle. A strong answer gives the consequence: with a 20% window no cycle below 607.4 µs delivers the scheduled class anything, and adds the counterintuitive half — the synchronisation term does not scale, so it falls from 89.4% of the band at 100 Gb/s to 0.04% here.
2. Strict priority bounds the camera's interference. What does it not bound?
Interference from the same class. Chapter 17.1 §11's two unbounded terms are interference from higher priorities and queueing among equals; priority fixes the first and not the second. A strong answer quantifies it — fifty 84-octet control streams at 100 Mb/s are 336 µs of same-priority queueing — and names the aggravating factor: periodic streams started by a common power-on event align and stay aligned, so the worst case is the normal case.
3. Your node loses PTP. What does its own verification tell you?
That everything is perfect, for as long as you care to look. The local cycle timer free-runs, the gates open exactly as programmed, the band is subtracted correctly, and the measured jitter improves, because a free-running counter is more regular than a servo-corrected one. A strong answer gives the timeline — the guard band is consumed in 25.8 ms at 200 ppm, a 200 µs window in one second, a whole 1 ms cycle in five — and names the only detector: time since the last servo correction, which costs 32 flops and which the servo already computes.
4. Preemption is negotiated. Why does that matter for a schedule computed offline?
Because the schedule was computed against a band that assumes it. With preemption the band is 5.168 µs; without, 121.488 µs — a factor of 23.5 — and every window shorter than 121.488 µs then delivers nothing. A strong answer notes that nothing re-plans: Chapter 17.2 §13's atomic installation exists for schedule changes, and a band change caused by a partner's handshake failing is not a schedule change. The correct behaviour is to treat it as a fault.
5. Would jumbo frames help a vehicle's camera stream?
It depends entirely on preemption, and the dependence is total. Without preemption a 9 000-octet uninterruptible frame at 100 Mb/s is a 720 µs guard band against 121.488 — a factor of 5.9 — and the minimum viable cycle moves from 607 µs to 3.6 ms, which no vehicle control loop can live with. With preemption the band does not move at all, because the uninterruptible unit is the fragment. A strong answer states the rule: jumbo frames are free on a preempting link and catastrophic on a non-preempting one.
6. What can a single-node testbench never verify here?
That two nodes agree which microsecond is which. Every property about a scheduled port is evaluated against the node's own clock, so all of them hold during a total loss of network synchronisation. A strong answer names what has to be imported — a peer's cycle timestamp, or a schedule version number exchanged and compared — and generalises: when a guarantee is a relation between two places, one place cannot check it, which is the same conclusion Chapter 21.9 §6 reached about captures and Chapter 20.6 §4 reached about scoreboards.
25. Questions and Answers
26. What's Next
The vehicle's link and its schedule are both done. What remains is the traffic that justified the whole exercise.
| This chapter established | |
|---|---|
| per-hop bounded latency at 100 Mb/s | 366.03 µs — three hops miss a 1 ms deadline |
| the guard band | 121.488 µs, of which 0.04% is the clock |
| the shortest usable cycle | 607.4 µs, or 25.8 with preemption |
| preemption's status | mandatory, and negotiated, and therefore losable |
| holdover's cost | the band in 25.8 ms, a cycle in 5 s |
| what local verification covers | everything except the guarantee |
Chapter 22.3 takes the traffic. A camera at 25 Mb/s and 30 frames per second was this chapter's illustration; an ADAS sensor suite is eight to twelve of them, plus radar, plus lidar, and the aggregate is what moved automotive networking to Ethernet in the first place. The questions are volume — what a sensor set actually produces and what link rate it needs — latency, because a fusion deadline is a chain of sensor, transport, compute and actuation, and synchronisation, because fusing two sensors requires knowing when each sample was taken to a precision this chapter has already shown is fragile.
Continue learning
Related tutorials
- Related topic
What Determinism Requires
Five of a hop's seven latency terms are bounded and sum to 37 microseconds. The other two have no bound at all, and no amount of engineering gives them one.
- Related topic
Time-Aware Shaping (802.1Qbv)
A schedule turns an unbounded interference term into a configuration parameter, and then spends up to 19.5% of the cycle on a guard band to stay safe.
- Related topic
Frame Preemption (802.1Qbu / 802.3br)
Interrupting a frame in flight takes the guard band from 12.192 to 0.560 microseconds, and gives Chapter 6.3's FCS checker a case it was never designed for.
- Related topic
Backpressure and Head-of-Line Blocking
Every queue is work-conserving, every link runs at line rate, every switch is non-blocking — and the composition delivers 58.6% of capacity. The bound has been known since 1987.
Standards & specifications
- Governing standard
- IEEE Std 802.3 (Ethernet)(opens IEEE in a new tab)
Defines the Ethernet MAC, the media-independent interfaces and the physical-layer sublayers, including framing, access control, auto-negotiation and per-rate PHY specifications. VLAN tagging, priority and time-sensitive shaping are defined by IEEE 802.1, not by 802.3.
This page also covers RTL structure, verification approach and debugging technique. Those are engineering practice built on the standard, not requirements the standard itself imposes.
Where this fits
Part of the Ethernet curriculum.
