USB · Module 3
The D- Line
The chapter where J stops being a voltage. A low-speed device biases the other conductor, so its idle polarity is reversed — and because idle is named J at both speeds, J is a different physical polarity at low speed than at full speed. What that forces on a decoder, and the latent bug it creates.
Chapter 3.3 qualified every statement it made with for a full-speed device. This chapter removes the qualification, and the answers change.
The result is the single most important fact in USB's physical layer, and the one most often taught wrongly:
J and K are names for the idle state and its opposite. Which physical polarity is J depends on the operating speed. At low speed it is the reverse of full speed.
Everything in this chapter follows from that, including a latent RTL bug that is correct on the engineer's desk and wrong for half the devices in the world.
1. The Other Conductor, the Other Speed
D- is the second conductor of the pair. As half of the differential measurement it is interchangeable with D+, exactly as Chapter 3.2 established.
Its static role is the mirror of D+'s, and the mirror is the point. Where a full-speed device presents its pull-up on D+, a low-speed device presents its pull-up on D-.
That single difference is how the interface carries speed information before any communication exists. The host's downstream port holds both conductors low through its pull-downs; whichever conductor rises when a device attaches tells the host which kind of device arrived. Chapter 3.7 owns the detection procedure; what matters here is the consequence for the line states.
2. Idle Is J — Whichever Conductor Makes It
Follow the consequence carefully, because it is a two-step argument and skipping either step is how the misconception forms.
Step one. A device's pull-up determines the resting condition of the pair. Full speed: D+ high, D- low. Low speed: D- high, D+ low. These are opposite differential polarities.
Step two. In both cases, that resting condition is the idle state, and the idle state is named J.
Put the two together and the conclusion is forced:
At full speed, J is D+ higher. At low speed, J is D- higher. Same name, opposite polarity. And K, being the other signalling state, inverts with it.
| Full speed | Low speed | |
|---|---|---|
| Device pull-up on | D+ | D- |
| Idle condition | D+ higher | D- higher |
| Named | J | J |
| K is therefore | D- higher | D+ higher |
| SE0 | both low | both low |
| SE1 | both high — illegal | both high — illegal |
Read the table by row. The first two rows differ, the third is identical, and the fourth differs because the first two do. SE0 and SE1 do not invert, because they are defined by both conductors being in the same state rather than by a polarity — which is a useful asymmetry and one reason those conditions are reliable regardless of speed.
3. The Same Waveform, Two Readings
This figure is the chapter in one picture: an identical sequence of physical conditions, decoded twice.
Identical conductor behaviour decoded at full speed and at low speed
6 cycles4. The Latent Bug
Now the practical consequence, which is why this chapter is worth its length.
Chapter 3.1's decoder named J when D+ was the higher conductor. Its header says so explicitly — it assumes full speed. Written without that awareness, the same three lines are a latent bug:
It works on the engineer's desk. Full-speed devices are the common case in development, and against them the decoder is correct.
It fails silently on low-speed devices. Not with an error — with inverted J and K. Everything downstream that depends on distinguishing the two sees a consistent, plausible, wrong answer, and there is no illegal condition to trip an error flag because both J and K are entirely legal states.
And the symptom appears far from the cause. Nothing complains at the line-state layer. The failure surfaces wherever J and K are first interpreted, which is well downstream, so an engineer investigating starts at the wrong end and finds logic that is working correctly on inputs that were wrong before they arrived.
The fix is structural rather than a correction. The decoder must know the port's operating speed, which means the speed must be an input to the decode rather than an assumption inside it.
5. Generalising the Decoder
// ─────────────────────────────────────────────────────────────────────────
// jk_name
//
// Classification: CONCEPTUAL RTL — the speed-dependent half of PHY-side
// line-state naming. Synthesizable, trivially small, and the point is the
// INPUT LIST rather than the logic.
//
// WHAT IT MODELS. The mapping from a differential polarity observation to
// the J / K names, given the port's operating speed. It generalises the
// full-speed-only assumption in Chapter 3.1's line_state_decode.
//
// WHAT IT DOES NOT MODEL. Anything analog; how the speed was determined
// (Chapter 3.7); how the port came to be operating at that speed at all;
// high-speed operation, whose termination and signalling differ from the
// model used throughout this module; encoding; packet structure.
//
// NOTE ON HIGH SPEED. This block covers the low-speed / full-speed naming
// question only. High-speed operation changes the electrical arrangement
// substantially -- see Chapter 3.7 -- and is not represented by a simple
// polarity inversion.
// ─────────────────────────────────────────────────────────────────────────
module jk_name (
// Differential observation: is D+ the higher conductor this cycle?
input logic diff_dp_hi,
// The PORT's operating speed. Not a property of the decoder, not a
// compile-time constant, and not something to guess: a host port's speed
// is established by the detection sequence of Chapter 3.7 and can differ
// from one port to the next in the same design.
input logic low_speed,
// Valid only while the pair is genuinely signalling. During SE0 and SE1
// neither name applies, so the caller must qualify with the line state
// from Chapter 3.1 rather than trusting these outputs unconditionally.
output logic is_j,
output logic is_k
);
// Full speed : idle is D+ higher, and idle is named J.
// Low speed : idle is D- higher, and idle is STILL named J.
// So the polarity that earns the name J inverts with the speed, and the
// whole of this module is that one inversion made explicit.
assign is_j = low_speed ? ~diff_dp_hi : diff_dp_hi;
assign is_k = ~is_j;
endmoduleWhat it models. One inversion, and the fact that it is conditional on a runtime input.
Why the structure exists. low_speed is a port, not a parameter. Making it a parameter would bake the speed into the elaborated design, which is wrong for a host port that must serve whatever is plugged into it, and it would also hide the dependency — a parameter looks like configuration while a port looks like information the block needs continuously. The comment about qualification exists because is_j and is_k are meaningless during SE0 and SE1, and outputs that are meaningless under some conditions must say so or they will be believed under all conditions.
Hardware implied. An XOR and an inverter. The teaching content is entirely in the interface.
State retained. None — it is combinational by design, because the naming question has no history in it. The speed has history, but that history belongs to the detection logic of Chapter 3.7, not here.
What DV should verify. That the mapping inverts with low_speed — which means the environment must run the same stimulus at both speeds and check that the naming reverses, since a test at one speed cannot distinguish this block from a hard-coded one. That is the single most important check here and the one a single-speed regression structurally cannot perform.
What it deliberately omits. How speed was determined, high-speed operation, and everything analog.
6. Verification: the Test a Single-Speed Regression Cannot Run
This chapter produces an unusually clean verification lesson, because the bug in §4 has a precise signature: it is invisible to any test that runs at one speed.
A full-speed regression against a full-speed-only decoder passes completely. Every line state is correct, every downstream check passes, coverage of J, K, SE0 and SE1 is closed. The defect is not a corner case within the tested space; it is entirely outside it.
The stimulus dimension that matters is therefore speed itself, and it must be crossed with everything else. Running the full signalling suite at full speed and separately at low speed is not the same as running it once — and an environment whose device model has a fixed speed has silently made that dimension a constant.
Representative coverage dimensions — not a verification plan:
- each line state reached, crossed with each operating speed
- J-to-K and K-to-J transitions at both speeds
- SE0 entered from J and from K, at both speeds
- a port that operates at different speeds across successive attachments, which is the case a static configuration never produces
The assertion worth writing is a relation rather than a value, because a value assertion would have to encode the very convention under test:
// ─────────────────────────────────────────────────────────────────────────
// Classification: TEACHING ASSERTION for the naming relation. It expresses
// the SPEED DEPENDENCE itself, which is what a single-speed test cannot
// reach. It is not a USB compliance check.
// ─────────────────────────────────────────────────────────────────────────
// N1 -- the names are complementary while signalling. If both or neither
// were asserted, downstream logic distinguishing them would be reading
// nonsense.
property p_j_k_complementary;
@(posedge clk) disable iff (!rst_n)
(line_state == LS_J || line_state == LS_K) |-> (is_j ^ is_k);
endproperty
assert property (p_j_k_complementary);
// N2 -- THE ONE THAT MATTERS. For one and the same differential
// observation, the name assigned at low speed must be the OPPOSITE of the
// name assigned at full speed. Written as a relation between the inputs,
// so it holds without restating the convention it is checking -- and so it
// fails immediately against a decoder that ignores `low_speed`.
property p_naming_inverts_with_speed;
@(posedge clk) disable iff (!rst_n)
is_j == (low_speed ^ diff_dp_hi ^ 1'b1);
endproperty
assert property (p_naming_inverts_with_speed);N2 is the assertion that catches §4's bug, and it does so in a single-speed simulation as soon as low_speed is driven high, because it constrains the relationship rather than checking a table of expected outputs. A decoder that ignores low_speed violates it the first time the input is asserted.
7. Debugging an Inversion
The inverted-naming failure has a characteristic and recognisable shape, and knowing it saves a great deal of time.
It is deterministic, not statistical. Unlike Chapter 3.2's analog degradation, this fails the same way every time, on every unit, and reproduces in simulation given the same stimulus. That alone places it in the digital domain.
It correlates with the attached device, not the cable. Swap in a full-speed device and the problem disappears; swap back and it returns. That correlation points at speed rather than at any physical property.
Nothing reports an error at the line-state layer, because J and K are both entirely legal. There is no illegal condition, no violated invariant, no flag — which is exactly why an engineer watching for errors sees none and concludes the physical layer is healthy.
And the observation that settles it is a comparison across abstraction levels. Capture the conductors and, separately, capture the decoded line state. If the conductors show D- higher and the decode reports J while the port is operating at low speed, the decode is correct; if it reports K, the speed input is wrong or absent. That two-point comparison is the physical layer's most reliable debugging move, and this module keeps returning to it because it keeps working: an error localised between two observation points is an error in the transformation between them.
8. Common Misconceptions
9. Reason It Through
A host design works correctly with every full-speed device tested. A low-speed keyboard is attached. The port detects the attachment and reports the correct speed, but communication never succeeds. Line-state monitoring shows legal states throughout, with no illegal conditions and no error flags.
What has the evidence already ruled out? Attachment and detection — Chapter 3.3 §5's partition says the port left SE0 and the device was noticed, and the speed was reported correctly, so the biasing and the detection sequence both worked. It has also effectively ruled out the analog layer, since the failure is deterministic and device-correlated rather than statistical.
Why is “legal states throughout, no errors” the most informative clue? Because an inversion produces exactly that. J and K are both legal, so exchanging them violates nothing observable at the line-state layer. A monitor watching for illegal conditions is structurally incapable of seeing this fault, and its silence is therefore not evidence of health.
What is the likely cause? The decode is naming J and K by the full-speed convention while the port is operating at low speed. The speed was detected correctly — that is reported — but it is evidently not reaching the naming logic, which is a different thing and a common one: information determined in one block and never plumbed to the block that needs it.
What confirms it in one measurement? Compare the conductors against the reported line state during idle. At low speed the port should rest with D- higher and report J. If it rests with D- higher and reports K, the naming is inverted and the diagnosis is complete.
What is the general lesson? A fault that produces only legal outputs is invisible to legality checking, and needs a check on relationships instead — which is precisely why assertion N2 constrains the mapping's dependence on speed rather than checking a table of expected states.
10. Understanding Check
11. Summary
J and K are names for the idle state and its opposite, and their physical polarity depends on the operating speed.
The mechanism is a two-step consequence. A full-speed device biases D+ and a low-speed device biases D-, so the pair rests at opposite polarities in the two cases. In both cases that resting condition is the idle state and is named J. Therefore J is D+ higher at full speed and D- higher at low speed, and K inverts with it. SE0 and SE1 do not invert, because they are defined by both conductors sharing a state rather than by a polarity.
This creates a specific latent bug: a decoder that names J when D+ is higher is correct at full speed, silently inverted at low speed, and reports only legal states either way — so nothing flags it, and the symptom surfaces far downstream where J and K are first interpreted. The fix is structural: operating speed must be an input to the naming logic, a port rather than a parameter, because a host port serves whatever is attached and that changes between attachments.
For verification, the defect is invisible to any single-speed regression — it lies outside the tested space rather than in a corner of it — so speed must be a crossed dimension. The assertion that catches it constrains the relationship between polarity, speed and name rather than checking expected values, because a value check would encode the convention under test.
For debug, the fault is deterministic and device-correlated, reports no errors because both states are legal, and is settled by one comparison across abstraction levels: at low speed the port should idle with D- higher and report J.
12. What Comes Next
Three chapters have now leaned on the pull-up without examining it. It has determined the idle polarity, announced the device's presence, and carried the speed information that §5's decoder needs — a great deal of work for one resistor.
Chapter 3.5 takes the mechanism itself: why biasing is the right tool for announcing something before communication exists, what the resistor actually does against the host's opposing pull-down, why the value matters, and what it means that a device can choose when to present it — which turns a static announcement into something a device can use deliberately.
Browse the full path on the USB tutorials index.
Continue learning
Related tutorials
- Related topic
The Parallel Port
Why presenting eight data lines at once forces an explicit data/strobe/acknowledge handshake, what that costs in timing discipline, a synthesizable teaching FSM that implements it with the assertions that protect it, and why an interface shaped around one peripheral's operational model cannot generalise.
- Related topic
PS/2 Keyboard / Mouse
The dedicated input port where the device supplies the clock and the host receives on someone else's timing. The two-wire open-drain bus, the framed byte, why sampling a foreign clock directly is a real hardware bug, and a synthesizable teaching receiver with its synchroniser, recovery timeout and assertions.
- Related topic
The USB Device
What is left when every decision belongs to the host: the responder discipline, why a device must answer even when it has nothing to say, the split between the USB-facing device controller and the function it exists to provide, and a teaching abstraction with the assertion that protects the ownership model.
- Related topic
The Root Hub
Where the tree begins: a hub that is architecturally ordinary and structurally unique, living inside the host controller and managed through its registers rather than addressed on the bus. The place bus events first become software-visible, with a teaching register block covering synchronisation, sticky status and clear semantics.
Standards & specifications
- Governing standard
- USB-IF (Universal Serial Bus Specification)(opens USB Implementers Forum (USB-IF) in a new tab)
Defines the USB bus — its electrical signalling, connectors, packet and transaction model, device framework and the descriptors a device must expose — together with the device-class specifications layered on it. It does not define host-controller register interfaces (xHCI and EHCI are separate documents) nor any operating system's driver architecture.
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 USB curriculum.
