2424
2525from litedram .common import *
2626from litedram .phy .dfi import *
27+ from litedram .phy .utils import ConstBitSlip
2728
2829# BitSlip ------------------------------------------------------------------------------------------
2930
@@ -49,6 +50,18 @@ def __init__(self, dw, rst=None, slp=None, cycles=1):
4950 cases [i ] = self .o .eq (r [i :dw + i ])
5051 self .comb += Case (value , cases )
5152
53+ # Nexus DDR PHY Write BitSlip ----------------------------------------------------------------------
54+
55+ class _NexusDDRPHYWriteBitSlip (ConstBitSlip ):
56+ def __init__ (self , dw ):
57+ assert (dw % 2 ) == 0
58+ ConstBitSlip .__init__ (self ,
59+ dw = dw ,
60+ slp = dw // 2 ,
61+ cycles = 1 ,
62+ register = False ,
63+ )
64+
5265# Lattice Nexus DDR PHY Initialization --------------------------------------------------------------
5366
5467class NexusDDRPHYInit (Module ):
@@ -170,10 +183,6 @@ def __init__(self, pads,
170183 rdphase = get_sys_phase (nphases , cl_sys_latency , cl )
171184 wrphase = get_sys_phase (nphases , cwl_sys_latency , cwl )
172185
173- # Otherwise writes are off by half a SCLK cycle
174- # TODO: should we implement write DQ/DQS bitslip like s7ddrphy?
175- cwl += 1
176-
177186 self .settings = PhySettings (
178187 phytype = "NexusDDRPHY" ,
179188 memtype = memtype ,
@@ -186,7 +195,7 @@ def __init__(self, pads,
186195 cl = cl ,
187196 cwl = cwl ,
188197 read_latency = cl_sys_latency + 9 ,
189- write_latency = cwl_sys_latency ,
198+ write_latency = cwl_sys_latency - 1 ,
190199 read_leveling = True ,
191200 bitslips = 4 ,
192201 delays = 16 ,
@@ -329,28 +338,37 @@ def __init__(self, pads,
329338 ]
330339
331340 # DQS ----------------------------------------------------------------------------------
332- dqs = Signal ()
333- dqs_oe_n = Signal ()
341+ dqs = Signal ()
342+ dqs_oe_n = Signal ()
343+ dqs_o_data = Signal (4 )
344+ dqs_oe_n_data = Signal (2 )
345+ dqs_o_bitslip = _NexusDDRPHYWriteBitSlip (4 )
346+ dqs_oe_n_bitslip = _NexusDDRPHYWriteBitSlip (2 )
347+ self .submodules += dqs_o_bitslip , dqs_oe_n_bitslip
348+ self .comb += [
349+ dqs_o_data .eq (Cat (0 , dqs_oe , 0 , dqs_oe | dqs_preamble )),
350+ dqs_oe_n_data .eq (Cat (
351+ ~ (dqs_oe | dqs_postamble ),
352+ ~ (dqs_oe | dqs_preamble ),
353+ )),
354+ dqs_o_bitslip .i .eq (dqs_o_data ),
355+ dqs_oe_n_bitslip .i .eq (dqs_oe_n_data ),
356+ ]
334357 self .specials += [
335358 Instance ("ODDRX2DQS" ,
336359 i_RST = ResetSignal ("sys" ),
337360 i_SCLK = ClockSignal ("sys" ),
338361 i_ECLK = ClockSignal ("sys2x" ),
339362 i_DQSW = dqsw ,
340- i_D0 = 0 ,
341- i_D1 = dqs_oe ,
342- i_D2 = 0 ,
343- i_D3 = dqs_oe | dqs_preamble ,
344- # **{f"i_D{n}": (0b1010 >> n) & 0b1 for n in range(4)},
363+ ** {f"i_D{ n } " : dqs_o_bitslip .o [n ] for n in range (4 )},
345364 o_Q = dqs
346365 ),
347366 Instance ("TSHX2DQS" ,
348367 i_RST = ResetSignal ("sys" ),
349368 i_SCLK = ClockSignal ("sys" ),
350369 i_ECLK = ClockSignal ("sys2x" ),
351370 i_DQSW = dqsw ,
352- i_T0 = ~ (dqs_oe | dqs_postamble ),
353- i_T1 = ~ (dqs_oe | dqs_preamble ),
371+ ** {f"i_T{ n } " : dqs_oe_n_bitslip .o [n ] for n in range (2 )},
354372 o_Q = dqs_oe_n
355373 ),
356374 Tristate (pads .dqs_p [i ], dqs , ~ dqs_oe_n , dqs_i )
@@ -360,8 +378,11 @@ def __init__(self, pads,
360378 dm_o_data = Signal (8 )
361379 dm_o_data_d = Signal (8 )
362380 dm_o_data_muxed = Signal (4 )
381+ dm_o_bitslip = _NexusDDRPHYWriteBitSlip (4 )
382+ self .submodules += dm_o_bitslip
363383 for n in range (8 ):
364384 self .comb += dm_o_data [n ].eq (dfi .phases [n // 4 ].wrdata_mask [n % 4 * databits // 8 + dm_remapping .get (i , i )])
385+ self .comb += dm_o_bitslip .i .eq (dm_o_data_muxed )
365386 self .sync += dm_o_data_d .eq (dm_o_data )
366387 dm_bl8_cases = {}
367388 dm_bl8_cases [0 ] = dm_o_data_muxed .eq (dm_o_data [:4 ])
@@ -372,7 +393,7 @@ def __init__(self, pads,
372393 i_SCLK = ClockSignal ("sys" ),
373394 i_ECLK = ClockSignal ("sys2x" ),
374395 i_DQSW270 = dqsw270 ,
375- ** {f"i_D{ n } " : dm_o_data_muxed [n ] for n in range (4 )},
396+ ** {f"i_D{ n } " : dm_o_bitslip . o [n ] for n in range (4 )},
376397 o_Q = pads .dm [i ]
377398 )
378399
@@ -386,8 +407,20 @@ def __init__(self, pads,
386407 dq_o_data = Signal (8 )
387408 dq_o_data_d = Signal (8 )
388409 dq_o_data_muxed = Signal (4 )
410+ dq_oe_n_data = Signal (2 )
411+ dq_o_bitslip = _NexusDDRPHYWriteBitSlip (4 )
412+ dq_oe_n_bitslip = _NexusDDRPHYWriteBitSlip (2 )
413+ self .submodules += dq_o_bitslip , dq_oe_n_bitslip
389414 for n in range (8 ):
390415 self .comb += dq_o_data [n ].eq (dfi .phases [n // 4 ].wrdata [n % 4 * databits + j ])
416+ self .comb += [
417+ dq_oe_n_data .eq (Cat (
418+ ~ (dq_oe | dqs_postamble ),
419+ ~ (dq_oe | dqs_preamble ),
420+ )),
421+ dq_o_bitslip .i .eq (dq_o_data_muxed ),
422+ dq_oe_n_bitslip .i .eq (dq_oe_n_data ),
423+ ]
391424 self .sync += dq_o_data_d .eq (dq_o_data )
392425 dq_bl8_cases = {}
393426 dq_bl8_cases [0 ] = dq_o_data_muxed .eq (dq_o_data [:4 ])
@@ -399,7 +432,7 @@ def __init__(self, pads,
399432 i_SCLK = ClockSignal ("sys" ),
400433 i_ECLK = ClockSignal ("sys2x" ),
401434 i_DQSW270 = dqsw270 ,
402- ** {f"i_D{ n } " : dq_o_data_muxed [n ] for n in range (4 )},
435+ ** {f"i_D{ n } " : dq_o_bitslip . o [n ] for n in range (4 )},
403436 o_Q = dq_o
404437 )
405438 ]
@@ -437,8 +470,7 @@ def __init__(self, pads,
437470 i_SCLK = ClockSignal ("sys" ),
438471 i_ECLK = ClockSignal ("sys2x" ),
439472 i_DQSW270 = dqsw270 ,
440- i_T0 = ~ (dq_oe | dqs_postamble ),
441- i_T1 = ~ (dq_oe | dqs_preamble ),
473+ ** {f"i_T{ n } " : dq_oe_n_bitslip .o [n ] for n in range (2 )},
442474 o_Q = dq_oe_n ,
443475 ),
444476 Tristate (pads .dq [j ], dq_o , ~ dq_oe_n , dq_i )
@@ -466,7 +498,9 @@ def __init__(self, pads,
466498 self .comb += dqs_re .eq (rddata_en .taps [rdtap ] | rddata_en .taps [rdtap + 1 ])
467499
468500 # Write Control Path -----------------------------------------------------------------------
469- wrtap = cwl_sys_latency
501+ # The Nexus write path is one memory-clock late. Start one sys_clk cycle early and use the
502+ # fixed half-word bitslips above to place DQ, DM, DQS and their tristates at the JEDEC CWL.
503+ wrtap = cwl_sys_latency - 1
470504
471505 # Create a delay line of write commands coming from the DFI interface. This taps are used to
472506 # control DQ/DQS tristates and to select write data of the DRAM burst from the DFI interface.
0 commit comments