ddr4 module#

DDR4#

Port bundles and signal-integrity constraints for a point-to-point DDR4 link between a controller and one memory device.

Source and scope#

The defaults are Table 116, “Skew Matching Guidelines for DDR4 Discrete Topologies”, in Altera, External Memory Interfaces Agilex 7 F-Series and I-Series FPGA IP User Guide (683216, version 23.2), section 6.5.6.4, “Skew Matching Guidelines for DDR4 Discrete Configurations”, https://docs.altera.com/r/docs/683216/23.2/external-memory-interfaces-agilextm-7-f-series-and-i-series-fpga-ip-user-guide/skew-matching-guidelines-for-ddr4-discrete-configurations. That section covers single-rank x8 and single-rank x16 discrete (device-down) topologies. The module accepts other widths and ranks, but the table does not cover them, and it does not support several memories on one bus (see Fly-by below).

  • CK to CK#: < 1 ps (applied as +/-1 ps)

  • DQS to DQS#: < 1 ps (applied as +/-1 ps)

  • DQ to DQS within a byte: -3.5 ps < DQ - DQS < 3.5 ps (applied to DQ and DM_n)

  • CMD/ADDR/CTRL to clock: -20 ps < CLK - CMD/ADDR/CTRL < 20 ps

  • CMD/ADDR/CTRL among themselves within each channel: < 20 ps. The constraint holds each of them within +/-10 ps of CKE[0], so any two differ by at most 20 ps. That is stricter than the table, which allows every other signal to sit together 15 ps from CKE[0]; the constraint fails that layout.

  • DQS to CLK: -85 ps < CLK - DQS < 935 ps. On jitx 4.6, ConstrainReferenceDifference(guide, target) measures guide delay minus target delay (checked on a code-routed pair), so CK is the guide and the window is used as written.

The constraint applies the CMD/ADDR/CTRL rules to the address bits (A0 to A16 in this bundle; A14 to A16 double as WE_n, CAS_n and RAS_n), BA, BG, ACT_n, CKE, CS_n, ODT and PAR. The section says ALERT_n needs no skew matching. It does not name RESET_n; this module gives RESET_n no skew limit. Both get the routing structure and the optional loss limit.

The section also asks for skew matching in time rather than length: “Include both package per-pin skew and PCB delay when performing skew matching.” 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. The controller in ddr4_example is fictional and has none, so its numbers would be PCB delay only. The table gives no rule between CK pairs, no insertion-loss limit and no impedance target, so the module sets none of them: pass loss in the parameter classes 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.ddr4 + self.memory.ddr4
self.si = DDR4Constraint(
    ck_structure=..., dqs_structure=..., dq_structure=..., acc_structure=...
)
self.si.constrain(self.controller.ddr4, self.memory.ddr4)

The issue report measures a constraint only once the path between its two ends is routed.

Fly-by#

With several memories on one address/command bus, the bus is a daisy chain: controller, first memory, second memory. This module does not support that: its constraint covers one controller-to-memory link, and the cited table covers discrete single-device topologies only. In a fly-by design, the chain order is part of the design, and >> (TopologyNet) declares it.

class DDR4Width(*values)[source]#

Bases: Enum

DDR4 data width: the number of DQ signals.

x4 = 4#

4 bits, one byte lane

x8 = 8#

8 bits, one byte lane

x16 = 16#

16 bits, two byte lanes

x32 = 32#

32 bits, four byte lanes

x64 = 64#

64 bits, eight byte lanes

x72 = 72#

72 bits (64 plus ECC), nine byte lanes

num_byte_lanes(width)[source]#

Return the number of byte lanes (DQS pairs) for a data width.

Return type:

int

Parameters:

width (DDR4Width)

class DDR4Rank(*values)[source]#

Bases: Enum

DDR4 rank count: the number of CS_n, CKE and ODT signals.

SingleRank = 1#

One rank

DualRank = 2#

Two ranks

QuadRank = 4#

Four ranks

class DDR4DataChannel(width)[source]#

Bases: Port

DDR4 data signals: DQ, one DQS pair and one DM_n per byte lane.

Parameters:

width (DDR4Width) – Data width.

DQ: Sequence[Port]#

Data bits

DQS: Sequence[DiffPair]#

Data strobes, one per byte lane (p is DQS_t, n is DQS_c)

DM_n: Sequence[Port]#

Data masks, one per byte lane

class DDR4AccChannel(rank, ck_count=1, bg_count=2, ba_count=2)[source]#

Bases: Port

DDR4 address, command, control and clock signals.

Parameters:
  • rank (DDR4Rank) – Rank count, which sets the number of CKE, CS_n and ODT signals.

  • ck_count (int) – Number of CK pairs.

  • bg_count (int) – Number of bank-group signals (one on x16 parts).

  • ba_count (int) – Number of bank-address signals.

ACT_n = Port()#

Activate command

RESET_n = Port()#

Reset

PAR = Port()#

Command and address parity

ALERT_n = Port()#

Alert

CK: Sequence[DiffPair]#

Clock pairs (p is CK_t, n is CK_c)

CKE: Sequence[Port]#

Clock enable, one per rank

A: Sequence[Port]#

Address A0 to A16 (A14 to A16 double as WE_n, CAS_n, RAS_n)

BG: Sequence[Port]#

Bank group

BA: Sequence[Port]#

Bank address

CS_n: Sequence[Port]#

Chip select, one per rank

ODT: Sequence[Port]#

On-die termination, one per rank

class DDR4(width, rank=DDR4Rank.SingleRank, ck_count=1, bg_count=2, ba_count=2)[source]#

Bases: Port

DDR4 interface: data channel plus address/command/control channel.

Parameters:
  • width (DDR4Width) – Data width.

  • rank (DDR4Rank) – Rank count.

  • ck_count (int) – Number of CK pairs.

  • bg_count (int) – Number of bank-group signals.

  • ba_count (int) – Number of bank-address signals.

data: DDR4DataChannel#

Data channel

acc: DDR4AccChannel#

Address, command, control and clock channel

signal_ports(bus)[source]#

Return every single-pin port of bus in a fixed order.

Data first (DQ, DQS p and n per lane, DM_n), then CK p and n per pair, CKE, A, ACT_n, BG, BA, CS_n, RESET_n, ODT, PAR and ALERT_n. Two bundles built with the same arguments give lists that line up signal for signal.

Return type:

list[Port]

Parameters:

bus (DDR4)

class DDR4DataConstraintParams(skew_dqs=Toleranced(0, 1e-12, 1e-12), skew_dq_dqs=Toleranced(0, 3.5e-12, 3.5e-12), loss=None)[source]#

Bases: object

DDR4 data-channel limits. Defaults are the cited rules in this module.

Variables:
  • skew_dqs (Toleranced) – DQS intra-pair skew.

  • skew_dq_dqs (Toleranced) – DQ and DM_n to DQS.P skew within a byte lane.

  • loss (float | None) – Maximum insertion loss in dB for DQ, DM_n and DQS, or None for no loss limit.

Parameters:
skew_dqs: Toleranced = Toleranced(0, 1e-12, 1e-12)#
skew_dq_dqs: Toleranced = Toleranced(0, 3.5e-12, 3.5e-12)#
loss: float | None = None#
class DDR4AccConstraintParams(skew_ck=Toleranced(0, 1e-12, 1e-12), skew_acc_ck=Toleranced(0, 2e-11, 2e-11), spread_acc=2e-11, loss=None)[source]#

Bases: object

DDR4 address/command/control limits. Defaults are the cited rules.

Variables:
  • skew_ck (Toleranced) – CK intra-pair skew.

  • skew_acc_ck (Toleranced) – CK.P delay minus address, command and control delay.

  • spread_acc (float) – Largest delay difference among the address, command and control signals of the channel, in seconds. Applied as +/- half of it around CKE[0].

  • loss (float | None) – Maximum insertion loss in dB for CK and the address, command and control signals, or None for no loss limit.

Parameters:
skew_ck: Toleranced = Toleranced(0, 1e-12, 1e-12)#
skew_acc_ck: Toleranced = Toleranced(0, 2e-11, 2e-11)#
spread_acc: float = 2e-11#
loss: float | None = None#
class DDR4DataAccConstraintParams(skew_ck_dqs=Toleranced(4.25e-10, 5.1e-10, 5.1e-10))[source]#

Bases: object

DDR4 data-to-clock limit. The default is the cited rule.

Variables:

skew_ck_dqs (Toleranced) – CK.P delay minus DQS.P delay.

Parameters:

skew_ck_dqs (Toleranced)

skew_ck_dqs: Toleranced = Toleranced(4.25e-10, 5.1e-10, 5.1e-10)#
class DDR4DataConstraint(dqs_structure, dq_structure, params=None)[source]#

Bases: SignalConstraint[DDR4DataChannel]

Constraint for the DDR4 data channel.

Per byte lane: DQS intra-pair skew, and DQ and DM_n skew against DQS.P. Byte lane i holds DQ 8 * i to 8 * i + 7.

Parameters:
constrain(src, dst)[source]#

Apply the data-channel constraints between two netted channels.

Raises:

ValueError – If the channels differ in width.

Return type:

None

Parameters:
class DDR4AccConstraint(ck_structure, acc_structure, params=None)[source]#

Bases: SignalConstraint[DDR4AccChannel]

Constraint for the DDR4 address, command, control and clock channel.

Applies CK intra-pair skew to every CK pair, then holds CKE, A, ACT_n, BG, BA, CS_n, ODT and PAR within skew_acc_ck of CK[0].P and within half of spread_acc of CKE[0]. RESET_n and ALERT_n get the routing structure and loss limit only. There is no limit between CK pairs, since the cited table gives none.

Parameters:
constrain(src, dst)[source]#

Apply the address/command/control constraints between two channels.

Return type:

None

Parameters:
class DDR4DataAccConstraint(params=None)[source]#

Bases: SignalConstraint[DDR4]

Constraint between the two channels: each DQS.P against CK[0].P.

Parameters:

params (DDR4DataAccConstraintParams | None) – Limit. Defaults to DDR4DataAccConstraintParams.

constrain(src, dst)[source]#

Apply the DQS-to-CK window between two netted bundles.

Return type:

None

Parameters:
class DDR4Constraint(ck_structure, dqs_structure, dq_structure, acc_structure, data_params=None, acc_params=None, data_acc_params=None)[source]#

Bases: SignalConstraint[DDR4]

Complete DDR4 constraint: data, address/command/control, and the DQS-to-CK window between them.

Parameters:
constrain(src, dst)[source]#

Apply every DDR4 constraint between two netted bundles.

Parameters:
  • src (DDR4) – Controller-side bundle.

  • dst (DDR4) – Memory-side bundle, built with the same arguments.

Return type:

None