Commit 6989d804 authored by Andrey Filippov's avatar Andrey Filippov

working on DQS+DQ inpute delays adjustment

parent 4f1a1c28
......@@ -45,6 +45,10 @@ from x393_mcntrl_buffers import X393McntrlBuffers
#from x393_axi_control_status import concat, bits
#from time import sleep
from verilog_utils import checkIntArgs,smooth2d
import get_test_dq_dqs_data # temporary to test processing
import x393_lma
#import vrlg
NUM_FINE_STEPS= 5
......@@ -210,16 +214,18 @@ class X393McntrlAdjust(object):
low_delay,
high_delay,
num=8,
sel=1, # 0 - early, 1 - late read command (shift by a SDCLK period)
quiet=2 ):
"""
Scan DQS input delay values using pattern read mode
<low_delay> low delay value (in 'hardware' format, sparse)
<high_delay> high delay value (in 'hardware' format, sparse)
<num> number of 64-bit words to process
<sel> 0 - early, 1 - late read command (shift by a SDCLK period)
<quiet> less output
"""
checkIntArgs(('low_delay','high_delay','num'),locals())
self.x393_pio_sequences.set_read_pattern(num+1) # do not use first/last pair of the 32 bit words
self.x393_pio_sequences.set_read_pattern(num+1,sel) # do not use first/last pair of the 32 bit words
low = self.split_delay(low_delay)
high = self.split_delay(high_delay)
results = []
......@@ -286,16 +292,18 @@ class X393McntrlAdjust(object):
low_delay,
high_delay,
num=8,
sel=1,# 0 - early, 1 - late read command (shift by a SDCLK period)
quiet=2 ):
"""
Scan DQ input delay values using pattern read mode
<low_delay> low delay value (in 'hardware' format, sparse)
<high_delay> high delay value (in 'hardware' format, sparse)
<num> number of 64-bit words to process
<sel> 0 - early, 1 - late read command (shift by a SDCLK period)
<quiet> less output
"""
checkIntArgs(('low_delay','high_delay','num'),locals())
self.x393_pio_sequences.set_read_pattern(num+1) # do not use first/last pair of the 32 bit words
self.x393_pio_sequences.set_read_pattern(num+1,sel) # do not use first/last pair of the 32 bit words
low = self.split_delay(low_delay)
high = self.split_delay(high_delay)
results = []
......@@ -363,6 +371,7 @@ class X393McntrlAdjust(object):
low_delay,
high_delay,
num=8,
sel=1, # 0 - early, 1 - late read command (shift by a SDCLK period)
falling=0, # 0 - use rising as delay increases, 1 - use falling
smooth=10,
quiet=2):
......@@ -372,6 +381,7 @@ class X393McntrlAdjust(object):
<low_delay> low delay value (in 'hardware' format, sparse)
<high_delay> high delay value (in 'hardware' format, sparse)
<num> number of 64-bit words to process
<sel> 0 - early, 1 - late read command (shift by a SDCLK period)
<falling> 0 - use rising edge as delay increases, 1 - use falling one
In 'falling' mode results are the longest DQ idelay
when bits switch from correct to incorrect,
......@@ -382,7 +392,7 @@ class X393McntrlAdjust(object):
"""
checkIntArgs(('low_delay','high_delay','num'),locals())
low = self.split_delay(low_delay)
data_raw=self.scan_dq_idelay(low_delay,high_delay,num,quiet)
data_raw=self.scan_dq_idelay(low_delay,high_delay,num,sel,quiet)
data=[]
delays=[]
for i,d in enumerate(data_raw):
......@@ -1318,7 +1328,7 @@ class X393McntrlAdjust(object):
quiet=1
):
"""
Find DQS odelay for each phase value
Find DQS output delay for each phase value
Depends on adjust_cmda_odelay results
"""
if not self.adjustment_state['cmda_bspe']:
......@@ -1644,3 +1654,358 @@ class X393McntrlAdjust(object):
# print (self.adjustment_state)
return rdict
def adjust_pattern(self,
limit_step=0.125, # initial delay step as a fraction of the period
max_phase_err=0.1,
quiet=1,
start_dly=0): #just to check dependence
"""
for each DQS input delay find 4 DQ transitions for each DQ bit,
then use them to find finedelay for each of the DQS and DQ,
linear coefficients (a,b) for each DQ vs DQS and asymmetry
(late 0->1, early 1->0) for each of the DQ and DQS
"""
nrep=8
max_lin_dly=159
timing=self.x393_mcntrl_timing.get_dly_steps()
#steps={'DLY_FINE_STEP': 0.01, 'DLY_STEP': 0.078125, 'PHASE_STEP': 0.022321428571428572, 'SDCLK_PERIOD': 2.5}
dly_step=int(5*limit_step*timing['SDCLK_PERIOD']/timing['DLY_STEP']+0.5)
step180= int(5*0.5* timing['SDCLK_PERIOD'] / timing['DLY_STEP'] +0.5)
if quiet<2:
print ("timing)=%s, dly_step=%d step180=%d"%(str(timing),dly_step,step180))
self.x393_pio_sequences.set_read_pattern(nrep+3) # set sequence once
def patt_dqs_step(dqs_lin):
patt_cache=[None]*(max_lin_dly+1) # cache for holding already measured delays
def measure_patt(dly,force_meas=False):
if (patt_cache[dly] is None) or force_meas:
self.x393_mcntrl_timing.axi_set_dq_idelay(self.combine_delay(dly),quiet=quiet)
patt= self.x393_pio_sequences.read_levelling(nrep,
-1, # sel=1, # 0 - early, 1 - late read command (shift by a SDCLK period), -1 - use current sequence
quiet+1)
patt_cache[dly]=patt
if quiet < 1:
print ('measure_patt(%d,%s) - new measurement'%(dly,str(force_meas)))
else:
patt=patt_cache[dly]
if quiet < 1:
print ('measure_patt(%d,%s) - using cache'%(dly,str(force_meas)))
return patt
def get_sign(data,edge=None):
"""
edge: 0 - first 16, 1 - second 16
return -1 if all <0.5
return +1 if all >0.5
return 0 otherwise
"""
if edge == 0:
return get_sign(data[:16])
if edge == 1:
# return -get_sign(data[16:])
return get_sign(data[16:])
m1=True
p1=True
for d in data:
m1 &= (d < 0.5)
p1 &= (d > 0.5)
if not (m1 or p1):
break
else:
if m1:
return -1
elif p1:
return 1
return 0
rslt=[None]*16 # each bit will have [inphase][dqs_falling]
self.x393_mcntrl_timing.axi_set_dqs_idelay(self.combine_delay(dqs_lin),quiet=quiet)
d_low=[None]*2 # first - lowest when all are -+, second - when all are +-
d_high=[None]*2 # first - when all are +- after -+, second - when all are -+ after +-
dly=0
notLast=True
needSigns=None
lowGot=None
highGot=None
while (dly <= max_lin_dly) and notLast:
notLast= dly < max_lin_dly
patt=measure_patt(dly) # ,force_meas=False)
signs=(get_sign(patt,0),get_sign(patt,1))
if quiet < 1:
print ('dly=%d lowGot=%s, highGot=%s, signs=%s'%(dly,str(lowGot),str(highGot),str(signs)))
if lowGot is None : # looking for the first good sample
if (signs==(-1,1)) or (signs==(1,-1)) :
if signs[0] == -1: # == (-1,1):
lowGot=0
else:
lowGot=1
d_low[lowGot] = dly
needSigns=((1,-1),(-1,1))[lowGot]
dly += step180-dly_step # almost 180 degrees
else: # at least one is 0
dly += dly_step # small step
if quiet < 1:
print ('lowGot was None : dly=%d, lowGot=%s, needSigns=%s'%(dly,str(lowGot),str(needSigns)))
elif highGot is None : # only one good sample is available so far
if signs == needSigns:
highGot=lowGot
d_high[highGot] = dly
d_low[1-lowGot] = dly
needSigns=((-1,1),(1,-1))[lowGot]
dly += step180-dly_step # almost 180 degrees
else:
dly += dly_step # small step
if quiet < 1:
print ('highGot was None : dly=%d, lowGot=%s, highGot=%s, needSigns=%s'%(dly,str(lowGot),str(lowGot),str(needSigns)))
else: # looking for the 3-rd sample
if signs == needSigns:
highGot=1-highGot
d_high[highGot] = dly
break
else:
dly += dly_step # small step
dly = min (dly,max_lin_dly)
if highGot is None:
if quiet < 3:
print ("Could not find initial bounds for DQS input delay = %d d_low=%s, d_high=%s"%(dqs_lin,str(d_low),str(d_high)))
return None
if quiet < 2:
print ("DQS input delay = %d , preliminary bounds: d_low=%s, d_high=%s"%(dqs_lin,str(d_low),str(d_high)))
for inPhase in range(2):
if not d_high[inPhase] is None:
# Try to squeeze d_low, d_high closer to reduce scan range
while d_high[inPhase]>d_low[inPhase]:
dly=(d_high[inPhase] + d_low[inPhase])//2
patt=measure_patt(dly) # ,force_meas=False)
signs=(get_sign(patt,0),get_sign(patt,1))
if signs==(-1,1):
if inPhase:
d_high[inPhase]=dly
else:
if d_low[inPhase]==dly:
break
d_low[inPhase]=dly
elif signs==(1,-1):
if inPhase:
if d_low[inPhase]==dly:
break
d_low[inPhase]=dly
else:
d_high[inPhase]=dly
else: # uncertain result
break
if quiet < 2:
print ("DQS input delay = %d , squeezed bounds: d_low=%s, d_high=%s"%(dqs_lin,str(d_low),str(d_high)))
#Improve squeezing - each limit to the last
for inPhase in range(2):
if not d_high[inPhase] is None:
# Try to squeeze d_low first
d_uncertain=d_high[inPhase]
while d_uncertain > d_low[inPhase]:
dly=(d_uncertain + d_low[inPhase])//2
patt=measure_patt(dly) # ,force_meas=False)
signs=(get_sign(patt,0),get_sign(patt,1))
if signs==(-1,1):
if inPhase:
d_uncertain=dly
else:
if d_low[inPhase]==dly:
break
d_low[inPhase]=dly
elif signs==(1,-1):
if inPhase:
if d_low[inPhase]==dly:
break
d_low[inPhase]=dly
else:
d_uncertain=dly
else: # uncertain result
d_uncertain=dly
#now udjust upper limit
while d_high[inPhase] > d_uncertain:
dly=(d_high[inPhase] + d_uncertain)//2
patt=measure_patt(dly) # ,force_meas=False)
signs=(get_sign(patt,0),get_sign(patt,1))
if signs==(-1,1):
if inPhase:
d_high[inPhase]=dly
else:
if d_uncertain==dly:
break
d_uncertain=dly
elif signs==(1,-1):
if inPhase:
if d_uncertain==dly:
break
d_uncertain=dly
else:
d_high[inPhase]=dly
else: # uncertain result
if d_uncertain==dly:
break
d_uncertain=dly
if quiet < 2:
print ("DQS input delay = %d , tight squeezed bounds: d_low=%s, d_high=%s"%(dqs_lin,str(d_low),str(d_high)))
# scan ranges, find closest solutions
best_dly= [[],[]]
best_diff=[[],[]]
for inPhase in range(2):
if not d_high[inPhase] is None:
patt=None
for dly in range(d_low[inPhase],d_high[inPhase]+1):
patt_prev=patt
patt=measure_patt(dly) # ,force_meas=False) - will be stored in cache
if patt_prev is None: #first run
best_dly[inPhase]=[d_low[inPhase]]*32
for p in patt:
best_diff[inPhase].append(p-0.5)
else: # all the rest
for b in range(32):
positiveJump=((not inPhase) and (b<16)) or (inPhase and (b >= 16)) # may be 0, False, True
signs=((-1,1)[patt_prev[b]>0.5],(-1,1)[patt[b]>0.5])
if (positiveJump and (signs==(-1,1))) or (not positiveJump and (signs==(1,-1))):
if abs(patt_prev[b]-0.5) < abs(patt[b]-0.5): # store previos sample
best_dly[inPhase][b]=dly-1
best_diff[inPhase][b]=patt_prev[b]-0.5
else:
best_dly[inPhase][b]=dly
best_diff[inPhase][b]=patt[b]-0.5
if not positiveJump:
best_diff[inPhase][b] *= -1 # inver sign, so sign always means <0 - delay too low, >0 - too high
# rslt=[None]*16 # each bit will have [inphase][dqs_falling], each - a pair of (delay,diff)
for b in range(16):
rslt[b]=[[None]*2,[None]*2] # [inphase][dqs_falling]
for inPhase in range(2):
if not d_high[inPhase] is None:
rslt[b][inPhase]= [(best_dly[inPhase][b],best_diff[inPhase][b]),(best_dly[inPhase][b+16],best_diff[inPhase][b+16])]
if quiet < 2:
print ("%d: rslt=%s"%(dqs_lin,str(rslt)))
return rslt
# meas_data=[]
# for ldly in range(max_lin_dly+1):
# if quiet <3:
# print ("%d(0x%x):"%(ldly,self.combine_delay(ldly)),end=" ")
# sys.stdout.flush()
# meas_data.append(patt_dqs_step(ldly))
# if quiet <3:
# print ()
meas_data=[None]*(max_lin_dly+1)
#start_dly
for sdly in range(max_lin_dly+1):
ldly = (start_dly+sdly)%(max_lin_dly+1)
# for ldly in range(max_lin_dly+1):
if quiet <3:
print ("%d(0x%x):"%(ldly,self.combine_delay(ldly)),end=" ")
sys.stdout.flush()
meas_data[ldly] = patt_dqs_step(ldly)
if quiet <3:
print ()
if quiet < 3:
print ("DQS",end=" ")
for f in ('ir','if','or','of'):
for b in range (16):
print ("%s_%d"%(f,b),end=" ")
print()
for ldly, data in enumerate(meas_data):
print("%d"%ldly,end=" ")
if data:
for typ in ((0,0),(0,1),(1,0),(1,1)):
for pData in data: # 16 DQs, each None nor a pair of lists for inPhase in (0,1), each a pair of edges, each a pair of (dly,diff)
if pData:
if pData[typ[0]] and pData[typ[0]][typ[1]]:
print ("%d"%pData[typ[0]][typ[1]][0],end=" ")
'''
try:
print ("%d"%pData[typ[0]][typ[1]][0],end=" ")
except:
print (".", end=" ")
'''
else:
print ("?", end=" ")
else:
print ("x",end=" ")
print()
if quiet < 2:
print ("\nDifferences from 0.5:")
print ("DQS",end=" ")
for f in ('ir','if','or','of'):
for b in range (16):
print ("%s_%d"%(f,b),end=" ")
print()
for ldly, data in enumerate(meas_data):
print("%d"%ldly,end=" ")
if data:
for typ in ((0,0),(0,1),(1,0),(1,1)):
for pData in data: # 16 DQs, each None nor a pair of lists for inPhase in (0,1), each a pair of edges, each a pair of (dly,diff)
if pData:
if pData[typ[0]] and pData[typ[0]][typ[1]]:
print ("%.2f"%pData[typ[0]][typ[1]][1],end=" ")
'''
try:
print ("%d"%pData[typ[0]][typ[1]][0],end=" ")
except:
print (".", end=" ")
'''
else:
print ("?", end=" ")
else:
print ("x",end=" ")
print()
print("\n\n")
# print ("meas_data=%s"%str(meas_data))
print ("meas_data=[")
for d in meas_data:
print("%s,"%(str(d)))
print("]")
#meas_data=[
'''
adjust_cmda_odelay 0 1 0.1 3
adjust_write_levelling 0 1 0 .1 3
adjust_pattern 0.125 0.1 1
'''
def proc_test_data(self,
lane=0,
bin_size=5,
primary_set=2,
quiet=1):
meas_data=get_test_dq_dqs_data.get_data()
meas_delays=[]
for data in meas_data:
if data:
bits=[None]*16
for b,pData in enumerate(data):
if pData:
"""
bits[b]=[[None,None],[None,None]]
for inPhase in (0,1):
if pData[inPhase]:
for e in (0,1):
if pData[inPhase][e]:
bits[b][inPhase][e]=pData[inPhase][e][0]
"""
bits[b]=[None]*4
for inPhase in (0,1):
if pData[inPhase]:
for e in (0,1):
if pData[inPhase][e]:
bits[b][inPhase*2+e]=pData[inPhase][e][0]
meas_delays.append(bits)
if quiet<1:
x393_lma.test_data(meas_delays,quiet)
lma=x393_lma.X393LMA()
lma.init_parameters(
lane,
bin_size,
2500.0, # clk_period,
78.0, # dly_step_ds,
primary_set,
meas_delays,
quiet)
\ No newline at end of file
......@@ -178,12 +178,14 @@ class X393McntrlTiming(object):
self.axi_set_phase()
def axi_set_dq_idelay(self, # sets same delay to all dq idelay
delay=None): # input [7:0] delay;
delay=None, # input [7:0] delay;
quiet=1):
"""
Set all DQ input delays to the same value
<delay> 8-bit (5+3) delay value to use or a tuple/list with a pair for (lane0, lane1)
Each of the two elements in the delay tuple/list may be a a common integer or a list/tuple itself
if delay is None will restore default values
<quiet> reduce output
"""
# print("====axi_set_dq_idelay %s"%str(delay))
......@@ -194,7 +196,7 @@ class X393McntrlTiming(object):
delay[1].append(vrlg.get_default_field("DLY_LANE1_IDELAY",i))
if isinstance(delay,(int,long)):
delay=(delay,delay)
if self.DEBUG_MODE > 1:
if quiet < 2:
print("SET DQ IDELAY="+hexMultiple(delay)) # hexMultiple
self.axi_set_multiple_delays(vrlg.LD_DLY_LANE0_IDELAY, 0, 8, delay[0], "DLY_LANE0_IDELAY")
self.axi_set_multiple_delays(vrlg.LD_DLY_LANE1_IDELAY, 0, 8, delay[1], "DLY_LANE1_IDELAY")
......
......@@ -611,11 +611,13 @@ class X393PIOSequences(object):
# Set MR3, read nrep*8 words, save to buffer (port0). No ACTIVATE/PRECHARGE are needed/allowed
def set_read_pattern (self,
nrep, # input integer nrep;
sel=1, # 0 - early, 1 - late read command (shift by a SDCLK period)
verbose=0):
"""
Setup read pattern sequence at parameter defined address in the sequencer memory
<nrep> number of times pattern burst is read
<sel> 0 - early, 1 - late read command (shift by a SDCLK period)
<verbose> print data being written (default: False)
"""
......@@ -639,43 +641,43 @@ class X393PIOSequences(object):
# first read
#@ read
# addr bank RCW ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD NOP, B_RST
data=self.func_encode_cmd( 0, 0, 2, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0)
data=self.func_encode_cmd( 0, 0, 2, 0, 0, sel, 0, 0, 0, 1, 1, 0, 0, 0)
self.x393_mem.axi_write_single_w(cmd_addr, data, verbose)
cmd_addr += 1
# nop (combine with previous?)
# skip done bank ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD B_RST
data=self.func_encode_skip( 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0)
data=self.func_encode_skip( 0, 0, 0, 0, 0, sel, 0, 0, 0, 1, 1, 0, 0)
self.x393_mem.axi_write_single_w(cmd_addr, data, verbose)
cmd_addr += 1
#repeat remaining reads
# for (i = 1; i < nrep; i = i + 1) begin
for _ in range(1,nrep):
# addr bank RCW ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD NOP, B_RST
data=self.func_encode_cmd( 0, 0, 2, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0)
data=self.func_encode_cmd( 0, 0, 2, 0, 0, sel, 0, 0, 0, 1, 1, 0, 1, 0)
self.x393_mem.axi_write_single_w(cmd_addr, data, verbose)
cmd_addr += 1
# nop - all 3 below are the same? - just repeat?
# skip done bank ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD B_RST
data=self.func_encode_skip( 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0)
data=self.func_encode_skip( 0, 0, 0, 0, 0, sel, 0, 0, 0, 1, 0, 0, 0)
self.x393_mem.axi_write_single_w(cmd_addr, data, verbose)
cmd_addr += 1
# nop
# skip done bank ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD B_RST
data=self.func_encode_skip( 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0)
data=self.func_encode_skip( 0, 0, 0, 0, 0, sel, 0, 0, 0, 1, 0, 0, 0)
self.x393_mem.axi_write_single_w(cmd_addr, data, verbose)
cmd_addr += 1
# nop
# skip done bank ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD B_RST
data=self.func_encode_skip( 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0)
data=self.func_encode_skip( 0, 0, 0, 0, 0, sel, 0, 0, 0, 1, 0, 0, 0)
self.x393_mem.axi_write_single_w(cmd_addr, data, verbose)
cmd_addr += 1
# nop, no write buffer - next page
# skip done bank ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD B_RST
data=self.func_encode_skip( 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1)
data=self.func_encode_skip( 0, 0, 0, 0, 0, sel, 0, 0, 0, 1, 0, 0, 1)
self.x393_mem.axi_write_single_w(cmd_addr, data, verbose)
cmd_addr += 1
# skip done bank ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD B_RST
data=self.func_encode_skip( 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0)
data=self.func_encode_skip( 1, 0, 0, 0, 0, sel, 0, 0, 0, 1, 0, 0, 0)
self.x393_mem.axi_write_single_w(cmd_addr, data, verbose)
cmd_addr += 1
# Turn off read pattern mode
......@@ -995,6 +997,55 @@ class X393PIOSequences(object):
print ("WLEV lanes ratios: %f %f, non 0x00/0x01 bytes: %f"%(rslt[0],rslt[1],rslt[2]))
return rslt
def read_levelling(self,
nrep,
sel=1, # 0 - early, 1 - late read command (shift by a SDCLK period), -1 - use current sequence
quiet=1):
"""
Read and process data in 'read patter' mode
refresh may be off, delays: cmda_edelay, dq_idelay, dqs_idelauy should be set
<nrep> number of times pattern burst is read (8-bursts), actually will be read nrep+3, nut the first/last will be discarded
<sel> 0 - early, 1 - late read command (shift by a SDCLK period)
"""
if sel>=0:
self.set_read_pattern(nrep+3,sel) # do not use first/last pair of the 32 bit words
buf= self.read_pattern((4*(nrep+1)+2), # num,
(0,1)[quiet<1], # show_rslt,
1) # Wait for operation to complete
buf= buf[4:] # discard first 4*32-bit words
if quiet <1:
hbuf=[]
for dd in buf:
hbuf.append(hex(dd))
print(hbuf)
# with "good" data each word in buf should be 0xff00ff00
for d in buf:
if d !=0xffffffff:
break
else: # Maybe it is not needed with correct cmda_odelay ?
if quiet<3:
print ("Got a block of bad data during read pattern")
return None
data=[0]*32 # for each bit - even, then for all - odd
for w in range (4 * nrep):
lane=w%2
for wb in range(32):
g=(wb/8)%2
b=wb%8+lane*8+16*g
if (buf[w+2] & (1<<wb) != 0):
data[b]+=1
scale=1.0/(4*nrep)
for i in range(32):
data[i]*=scale
if quiet < 2:
for i in range(32):
print("%.2f"%data[i],end=" ")
print()
return data
def restart_ddr3(self,
wait_complete=True,
quiet=1):
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment