lpddr4 module#
LPDDR4#
Port bundles and a signal-integrity constraint for a point-to-point LPDDR4 link between a controller and one memory device.
Source and scope#
The defaults in LPDDR4ConstraintParams are Table 2, “LPDDR4
without ECC Skew Constraints”, in AMD UG583, UltraScale Architecture PCB
Design User Guide, section “LPDDR4 without ECC Length and Skew Constraints”,
https://docs.amd.com/r/en-US/ug583-ultrascale-pcb-design/LPDDR4-without-ECC-Length-and-Skew-Constraints.
That table is written for the Zynq UltraScale+ MPSoC processing system (PS)
driving one LPDDR4 device without ECC; for any other controller, check its
own layout guide.
CK_t to CK_c: 2 ps (applied as +/-2 ps)
DQS_t to DQS_c: 2 ps (applied as +/-2 ps)
Address/command/control to CK: +/-8 ps (applied to CKE, CS and CA0 to CA5)
DQ and DM to DQS: +/-5 ps (applied to DQ and DMI)
CK to DQS: -500 ps to +2500 ps, as CK delay minus DQS delay. Table 2’s note sends skew to items 3 to 8 of UG583’s General Memory Routing Guidelines, whose CK-to-DQS example subtracts the DQS delay from the clock delay. On jitx 4.6,
ConstrainReferenceDifference(guide, target)measures guide delay minus target delay (checked on a code-routed pair), so CK is the guide.DQ and DM, slowest to fastest: 5 ps. The constraint holds each DQ within +/-2.5 ps of DMI, which keeps any two of them within 5 ps; it is stricter than the rule for DMI against a DQ, since UG583 allows DMI anywhere inside the 5 ps spread.
Table 2’s note also says: “FPGA package flight times must be included in
both total length constraints and skew constraints … Memory device
package flight times do not need to be factored in.” The design-issue
report counts a package’s delay only where its pins carry a
TerminatingPinModel, so give the controller’s pins one
from its package delay data (UG583 asks for the midrange where a minimum
and maximum are given), and leave the memory’s pins without one. The
controller in lpddr4_example is fictional and has none.
UG583 also sets maximum lengths (its Table 1), which this module does not
apply, and excludes reset_n from the skew rules. It gives no insertion-loss
limit and no impedance target, so the module sets neither by default: pass
loss in the parameters to add a loss limit, and pass the routing
structures from the board’s substrate.
Use#
Net the controller’s bundle to the memory’s bundle with an ordinary net and apply the constraint to the same two bundles:
self.link = self.controller.lpddr4 + self.memory.lpddr4
self.si = LPDDR4Constraint(diff_structure=..., se_structure=...)
self.si.constrain(self.controller.lpddr4, self.memory.lpddr4)
A controller that drives one CKE per channel for both ranks of an x32
dual-rank memory (the dual-rank VMK180 and VPK120 boards map their LPDDR4
interfaces this way) offers LPDDR4SharedCKE instead. Net its one
CKE to both of the memory channel’s CKE balls and pass it as the controller side:
LPDDR4Constraint.constrain() holds each of those balls against CK.
Set spread_dq to None for a layout guide with no DQ spread rule.
The issue report measures a constraint only once the path between its two ends
is routed. lpddr4_example is not routed.
- class LPDDR4Width(*values)[source]#
Bases:
EnumLPDDR4 interface width: the number of x16 channels times 16.
- x16 = 16#
One x16 channel
- x32 = 32#
Two x16 channels
- x64 = 64#
Four x16 channels
- num_x16_channels(width)[source]#
Return the number of x16 channels in an interface of this width.
- Return type:
- Parameters:
width (LPDDR4Width)
- class LPDDR4Rank(*values)[source]#
Bases:
EnumLPDDR4 rank count: the number of CKE and CS signals per channel.
- Rank1 = 1#
Single rank
- Rank2 = 2#
Dual rank
- class LPDDR4Lane[source]#
Bases:
PortOne LPDDR4 byte lane: eight DQ, one DQS pair and one DMI.
- dq = [Port(), Port(), Port(), Port(), Port(), Port(), Port(), Port()]#
Data bits
- dqs = DiffPair()#
Data strobe (
pis DQS_t,nis DQS_c)
- dmi = Port()#
Data mask and inversion
- class LPDDR4Channel(rank)[source]#
Bases:
PortOne LPDDR4 x16 channel: two byte lanes, the clock, and command/address.
- Parameters:
rank (
LPDDR4Rank) – Rank count, which sets the number of CKE and CS signals.
- ck = DiffPair()#
Clock (
pis CK_t,nis CK_c)
- ca = [Port(), Port(), Port(), Port(), Port(), Port()]#
Command/address bits CA0 to CA5
- d: Sequence[LPDDR4Lane]#
Byte lanes 0 and 1
- class LPDDR4(width, rank)[source]#
Bases:
PortLPDDR4 interface: one or more x16 channels.
- Parameters:
width (
LPDDR4Width) – Interface width.rank (
LPDDR4Rank) – Rank count.
- ch: Sequence[LPDDR4Channel]#
x16 channels
Bases:
PortOne x16 channel of a dual-rank controller that drives one CKE for both ranks.
Byte lanes 0 and 1
Clock (
pis CK_t,nis CK_c)
Clock enable, shared by both ranks
Chip select, one per rank
Command/address bits CA0 to CA5
Bases:
PortAn x32 dual-rank controller interface with one CKE per channel.
The controller side of a link to an x32 dual-rank
LPDDR4memory. A pin assignment option maps one controller pin to one port, so a shared CKE needs its own port rather than two ports ofLPDDR4.Channels A and B
- signal_ports(bus)[source]#
Return every single-pin port of
busin a fixed order.Per channel: CK p and n, the CKE signals, the CS signals, CA0 to CA5, then per byte lane DQ0 to DQ7, DQS p and n, and DMI. Two bundles of the same width and rank give lists that line up signal for signal. The example controller assigns its balls in this order.
- class LPDDR4ConstraintParams(skew_ck=Toleranced(0, 2e-12, 2e-12), skew_ck_cke=Toleranced(0, 8e-12, 8e-12), skew_ck_cs=Toleranced(0, 8e-12, 8e-12), skew_ck_ca=Toleranced(0, 8e-12, 8e-12), skew_ck_dqs=Toleranced(1e-09, 1.5e-09, 1.5e-09), skew_dqs=Toleranced(0, 2e-12, 2e-12), skew_dqs_dq=Toleranced(0, 5e-12, 5e-12), spread_dq=5e-12, loss=None)[source]#
Bases:
objectLPDDR4 timing limits. Defaults are AMD UG583 Table 2.
To change one value, use
dataclasses.replace()on a default instance.- Parameters:
skew_ck (Toleranced)
skew_ck_cke (Toleranced)
skew_ck_cs (Toleranced)
skew_ck_ca (Toleranced)
skew_ck_dqs (Toleranced)
skew_dqs (Toleranced)
skew_dqs_dq (Toleranced)
spread_dq (float | None)
loss (float | None)
- skew_ck: Toleranced = Toleranced(0, 2e-12, 2e-12)#
CK intra-pair skew
- skew_ck_cke: Toleranced = Toleranced(0, 8e-12, 8e-12)#
CKE to CK skew
- skew_ck_cs: Toleranced = Toleranced(0, 8e-12, 8e-12)#
CS to CK skew
- skew_ck_ca: Toleranced = Toleranced(0, 8e-12, 8e-12)#
CA to CK skew
- skew_ck_dqs: Toleranced = Toleranced(1e-09, 1.5e-09, 1.5e-09)#
CK.p delay minus DQS.p delay
- skew_dqs: Toleranced = Toleranced(0, 2e-12, 2e-12)#
DQS intra-pair skew
- skew_dqs_dq: Toleranced = Toleranced(0, 5e-12, 5e-12)#
DQ and DMI to DQS skew
- class LPDDR4Constraint(diff_structure, se_structure, params=None)[source]#
Bases:
SignalConstraint[LPDDR4]Signal-integrity constraint for an LPDDR4 link.
For each channel,
constrain()applies:CK: intra-pair skew, on the differential structure.
CKE, CS and CA: skew against CK.p, on the single-ended structure. A
LPDDR4SharedCKEcontroller’s one CKE is held against CK.p to each of the memory channel’s CKE balls.Per byte lane, DQS: intra-pair skew, and the CK.p minus DQS.p window.
Per byte lane, DQ and DMI: skew against DQS.p, on the single-ended structure.
Per byte lane, unless
spread_dqisNone, DQ spread: each DQ within half ofspread_dqof DMI, so any two of them differ by at mostspread_dq.ConstrainReferenceDifferencecompares each signal with one guide, which is why a pairwise limit is expressed this way.With
params.lossset, that insertion-loss limit on every signal.
The guides are single pins (CK.p, DQS.p) because
ConstrainReferenceDifferenceaccepts only a single-pin guide. UG583 measures against a differential pair’s mid-point, so the p leg can sit off that reference by up to half the pair’s intra-pair skew.- Parameters:
diff_structure (
DifferentialRoutingStructure) – Differential routing structure for CK and DQS.se_structure (
RoutingStructure) – Single-ended routing structure for CKE, CS, CA, DQ and DMI.params (
LPDDR4ConstraintParams|None) – Timing limits. Defaults toLPDDR4ConstraintParams.
- constrain(src, dst)[source]#
Apply the LPDDR4 constraints between two netted bundles.
- Parameters:
src (
LPDDR4|LPDDR4SharedCKE) – Controller-side bundle: anLPDDR4of the same width and rank asdst, or anLPDDR4SharedCKEwhendstis x32 dual rank.dst (
LPDDR4) – Memory-side bundle.
- Raises:
TypeError – If
dstis not anLPDDR4, such as the controller and memory sides passed in the wrong order.ValueError – If the bundles differ in width or rank.
- Return type: