Skip to content

phy: Align Nexus DDR writes without altering CWL - #397

Merged
enjoy-digital merged 1 commit into
masterfrom
fix-nexus-ddr-write-alignment
Jul 22, 2026
Merged

phy: Align Nexus DDR writes without altering CWL#397
enjoy-digital merged 1 commit into
masterfrom
fix-nexus-ddr-write-alignment

Conversation

@enjoy-digital

Copy link
Copy Markdown
Owner

Follow-up to #396.

Summary

  • Keep the DDR3 CWL selected from the memory clock instead of incrementing it to compensate for PHY timing.
  • Start the DFI write path one sys_clk cycle earlier and apply a fixed half-word slip to DQ, DM, DQS, and their tristate controls.
  • Add simulations covering serialized data/tristate ordering, DQS preamble/postamble boundaries, and the default Nexus PHY settings.

Rationale

The Nexus write path is one memory clock later than the command path. In the 1:2 PHY, one sys_clk cycle spans two memory clocks, so scheduling one sys_clk cycle earlier and delaying the serializer streams by half a word produces the required net advance of one memory clock.

This keeps the controller timing and programmed DDR3 mode consistent. Incrementing CWL can otherwise select a value that is not valid for the configured memory clock.

Testing

  • pytest -q test/test_nxddrphy.py test/test_phy_utils.py: 30 passed, 12 subtests passed.
  • pytest -q: 335 passed, 5 skipped, 612 subtests passed.
  • Nexus PHY elaboration and Verilog generation checked with an 8-bit DQ pad model.

@gatecat, could you please test this on the Certus-NX Versa board, first with Radiant and also with nextpnr if practical? The useful checks are DDR3 initialization plus repeated write/read tests, since hardware validation is the remaining part that simulation cannot cover here.

The Nexus write path is one memory clock later than the command path. Compensating for this by incrementing CWL programs a different DDR3 mode and can produce an invalid CWL for the selected memory clock.

Schedule DFI write data one sys_clk cycle earlier, then apply a fixed half-word slip to DQ, DM, DQS and their tristate controls. Since a sys_clk cycle spans two memory clocks, this advances the complete write stream by the required single memory clock while preserving the JEDEC CWL.

Add simulations for data and tristate bit ordering, burst preamble/postamble boundaries, and the default Nexus PHY timing settings.

Suggested-by: Myrtle Shah <gatecat@ds0.me>
@gatecat

gatecat commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Looks good, thanks for finding a better solution here! Tested with both Radiant and nextpnr:

        __   _ __      _  __
       / /  (_) /____ | |/_/
      / /__/ / __/ -_)>  <
     /____/_/\__/\__/_/|_|
   Build your hardware, easily!

 (c) Copyright 2012-2026 Enjoy-Digital
 (c) Copyright 2007-2015 M-Labs

 BIOS built on Jul 22 2026 18:27:49
 BIOS CRC passed (19033a25)

 LiteX git sha1: f0f4be1c2

--================ SoC =================--
CPU:		VexRiscv_Min @ 75MHz
BUS:		wishbone 32-bit data/32-bit addr
CSR:		32-bit data big ordering
ROM:		128.0KiB
SRAM:		8.0KiB
L2:		8.0KiB
SDRAM:		128.0MiB 16-bit @ 300MT/s (CL-6 CWL-5)
MAIN RAM:	128.0MiB

--=========== Initialization ===========--
Initializing SDRAM @0x40000000...
Switching SDRAM to software control.
Read leveling:
  m0, b00: |0000001111111100| delays: 09+-03
  m0, b01: |0000000000000000| delays: -
  m0, b02: |0000000000000000| delays: -
  m0, b03: |0000000000000000| delays: -
  best: m0, b00 delays: 09+-03
  m1, b00: |0000001111111100| delays: 09+-03
  m1, b01: |0000000000000000| delays: -
  m1, b02: |0000000000000000| delays: -
  m1, b03: |0000000000000000| delays: -
  best: m1, b00 delays: 09+-03
Switching SDRAM to hardware control.
Memtest at 0x40000000 (2.0MiB)...
  Write: 0x40000000-0x40200000 2.0MiB     
   Read: 0x40000000-0x40200000 2.0MiB     
Memtest OK
Memspeed at 0x40000000 (Sequential, 2.0MiB)...
  Write speed: 15.5MiB/s
   Read speed: 21.4MiB/s
--================ Boot ================--
Booting from serial...
Press Q or ESC to abort boot completely.
sL5DdSMmkekro
             Timeout
No boot medium found

--============== Console ===============--

litex> 

(incidentally, the workaround of tampering with latencies came from s7ddrphy doing a similar hack for the read path:

if (memtype == "DDR3") and (not with_odelay):
# DDR3 Write leveling is not possible on Artix7 due to the lack of ODELAYE2, adding +1
# to cl in MR register increases sys_clk_freq range.
cl += 1
)

@enjoy-digital

Copy link
Copy Markdown
Owner Author

Thanks @gatecat for the quick feedback! I'll merge then. The solution on Artix7 is indeed also a workaround, I'll try to explore other solutions with AI and see if we could improve.

@enjoy-digital
enjoy-digital merged commit 794cfa8 into master Jul 22, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants