Commit 45d1f6b7 authored by Andrey Filippov's avatar Andrey Filippov

Adding selection correct branch of read/write delays (considering full/half clock cycles)

parent 8ffbbc62
......@@ -3,6 +3,6 @@
-f /usr/local/verilog/x393_parameters.vh /usr/local/verilog/x393_cur_params_target.vh /usr/local/verilog/x393_localparams.vh
-l /usr/local/verilog/x393_cur_params_target.vh
-p PICKLE="/usr/local/verilog/x393_mcntrl.pickle
-c measure_all "ICWRPOASZ" 1 2 2 3
-c measure_all "ICWRPOASZ" 1 2 2 0xaa 3
-c set_phase_delays 15 'A' 'A' 1 None 0
-c save
......@@ -847,7 +847,7 @@ class X393LMA(object):
print()
return data_periods_map
def lma_fit_dqi_dqsi(self,
def lma_fit_dq_dqs(self,
lane, # byte lane
bin_size,
clk_period,
......@@ -885,8 +885,11 @@ class X393LMA(object):
numLanes=2
parametersKey='parameters'
errorKey='maxErrDqs'
tDQKey='tDQ'
earlyKey,nominalKey,lateKey=('early','nominal','late')
# periods={earlyKey:-1,nominalKey:0,lateKey:1} #t0~= +1216 t1~=-1245
for lane in range(numLanes):
lane_rslt.append(self.lma_fit_dqi_dqsi(lane, # byte lane
lane_rslt.append(self.lma_fit_dq_dqs(lane, # byte lane
bin_size,
clk_period,
dly_step_ds,
......@@ -894,7 +897,56 @@ class X393LMA(object):
data_set,
compare_prim_steps,
scale_w,
quiet))
quiet))
#fix parameters if they have average tDQ different by +/- period(s)
tDQ_avg=[]
for lane in range(numLanes):
tDQ_avg.append(sum(lane_rslt[lane][parametersKey][tDQKey])/len(lane_rslt[lane][parametersKey][tDQKey]))
per1_0=int(round((tDQ_avg[1]-tDQ_avg[0])/clk_period))
if abs(tDQ_avg[1]-tDQ_avg[0]) > clk_period/2:
if quiet <5:
print ("lma_fit_dq_dqs: Data lanes tDQ average differs by %.1fps (%d clocks), shifting to match"%(abs(tDQ_avg[1]-tDQ_avg[0]),per1_0))
if abs(per1_0) > 1:
raise Exception ("BUG: lma_fit_dq_dqs: dta lanes differ by more than a period (per1_0=%d periods) - should not happen"%(per1_0))
#see number of valid items in early,nominal,late branches of each lane
numInVar=[{},{}]
for lane in range(numLanes):
for k in lane_rslt[lane].keys():
if (k != parametersKey) and (k != errorKey):
numValid=0
try:
for ph in lane_rslt[lane][k]:
if not ph is None:
numValid+=1
except:
pass
numInVar[lane][k]=numValid
if quiet < 2:
print ("numInVar=",numInVar)
late_lane=(0,1)[per1_0<0] # for late_lane E,N,L -> x, E, N, for not late_lane: E,N,L -> N, L, x
move_late_lane= (0,1)[numInVar[late_lane][earlyKey] <= numInVar[1-late_lane][lateKey]] # currently both are 0 - nothing is lost
tDQ_delta=clk_period*(-1,1)[move_late_lane]
lane_to_change=(1,0)[late_lane ^ move_late_lane]
if quiet < 2:
print ("late_lane= ",late_lane)
print ("move_late_lane=",move_late_lane)
print ("lane_to_change=",lane_to_change)
print ("tDQ_delta= ",tDQ_delta)
# modify tDQ:
for b in range(len(lane_rslt[lane_to_change][parametersKey][tDQKey])):
lane_rslt[lane_to_change][parametersKey][tDQKey][b]+=tDQ_delta
if quiet < 2:
print ("lane_rslt[%d]['%s']['%s']=%s"%(lane_to_change,parametersKey,tDQKey, str(lane_rslt[lane_to_change][parametersKey][tDQKey])))
# modify variants:
if move_late_lane:
lane_rslt[lane_to_change][earlyKey], lane_rslt[lane_to_change][nominalKey], lane_rslt[lane_to_change][lateKey]= (
lane_rslt[lane_to_change][nominalKey],lane_rslt[lane_to_change][lateKey], None)
else:
lane_rslt[lane_to_change][lateKey], lane_rslt[lane_to_change][nominalKey], lane_rslt[lane_to_change][earlyKey]= (
lane_rslt[lane_to_change][nominalKey],lane_rslt[lane_to_change][earlyKey], None)
# If there are only 2 ENL variants, make 'Nominal' - the largest
rslt={}
for k in lane_rslt[0].keys():
if (k != parametersKey) and (k != errorKey):
......@@ -924,8 +976,17 @@ class X393LMA(object):
rslt[parametersKey] = []
for lane in range(numLanes):
rslt[parametersKey].append(lane_rslt[lane][parametersKey])
#per1_0
#print parameters?
if quiet <4:
print ("'%s' = ["%(parametersKey))
for lane_params in rslt[parametersKey]:
print("{")
for k,v in lane_params.items():
print('%s:%s'%(k,str(v)))
print("},")
print ("]")
rslt[errorKey]={}
# print ("lane_rslt[0][errorKey]=",lane_rslt[0][errorKey])
for k in lane_rslt[0][errorKey].keys():
for r in lane_rslt: # lane_rslt is list of two dictionaries
try:
......@@ -951,14 +1012,7 @@ class X393LMA(object):
else:
rslt[errorKey][k].append(None)
# print ("lane_rslt[0][errorKey]=",lane_rslt[0][errorKey])
# print ("lane_rslt[1][errorKey]=",lane_rslt[1][errorKey])
# print ("combined: rslt['maxErrDqs']=",rslt['maxErrDqs'])
# print ("rslt=",rslt)
return rslt # byte lanes combined
# rslt['parameters']=parameters
# rslt['maxErrDqs']=DQvDQS_ERR # {enl}[dly]
......
......@@ -46,7 +46,11 @@ import x393_lma
import time
import vrlg
#NUM_FINE_STEPS= 5
NUM_DLY_STEPS =NUM_FINE_STEPS * 32 # =160
NUM_DLY_STEPS =NUM_FINE_STEPS * 32 # =160
DQI_KEY='dqi'
DQO_KEY='dqo'
ODD_KEY='odd'
class X393McntrlAdjust(object):
DRY_MODE= True # True
......@@ -211,12 +215,16 @@ class X393McntrlAdjust(object):
filter_dqso=2,
filter_dqsi=2,
filter_cmda=2,
filter_read=0,
filter_write=0,
filter_rsel=None,
filter_wsel=None,
keep_all=False,
set_table=True,
quiet=quiet+2)
self.adjustment_state['delays_phase']=delays_phase
except:
print ("Failed to execute get_'delays_vs_phase' command")
print ("Failed to execute 'get_delays_vs_phase' command")
return False
elif quiet < 2:
print ("using provided delays_phase")
......@@ -2312,6 +2320,10 @@ class X393McntrlAdjust(object):
filter_dqso=2,
filter_dqsi=2,
filter_cmda=2,
filter_read=0,
filter_write=0,
filter_rsel=None,
filter_wsel=None,
keep_all=False,
set_table=True,
quiet=quiet+2)
......@@ -2381,6 +2393,10 @@ class X393McntrlAdjust(object):
filter_dqso=0, #2,
filter_dqsi=1, #2,
filter_cmda=filter_cmda, #2, # special mode - try to keep cmda low, with setup violation to test marginal phase
filter_read=0,
filter_write=0,
filter_rsel=None,
filter_wsel=None,
keep_all=False,
set_table=False, # True,
quiet=quiet+2)
......@@ -2836,21 +2852,488 @@ class X393McntrlAdjust(object):
# Restore default write levelling sequence
self.x393_pio_sequences.set_write_lev(16,False) # write leveling - 'good' mode (if it was not set so)
return cmd_odelay
return cmd_odelay
def set_read_branch(self,
wbuf_dly=9,
quiet=1):
"""
Try read mode branches and find sel (early/late read command) and wbuf delay,
if possible
Detect shift by 1/2 clock cycle (should not happen), if it does proq_dqi_dqsi with duifferent prim_set (^2) is needed
delay vs. phase should be already calibrated
@param wbuf_dly - initial wbuf delay to try
@quiet reduce output
@return dictionary with key(s) (early,nominal,late) containing dictionary of {'wbuf_dly':xx, 'sel':Y}
optionally result may contain key 'odd' with a list of varinats that resulted in odd number of wrong words
if the remaining number of errors is odd
"""
if wbuf_dly is None:
wbuf_dly=vrlg.DFLT_WBUF_DELAY
try:
delays_phase=self.adjustment_state['delays_phase']
except:
print("Delays for phases (self.adjustment_state['delays_phase']) are not set, running 'get_delays_vs_phase' command ")
try:
delays_phase=self.get_delays_vs_phase(filter_dqo=2,
filter_dqi=2,
filter_dqso=2,
filter_dqsi=2,
filter_cmda=2,
filter_read=0,
filter_write=0,
filter_rsel=None,
filter_wsel=None,
keep_all=False,
set_table=True,
quiet=quiet+2)
self.adjustment_state['delays_phase']=delays_phase
except:
print ("Failed to execute get_'delays_vs_phase' command")
return False
#find one valid phase per existing branch
phase_var={}
for phase, dlys in enumerate(delays_phase):
try:
for k,v in dlys[DQI_KEY].items():
if (not k in phase_var) and (not None in v):
phase_var[k]=phase
except:
pass
if quiet <2:
print ("phase_var=",phase_var)
written=False
#write/used block parameters
startValue=0
ca=0
ra=0
ba=0
extraTgl=1 # just in case
wsel=1
rslt={}
odd_list=[]
for var,phase in phase_var.items():
OK=self.set_phase_delays(phase=phase,
refresh=True,
quiet=quiet+1) # all the rest are defaults
if not OK:
raise Exception("set_read_branch(): failed to set phase = %d"%(phase))
if not written:
#write_block_inc, it may turn out to be shifted, have problems at the beginning or end - write is not set up yet
self.x393_pio_sequences.write_block_inc(num8=64, # max 512 16-bit words
startValue=startValue,
ca=ca,
ra=ra,
ba=ba,
extraTgl=extraTgl,
sel=wsel,
quiet=quiet+1)
written=True
wbuf_dly_max=12
wdly=max(0,min(wbuf_dly,wbuf_dly_max))
rsel=0
#set_and_read_inc 8 16 0 0 1 1
last_wstep=0
read_problems=None
for _ in range(20):
self.x393_mcntrl_timing.axi_set_wbuf_delay(wdly)
read_problems=self.x393_pio_sequences. set_and_read_inc(num8=8, # max 512 16-bit words
ca=ca+16,
ra=ra,
ba=ba,
sel=rsel,
quiet=quiet+1)
if (read_problems[0]>=4) or ((rsel==0) and (read_problems[0]>=2)):
if last_wstep < 0:
if quiet < 1:
print ("reversed wstep to +1 at wdly = %d"%(wdly))
break
last_wstep = 1
wdly += 1
if wdly >= wbuf_dly_max:
print("Exceeded maximal write buffer delay = %d while setting up read for branch '%s', phase=%d"%(wdly,var,phase))
read_problems=None
break # continue with next branch
continue
if (read_problems[1]>4) or (rsel and (read_problems[1] == 4)):
if last_wstep > 0:
if quiet < 1:
print ("reversed wstep to -1 at wdly = %d"%(wdly))
break
last_wstep =- 1
wdly -= 1
if wdly < 1:
print("Exceeded minimal write buffer delay = %d while setting up read for branch '%s', phase=%d"%(wdly,var,phase))
read_problems=None
break # continue with next branch
continue
break # close to target
if read_problems is None:
continue # could not get initial wbuf delay
# read_problems_initial=read_problems
read_problems_min=read_problems
best_dw,best_sel=(0,0)
if quiet < 2:
print("var=",var)
print("Read_problems_min=",read_problems_min)
print("wdly=",wdly)
print("rsel=",rsel)
print("sum(read_problems_min)=",sum(read_problems_min))
if sum(read_problems_min) > 0:
for dw,sel in ((-1,0),(-1,1),(0,0),(0,1),(1,0),(1,1)):
self.x393_mcntrl_timing.axi_set_wbuf_delay(wdly+dw)
read_problems=self.x393_pio_sequences. set_and_read_inc(num8=8, # max 512 16-bit words
ca=ca+16,
ra=ra,
ba=ba,
sel=sel ^ rsel,
quiet=quiet+1)
if sum(read_problems) < sum(read_problems_min):
read_problems_min=read_problems
best_dw,best_sel= dw,sel
if sum(read_problems_min) == 0:
break
wdly += best_dw
rsel ^= best_sel
if quiet < 2:
print("-Read_problems_min=",read_problems_min)
print("-wdly=",wdly)
print("-rsel=",rsel)
print("-sum(read_problems_min)=",sum(read_problems_min))
if sum(read_problems_min) ==0:
rslt[var]={'wbuf_dly':wdly, 'sel':rsel}
if quiet < 2:
print("-rslt=",rslt)
elif (read_problems_min[0]%2) or (read_problems_min[1]%2):
odd_list.append(var)
if quiet < 3:
print("Failed to find read settings for varinat '%s', phase=%d - best start read errors=%d, end read errors=%d"%(
var,phase,read_problems_min[0],read_problems_min[1]))
print("Odd number of wrong read words means that there is a half clock period shift, you may need to change")
print("primary_set parameter of proc_dqi_dqsi() from 2 to 0" )
else:
if quiet < 2:
print("Failed to find read settings for varinat '%s', phase=%d - best start read errors=%d, end read errors=%d"%(
var,phase,read_problems_min[0],read_problems_min[1]))
if quiet < 2:
print("odd_list=",odd_list)
for var,v in rslt.items():
try:
self.x393_mcntrl_timing.axi_set_wbuf_delay(v['wbuf_dly'])
break
except:
pass
if odd_list:
rslt[ODD_KEY]=odd_list
self.adjustment_state['read_variants']=rslt
if quiet < 3:
print ('read_variants=',rslt)
return rslt
def set_write_branch(self,
dqs_pattern=None,
quiet=1):
"""
Try write mode branches and find sel (early/late write command), even if it does not match read settings
Read mode should already be set up
if possible
Detect shift by 1/2 clock cycle (should not happen), if it does proq_dqi_dqsi with duifferent prim_set (^2) is needed
delay vs. phase should be already calibrated
@param dqs_pattern - 0x55/0xaa - DQS output toggle pattern. When it is 0x55 primary_set_out is reversed ?
@quiet reduce output
@return dictioray with a key(s) (early,nominal,late) containing dictionary of {'wbuf_dly':xx, 'sel':Y} or value 'ODD'
if the remaining number of errors is odd
"""
#write/used block parameters
startValue=0
num8=8 # 8 bursts to read/write
ca=0
ra=0
ba=0
extraTgl=1 # just in case
wsel=1
rslt={}
readVarKey='read_variants'
if dqs_pattern is None:
dqs_pattern=vrlg.DFLT_DQS_PATTERN
else: # only set if not None
self.x393_mcntrl_timing.axi_set_dqs_dqm_patterns(dqs_patt=dqs_pattern, # use default
dqm_patt=None, # use default
quiet=quiet+2)
try:
delays_phase=self.adjustment_state['delays_phase']
except:
print("Delays for phases (self.adjustment_state['delays_phase']) are not set, running 'get_delays_vs_phase' command ")
try:
delays_phase=self.get_delays_vs_phase(filter_dqo=2,
filter_dqi=2,
filter_dqso=2,
filter_dqsi=2,
filter_cmda=2,
filter_read=0,
filter_write=0,
filter_rsel=None,
filter_wsel=None,
keep_all=False,
set_table=True,
quiet=quiet+2)
self.adjustment_state['delays_phase']=delays_phase
except:
print ("Failed to execute get_'delays_vs_phase' command")
return False
try:
readVars=self.adjustment_state[readVarKey]
except:
raise Exception ("Read variants are not set up, need to run command set_read_branch90 first")
#verify read varinats have valid (not "ODD") branch
readBranch=None
for var in readVars:
if var != ODD_KEY:
readBranch=var
break
else:
raise Exception ("No valid read variant is found, can not proceed with write setup")
readPhase=None
#find one valid phase per existing branch
phase_var={}
read_phase_var={}
for phase, dlys in enumerate(delays_phase):
try:
for k,v in dlys[DQO_KEY].items():
if not None in v:
if not k in phase_var:
phase_var[k]=phase
if not k in read_phase_var: # read phase is not set yet for this write variant
if not None in dlys[DQI_KEY][readBranch]: # usually will fail here
phase_var[k]= phase
read_phase_var[k] = phase
readPhase= phase # will hold phase that
except:
pass
if quiet <2:
print ("phase_var=",phase_var)
print ("readPhase=",readPhase)
print ("read_phase_var=",read_phase_var)
if not phase_var:
raise Exception("Could not find any valid phase for writing to consider")
if readPhase is None: #find some phase to correctly read data, even if it does not match any write phase
for phase, dlys in enumerate(delays_phase):
try:
if not None in dlys[DQI_KEY][readBranch]: # usually will fail here
readPhase= phase
break
except:
pass
else:
raise Exception("Could not find any valid phase to read block correctly")
#see if any of the write varinats does not have read phase - use default readPhase
for var in phase_var:
if not var in read_phase_var:
read_phase_var[var]=readPhase
if quiet <2:
print ("phase_var=",phase_var)
print ("readPhase=",readPhase)
print ("read_phase_var=",read_phase_var)
if quiet <1:
print ("readVars=",readVars)
self.x393_mcntrl_timing.axi_set_wbuf_delay(readVars[readBranch]['wbuf_dly'])
rsel=readVars[readBranch]['sel']
odd_list=[]
for var,phase in phase_var.items():
problems_min=None
best_wsel=None
for wsel in range (2):
OK=self.set_phase_delays(phase=phase,
refresh=True,
quiet=quiet+2) # all the rest are defaults
if not OK:
raise Exception("set_read_branch(): failed to set phase = %d"%(phase))
self.x393_pio_sequences.write_block_inc(num8=num8, # max 512 16-bit words
startValue=startValue,
ca=ca,
ra=ra,
ba=ba,
extraTgl=extraTgl,
sel=wsel,
quiet=quiet+1)
startValue += 0x200
startValue &= 0xffff
if phase != read_phase_var[var]:
OK=self.set_phase_delays(phase=read_phase_var[var],
refresh=True,
quiet=quiet+2) # all the rest are defaults
if not OK:
raise Exception("set_read_branch(): failed to set phase = %d"%(phase))
problems=self.x393_pio_sequences. set_and_read_inc(num8=num8, # max 512 16-bit words
ca=ca,
ra=ra,
ba=ba,
sel=rsel,
quiet=quiet+1)
if (problems_min is None) or (sum(problems) < sum(problems_min)):
problems_min=problems
best_wsel=wsel
if sum(problems_min) == 0:
rslt[var]={'sel':best_wsel}
elif (problems_min[0]%2) or (problems_min[1]%2):
odd_list.append(var)
if quiet < 3:
print("Failed to find write settings for varinat '%s', phase=%d - best start write errors=%d, end write errors=%d, wsel=%d"%(
var,phase,problems_min[0],problems_min[1],best_wsel))
print("Odd number of wrong read words means that there is a half clock period shift, you may need to change")
print("primary_set parameter of proc_dqo_dqso() 2 <->0 or change DQS pattern (0x55<->0xAA)" )
print("Using of DQS PATTERN of 0xAA (output will start from 0, not 1) is not optimal, it requires extra toggling" )
print("of the DQS line after the end of block write" )
else:
if quiet < 2:
print("Failed to find write settings for varinat '%s', phase=%d - best start read errors=%d, end read errors=%d, wsel=%d"%(
var,phase,problems_min[0],problems_min[1],best_wsel))
if odd_list:
rslt[ODD_KEY]=odd_list
self.adjustment_state['write_variants']=rslt
if quiet < 3:
print ('write_variants=',rslt)
return rslt
def get_phase_range(self,
rsel=None, # None (any) or 0/1
wsel=None, # None (any) or 0/1
quiet=3):
"""
@param rsel filter by early/late read command (in two-clock command cycle - 'sel') Valid values: None, 0 or 1
@param wsel filter by early/late write command (in two-clock command cycle - 'sel') Valid values: None, 0 or 1
@param quiet reduce output
@return {'optimal_phase': optimal phase, 'rsel': read_sel, 'wsel': write_sel, 'min_phase': minimal_phase, 'max_phase': maximal_phase}
'max_phase' may be lower than 'min_phase' if the range rolls over
"""
# self.load_mcntrl('dbg/state_0x55.pickle')
try:
read_variants=self.adjustment_state['read_variants']
except:
read_variants=None
try:
write_variants=self.adjustment_state['write_variants']
except:
write_variants=None
try:
delays_phase=self.get_delays_vs_phase(filter_dqo=2,
filter_dqi=2,
filter_dqso=2,
filter_dqsi=2,
filter_cmda=2,
filter_read=True,
filter_write=True,
filter_rsel=rsel,
filter_wsel=wsel,
keep_all=False,
set_table=True,
# quiet=quiet+2)
quiet=quiet)
self.adjustment_state['delays_phase']=delays_phase
except:
print ("Failed to execute 'get_delays_vs_phase' command")
return None
phase_starts=[]
numPhases=len(delays_phase)
for phase,dlys in enumerate (delays_phase):
if (not dlys is None) and (delays_phase[(phase-1) % numPhases] is None):
phase_starts.append(phase)
phase_lengths=[]
if phase_starts:
for phase_start in phase_starts:
for phase in range(phase_start+1,phase_start+numPhases):
p=phase % numPhases
if delays_phase[p] is None:
phase_lengths.append((p-phase_start) % numPhases)
break
best_len= max(phase_lengths)
best_start=phase_starts[phase_lengths.index(best_len)]
else: # no ends, maybe all None, or all non-None
if delays_phase[0] is None:
return None
else: # all are valid
best_start=0
best_len=numPhases
#find center
rslt={}
optimal_phase= (best_start+best_len//2) % numPhases
rslt['optimal_phase'] = optimal_phase
rslt['min_phase'] = best_start
rslt['max_phase'] = (best_start+best_len-1) % numPhases
read_var="A"
write_var="A"
if quiet < 2:
print ("result=",rslt)
print ("phase_starts=",phase_starts)
print ("phase_lengths=",phase_lengths)
if not read_variants is None:
# find common variants in read_variants and delays_phase[optimal_phase] - in the future there may be several of them!
variants=[]
for var in read_variants.keys():
if quiet < 1:
print ("var=",var)
print ("delays_phase[optimal_phase]=",delays_phase[optimal_phase])
print ("delays_phase[optimal_phase][DQI_KEY]=",delays_phase[optimal_phase][DQI_KEY])
if var in delays_phase[optimal_phase][DQI_KEY]:
variants.append(var)
if variants:
rslt['rsel'] = read_variants[variants[0]]['sel']
read_var=variants[0][0].upper()
if not write_variants is None:
# find common variants in write_variants and delays_phase[optimal_phase] - in the future there may be several of them!
variants=[]
for var in write_variants.keys():
if var in delays_phase[optimal_phase][DQO_KEY]:
variants.append(var)
if variants:
rslt['wsel'] = write_variants[variants[0]]['sel']
write_var=variants[0][0].upper()
if quiet < 4:
print ("result=",rslt)
#set delays to set Verilog parameters. TODO: save sel-s somehow too?
self.set_phase_delays(phase=optimal_phase,
inp_period=read_var,
out_period=write_var,
refresh=False,
delays_phase=delays_phase, # if None - use global
quiet=quiet)
return rslt
def measure_all(self,
tasks="ICWRPOASZ",
prim_steps=1,
primary_set_in=2,
primary_set_out=2,
dqs_pattern=0xaa,
quiet=3):
"""
@param tasks - "C" cmda, "W' - write levelling, "R" - read levelling (DQI-DQSI), "P" - dqs input phase (DQSI-PHASE),
"O" - output timing (DQ odelay vs DQS odelay), "A" - address/bank lines output delays, "Z" - print results
@param prim_steps - compare measurement with current delay with one lower by 1 primary step (5 fine delay steps), 0 -
compare with one fine step lower
@param primary_set_in - which of the primary sets to use when processing DQi/DQSi results (2 - normal, 0 - other DQS phase)
@param primary_set_out - which of the primary sets to use when processing DQo/DQSo results (2 - normal, 0 - other DQS phase)
@param dqs_pattern - 0x55/0xaa - DQS output toggle pattern. When it is 0x55 primary_set_out is reversed ?
@param quiet reduce output
"""
# dqs_pattern=0x55 # 0xaa
max_phase_err=0.1
frac_step=0.125
# read_sel=1 # set DDR3 command in the second cycle of two (0 - during the first omne)
......@@ -2874,9 +3357,8 @@ class X393McntrlAdjust(object):
{'key':'I',
'func':self.x393_pio_sequences.task_set_up,
'comment':'Initial setup - memory controller, sequnces',
'params':{'quiet':quiet+1}},
'params':{'dqs_pattern':dqs_pattern,
'quiet':quiet+1}},
{'key':'C',
'func':self.adjust_cmda_odelay,
'comment':'Measuring CMDA output delay for each clock phase',
......@@ -2971,6 +3453,10 @@ class X393McntrlAdjust(object):
'filter_dqso':2,
'filter_dqsi':2,
'filter_cmda':2,
'filter_read':0,
'filter_write':0,
'filter_rsel':None,
'filter_wsel':None,
'keep_all':False,
'set_table':True,
'quiet':quiet+1}},
......@@ -3089,7 +3575,7 @@ class X393McntrlAdjust(object):
if quiet<1:
x393_lma.test_data(meas_delays,compare_prim_steps,quiet)
lma=x393_lma.X393LMA()
rslt = lma.lma_fit_dqi_dqsi(lane,
rslt = lma.lma_fit_dq_dqs(lane,
bin_size,
1000.0*self.x393_mcntrl_timing.get_dly_steps()['SDCLK_PERIOD'], # 2500.0, # clk_period,
78.0, # dly_step_ds,
......@@ -3235,7 +3721,7 @@ class X393McntrlAdjust(object):
if quiet<1:
x393_lma.test_data(meas_delays,compare_prim_steps,quiet)
lma=x393_lma.X393LMA()
rslt = lma.lma_fit_dqi_dqsi(lane,
rslt = lma.lma_fit_dq_dqs(lane,
bin_size,
1000.0*self.x393_mcntrl_timing.get_dly_steps()['SDCLK_PERIOD'], # 2500.0, # clk_period,
78.0, # dly_step_ds,
......@@ -3607,6 +4093,10 @@ class X393McntrlAdjust(object):
filter_dqso=2,
filter_dqsi=2,
filter_cmda=2,
filter_read=0,
filter_write=0,
filter_rsel=None,
filter_wsel=None,
keep_all=False,
set_table=True,
quiet=2):
......@@ -3620,6 +4110,12 @@ class X393McntrlAdjust(object):
@param filter_dqsi for DQS input delays
@param filter_cmda for command and address output delays
if non-integer - special mode - try to keep cmda low, with setup violation to test marginal phase
@param filter_read remove phases that do not provide correct reads (data shifted by some periods/half periods)
@param filter_write remove phases that do not provide correct writes (data shifted by some periods/half periods)
@param filter_rsel filter by early/late read command (in two-clock command cycle - 'sel') Valid values: None, 0 or 1
@param filter_wsel filter by early/late write command (in two-clock command cycle - 'sel') Valid values: None, 0 or 1
@param keep_all Keep phases where some delays do not have valid values, just mark them as None
remove just items that do not have any non-None elements
@param set_table store results to the global table (used to simultaneously set all pahse-derived
......@@ -3641,6 +4137,37 @@ class X393McntrlAdjust(object):
# clk_period=1000.0*timing['SDCLK_PERIOD'] # in PS
if quiet <1:
print ("halfDlyRange=",halfDlyRange)
try:
read_variants=self.adjustment_state['read_variants']
except:
read_variants=None
try:
write_variants=self.adjustment_state['write_variants']
except:
write_variants=None
if filter_read or (not filter_rsel is None):
if not read_variants is None:
filter_read=1 # if filter_rsel is not None
if filter_dqsi==0:
filter_dqsi=2
if filter_dqi==0:
filter_dqi=2
else:
print ('Data for filter_read is not available (self.adjustment_state["read_variants"]')
filter_read=0
filter_rsel=None
if filter_write or (not filter_wsel is None):
if not write_variants is None:
filter_write=1 # if filter_wsel is not None
if filter_dqso==0:
filter_dqso=2
if filter_dqo==0:
filter_dqo=2
else:
print ('Data for filter_write is not available (self.adjustment_state["write_variants"]')
filter_write=0
filter_wsel=None
delays_phase=[]
if filter_dqo:
try:
......@@ -3764,6 +4291,10 @@ class X393McntrlAdjust(object):
else:
if None in dqi:
continue # not this branch
elif filter_read and not k in read_variants:
continue # not this branch
elif (not filter_rsel is None) and (k in read_variants) and (read_variants[k]['sel'] != filter_rsel):
continue # not this branch
elif (filter_dqi == 2) and ((max(dqi) - min(dqi)) > halfDlyRange):
continue # failed filter, continue to the next branch
dqi_options[k]=dqi
......@@ -3788,6 +4319,10 @@ class X393McntrlAdjust(object):
else:
if None in dqo:
continue # not this branch
elif filter_write and not k in write_variants:
continue # not this branch
elif (not filter_wsel is None) and (k in write_variants) and (write_variants[k]['sel'] != filter_wsel):
continue # not this branch
elif (filter_dqi == 2) and ((max(dqo) - min(dqo)) > halfDlyRange):
continue # failed filter, continue to the next branch
dqo_options[k]=dqo
......@@ -3849,6 +4384,9 @@ class X393McntrlAdjust(object):
break
except:
pass
if numBits is None:
print ("No phase has all delays valid")
return delays_phase
numLanes=numBits//8
try:
maxErrDqsi=self.adjustment_state["maxErrDqsi"]
......@@ -3879,15 +4417,21 @@ class X393McntrlAdjust(object):
print("%s-DQ%di"%(k.upper()[0], b),end=" ")
for lane in range(numLanes):
print("DQS%d0"%(lane),end=" ")
#TODO: add DQ%do
for k in enl_list_out:
for b in range(numBits):
print("%s-DQ%do"%(k.upper()[0], b),end=" ")
if not read_variants is None:
for k in enl_list_in:
print("%s-rsel"%(k.upper()[0]),end=" ")
if not write_variants is None:
for k in enl_list_out:
print("%s-wsel"%(k.upper()[0]),end=" ")
for k in enl_list_in:
print("%s-in-err"%(k.upper()[0]),end=" ")
for k in enl_list_out:
print("%s-out-err"%(k.upper()[0]),end=" ")
print()
print()
#print table rows
for phase, phase_data in enumerate(delays_phase):
print ("%d"%(phase),end=" ")
......@@ -3926,13 +4470,30 @@ class X393McntrlAdjust(object):
print ("%d"%(phase_data['dqo'][k][b]),end=" ")
except:
print ("?",end=" ")
if not read_variants is None:
for k in enl_list_in:
try:
if not None in phase_data['dqi'][k]:
print ("%d"%(10*read_variants[k]['sel']),end=" ")# 10* - for graph visibility
else:
print ("?",end=" ")
except:
print ("?",end=" ")
if not write_variants is None:
for k in enl_list_out:
try:
# print ('k=',k,end=" ")
# print ("phase_data['dqo']=",phase_data['dqo'])
if not None in phase_data['dqo'][k]:
print ("%d"%(12*write_variants[k]['sel']),end=" ")# 12* - for graph visibility
else:
print ("?",end=" ")
except:
print ("?",end=" ")
for k in enl_list_in:
try:
if not None in phase_data['dqsi']:
max_err=max(maxErrDqsi[k][dly][lane] for lane,dly in enumerate(phase_data['dqsi']))
# for dly in phase_data['dqsi']:
# err=maxErrDqsi[k][dly]
# print("%.1f"%(err),end=" ")
print("%.1f"%(max_err),end=" ")
else:
print ("X",end=" ")
......@@ -3956,7 +4517,10 @@ class X393McntrlAdjust(object):
def show_all_vs_phase(self,
keep_all=False,
load_hardcoded=False):
load_hardcoded=False,
filter_rw=False,
filter_rsel=None,
filter_wsel=None):
'''
Show table (to be copied to a spreadsheet) with all delay settings for each
DDR3 memory clock phase value
......@@ -3973,6 +4537,10 @@ class X393McntrlAdjust(object):
filter_dqso=2,
filter_dqsi=2,
filter_cmda=2,
filter_read=(0,1)[filter_rw], #
filter_write=(0,1)[filter_rw],
filter_rsel=filter_rsel,
filter_wsel=filter_wsel,
keep_all=keep_all,
set_table=False,
quiet=2)
......
......@@ -117,17 +117,18 @@ class X393McntrlBuffers(object):
def write_block_incremtal(self,
start_word_address, # input [29:0] start_word_address;
num_words, # input integer num_words; # number of words to write (will be rounded up to multiple of 16)
start_value): # input integer start_value;
start_value, # input integer start_value;
quiet=1):
"""
Fill buffer the incremental data (each next register is written with previous register data + 1
<start_word_address> full register address in AXI space (in 32-bit words, not bytes)
<num_words> number of 32-bit words to generate/write
<start_value> value to write to the first register (to start_word_address)
@param start_word_address full register address in AXI space (in 32-bit words, not bytes)
@param num_words number of 32-bit words to generate/write
@start_value value to write to the first register (to start_word_address)
"""
if self.verbose>0:
if quiet < 2:
print("**** write_block_incremtal, start_word_address=0x%x, num_words=0x%x, start_value=0x%x "%(start_word_address,num_words,start_value))
for i in range(0,num_words):
if self.verbose>2:
if quiet < 1:
print(" write_block_buf 0x%x:0x%x"%(start_word_address+i,start_value+i))
self.x393_mem.axi_write_single_w(start_word_address+i, start_value+i)
......
......@@ -533,21 +533,24 @@ class X393McntrlTiming(object):
def axi_set_dqs_dqm_patterns(self,
dqs_patt=None,
dqm_patt=None):
dqm_patt=None,
quiet=1):
"""
Set sequencer patterns for the DQ lines ON/OFF (defined by parameters)
<dqs_patt> DQS toggle pattern (if None - use DFLT_DQS_PATTERN (currently 0xaa)
<dm_patt> DM pattern (if None - use DFLT_DQM_PATTERN (currently 0x00) should be 0 for now
@param dqs_patt DQS toggle pattern (if None - use DFLT_DQS_PATTERN (currently 0xaa)
@param dm_patt DM pattern (if None - use DFLT_DQM_PATTERN (currently 0x00) should be 0 for now
@param quiet reduce output
"""
if dqs_patt is None:
dqs_patt=vrlg.DFLT_DQS_PATTERN
if dqm_patt is None:
dqm_patt=vrlg.DFLT_DQM_PATTERN
patt = (dqs_patt & 0xff) | ((dqm_patt & 0xff) << 8)
if self.DEBUG_MODE > 1:
if quiet <2 :
print("SET DQS+DQM PATTERNS, patt= 0x%08x"%patt)
# set patterns for DM (always 0) and DQS - always the same (may try different for write lev.)
self.x393_axi_tasks.write_contol_register(vrlg.MCONTR_PHY_16BIT_ADDR + vrlg.MCONTR_PHY_16BIT_PATTERNS, patt) # 32'h0055);
def util_test4(self):
# print("vrlg.globals():")
# print(vrlg.globals())
......
......@@ -38,7 +38,7 @@ from x393_mem import X393Mem
import x393_axi_control_status
from x393_mcntrl_buffers import X393McntrlBuffers
#from verilog_utils import * # concat, bits
from verilog_utils import concat, bits
from verilog_utils import concat, bits, convert_mem16_to_w32, convert_w32_to_mem16
#from x393_axi_control_status import concat, bits
import vrlg # global parameters
from time import sleep
......@@ -527,13 +527,13 @@ class X393PIOSequences(object):
"""
Setup write block sequence at parameter defined address in the sequencer memory
@ba 3-bit memory bank address
@ra 15-bit memory row address
@ca 10-bit memory column address
@num8 - number of 8-bursts (default=64, should be >2)
@extraTgl add extra 8-burst of toggling DQS
@sel - 0 - early, 1 - late read command
@verbose print data being written (default: False)
@param ba 3-bit memory bank address
@param ra 15-bit memory row address
@param ca 10-bit memory column address
@param num8 - number of 8-bursts (default=64, should be >2)
@param extraTgl add extra 8-burst of toggling DQS
@param sel - 0 - early, 1 - late read command
@param verbose print data being written (default: False)
"""
if verbose > 0:
print("===set_write_block ba=0x%x, ra=0x%x, ca=0x%x, num8=%d extraTgl=%d, sel=%d, verbose=%d"%(ba,ra,ca,num8,extraTgl,sel, verbose))
......@@ -974,15 +974,15 @@ class X393PIOSequences(object):
return self.x393_mcntrl_buffers.read_block_buf_chn (0, 2, num, show_rslt ) # chn=0, page=2, number of 32-bit words=num, show_rslt
def read_block(self,
num,
show_rslt,
wait_complete=1): # Wait for operation to complete
num,
show_rslt,
wait_complete=1): # Wait for operation to complete
"""
Read block in PS PIO mode
<num> number of 32-bit words to read
<show_rslt> print read data
<wait_complete> wait read pattern operation to complete (0 - may initiate multiple PS PIO operations)
returns list of the read data
@param num number of 32-bit words to read
@param show_rslt print buffer data read 1 - column, 16 - as 16-bit (memory words), 32 - as 32-bit (data words)
@param wait_complete wait read pattern operation to complete (0 - may initiate multiple PS PIO operations)
@return list of the read data
"""
self.schedule_ps_pio ( # schedule software-control memory operation (may need to check FIFO status first)
......@@ -1012,6 +1012,117 @@ class X393PIOSequences(object):
# temporary - for debugging:
# self.wait_ps_pio_done(vrlg.DEFAULT_STATUS_MODE,1) # wait previous memory transaction finished before changing delays (effective immediately)
def write_block_inc(self,
num8=64, # max 512 16-bit words
startValue=0,
ca=0,
ra=0,
ba=0,
extraTgl=0, #
sel=1,
quiet=1):
"""
Program sequencer, fill buffer with incremented 16-bit wors (startValue, startValue+1...startValue+nrep*8-1)
and write buffer to memory
@param num8 number of 8-bursts (default=64, should be >2)
@param startValue - value of the first word to write
@param ca 10-bit memory column address
@param ra 15-bit memory row address
@param ba 3-bit memory bank address
@param extraTgl add extra 8-burst of toggling DQS
@param sel 0 - early, 1 - late read command
@param quiet reduce output
"""
self.set_write_block(ba=ba, # input[2:0]ba;
ra=ra, # input[14:0]ra;
ca=ca, # input[9:0]ca;
num8=num8,
extraTgl=extraTgl, #
sel=sel,
verbose=(0,1)[quiet < 2])
wdata16=[startValue+i for i in range(num8*8)]
wdata32=convert_mem16_to_w32(wdata16)
self.x393_mcntrl_buffers.write_block_buf_chn(0,0,wdata32,quiet) # fill block memory (channel, page, number)
self.write_block()
def set_and_read(self,
show_rslt=16,
num8=64, # max 512 16-bit words
ca=0,
ra=0,
ba=0,
sel=1,
quiet=1):
"""
Program sequencer, read block from memory and optionally print it
@param show_rslt: 0 - silent, 1 - as column, 16 - as 16-bit memory words, 32 - as 32-bit (system) words
@param num8 number of 8-bursts (default=64, should be >2)
@param ca 10-bit memory column address
@param ra 15-bit memory row address
@param ba 3-bit memory bank address
@param sel 0 - early, 1 - late read command
@param quiet reduce output
@return read data as 32-bit words
"""
self.set_read_block(ba=ba, # input[2:0]ba;
ra=ra, # input[14:0]ra;
ca=ca, # input[9:0]ca;
num8=num8,
sel=sel,
verbose=(0,1)[quiet < 2])
return self.read_block(num= num8*4,
show_rslt=show_rslt,
wait_complete=1) # Wait for operation to complete
def set_and_read_inc(self,
num8=64, # max 512 16-bit words
ca=0,
ra=0,
ba=0,
sel=1,
quiet=1):
"""
Program sequencer, read block from memory,optionally print it
Epecting incremental 16-bit data block, calculate number of leading and trailing
non-consecutive words and return them as a tuple
@param num8 number of 8-bursts (default=64, should be >2)
@param ca 10-bit memory column address
@param ra 15-bit memory row address
@param ba 3-bit memory bank address
@param sel 0 - early, 1 - late read command
@param quiet reduce output
@return read data as 32-bit words
"""
data32=self.set_and_read(
show_rslt=(0,16)[quiet<2],
num8=num8, # max 512 16-bit words
ca=ca,
ra=ra,
ba=ba,
sel=sel,
quiet=quiet+1)
data16=convert_w32_to_mem16(data32)
mid_index=len(data16)//2
data0= data16[mid_index]-mid_index
for i in range(mid_index-1,-1,-1):
if data16[i] != data0 + i:
first_bad=i+1
break
else:
first_bad= 0
for i in range(mid_index+1,len(data16)):
if data16[i] != data0 + i:
last_bad=len(data16)-i
break
else:
last_bad= 0
if quiet < 3:
print ("non_consecutive leading/trailing: %d /%d"%(first_bad, last_bad))
return (first_bad, last_bad)
def write_levelling(self,
wait_complete=1, # Wait for operation to complete
......@@ -1160,6 +1271,7 @@ class X393PIOSequences(object):
def task_set_up(self,
dqs_pattern=None,
quiet = 1):
"""
Initial setup of the memory controller, including:
......@@ -1173,7 +1285,7 @@ class X393PIOSequences(object):
I/O delays
clock phase
write buffer latency
<set_per_pin_delays> - 1 - set individual (per-pin) I/O delays, 0 - use common for the whole class
@param dqs_pattern None - use Verilog parameter, other values 0xaa or 0x55 - DQS output value per 1/2 SDCLK period
Returns 1 if phase was set, 0 if it failed
"""
#reset memory controller
......@@ -1185,7 +1297,9 @@ class X393PIOSequences(object):
# set dq /dqs tristate on/off patterns
self.x393_mcntrl_timing.axi_set_tristate_patterns()
# set patterns for DM (always 0) and DQS - always the same (may try different for write lev.)
self.x393_mcntrl_timing.axi_set_dqs_dqm_patterns()
self.x393_mcntrl_timing.axi_set_dqs_dqm_patterns(dqs_patt=dqs_pattern, # use default
dqm_patt=None, # use default
quiet=1)
# prepare all sequences
self.set_all_sequences(quiet)
# prepare write buffer
......
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