from __future__ import print_function ''' # Copyright (C) 2015, Elphel.inc. # Class based on earlier code to produce eye patterns # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . @author: Andrey Filippov @copyright: 2015 Elphel, Inc. @license: GPLv3.0+ @contact: andrey@elphel.coml @deffield updated: Updated ''' __author__ = "Andrey Filippov" __copyright__ = "Copyright 2015, Elphel, Inc." __license__ = "GPL" __version__ = "3.0+" __maintainer__ = "Andrey Filippov" __email__ = "andrey@elphel.com" __status__ = "Development" import random from x393_mem import X393Mem import x393_axi_control_status from x393_pio_sequences import X393PIOSequences from x393_mcntrl_timing import X393McntrlTiming from x393_mcntrl_buffers import X393McntrlBuffers from verilog_utils import checkIntArgs,smooth2d,split_delay,combine_delay,NUM_FINE_STEPS, convert_w32_to_mem16,convert_mem16_to_w32 import vrlg #NUM_FINE_STEPS= 5 NUM_DLY_STEPS =NUM_FINE_STEPS * 32 # =160 class X393McntrlEyepattern(object): DRY_MODE= True # True DEBUG_MODE=1 x393_mem=None x393_axi_tasks=None #x393X393AxiControlStatus x393_pio_sequences=None x393_mcntrl_timing=None x393_mcntrl_buffers=None verbose=1 adjustment_state={} def __init__(self, debug_mode=1,dry_mode=True): self.DEBUG_MODE= debug_mode self.DRY_MODE= dry_mode self.x393_mem= X393Mem(debug_mode,dry_mode) # self.x393_axi_tasks= X393AxiControlStatus(debug_mode,dry_mode) self.x393_axi_tasks= x393_axi_control_status.X393AxiControlStatus(debug_mode,dry_mode) self.x393_pio_sequences= X393PIOSequences(debug_mode,dry_mode) self.x393_mcntrl_timing= X393McntrlTiming(debug_mode,dry_mode) self.x393_mcntrl_buffers= X393McntrlBuffers(debug_mode,dry_mode) # self.__dict__.update(VerilogParameters.__dict__["_VerilogParameters__shared_state"]) # Add verilog parameters to the class namespace try: self.verbose=vrlg.VERBOSE except: pass def bad_data(self,buf): """ The whole block contains only "bad data" - nothing was read It can happen if command was not decoded correctly - list of the data read Returns True if the data is bad, False otherwise """ for w in buf: if (w!=0xffffffff): return False return True def missing_dqs(self, rd_blk, quiet=False): """ Suspect missing final DQS puls(es) during write if last written burst matches previous one - block of 32-bit data read from DDR3 device - no output Returns True if missing DQS pulse is suspected """ if (not rd_blk) or (len(rd_blk) <8 ): return False for i in range(-4,0): if rd_blk[i] != rd_blk[i-4]: break else: if not quiet: print ("End of the block repeats 2 last 8-bursts, insufficient number of trailing DQS pulses is suspected:") print("\n%03x:"%(len(rd_blk)-8),end=" ") for i in range(len(rd_blk)-8,len(rd_blk)): print("%08x"%rd_blk[i],end=" ") print("\n") return True return False def scan_dqs(self, 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 value (in 'hardware' format, sparse) high delay value (in 'hardware' format, sparse) number of 64-bit words to process 0 - early, 1 - late read command (shift by a SDCLK period) less output """ checkIntArgs(('low_delay','high_delay','num'),locals()) self.x393_pio_sequences.set_read_pattern(num+1,sel) # do not use first/last pair of the 32 bit words low = split_delay(low_delay) high = split_delay(high_delay) results = [] for dly in range (low, high+1): enc_dly=combine_delay(dly) self.x393_mcntrl_timing.axi_set_dqs_idelay(enc_dly) buf= self.x393_pio_sequences.read_pattern( (4*num+2), # num, 0, # show_rslt, 1) # Wait for operation to complete if quiet <1: hbuf=[] for dd in buf: hbuf.append(hex(dd)) print(hbuf) # with "good" data each word in buf should be 0xff00ff00 if self.bad_data(buf): results.append([]) else: data=[0]*32 # for each bit - even, then for all - odd for w in range (4*num): lane=w%2 for wb in range(32): g=(wb/8)%2 b=wb%8+lane*8+16*g if (buf[w+2] & (1<0): print ("%3d (0x%02x): "%(dly,enc_dly),end="") for i in range(32): print("%5x"%results[index][i],end="") print() print() if quiet < 4: print() print ("Delay",end=" ") for i in range(16): print ("Bit%dP"%i,end=" ") for i in range(16): print ("Bit%dM"%i,end=" ") print() for index in range (len(results)): dly=index+low enc_dly=combine_delay(dly) if (len (results[index])>0): print ("%d"%(dly),end=" ") for i in range(32): print("%d"%results[index][i],end=" ") print() return results def scan_dq_idelay(self, 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 value (in 'hardware' format, sparse) high delay value (in 'hardware' format, sparse) number of 64-bit words to process 0 - early, 1 - late read command (shift by a SDCLK period) less output """ checkIntArgs(('low_delay','high_delay','num'),locals()) self.x393_pio_sequences.set_read_pattern(num+1,sel) # do not use first/last pair of the 32 bit words low = split_delay(low_delay) high = split_delay(high_delay) results = [] for dly in range (low, high+1): enc_dly=combine_delay(dly) self.x393_mcntrl_timing.axi_set_dq_idelay(enc_dly) # same value to all DQ lines buf= self.x393_pio_sequences.read_pattern( (4*num+2), # num, 0, # show_rslt, 1) # Wait for operation to complete if not quiet: hbuf=[] for dd in buf: hbuf.append(hex(dd)) print(hbuf) # with "good" data each word in buf should be 0xff00ff00 if self.bad_data(buf): results.append([]) else: data=[0]*32 # for each bit - even, then for all - odd for w in range (4*num): # read 32-bit word number lane=w%2 # even words - lane 0, odd - lane 1 for wb in range(32): g=(wb/8)%2 b=wb%8+lane*8+16*g if (buf[w+2] & (1<0): print ("%3d (0x%02x): "%(dly,enc_dly),end="") for i in range(32): print("%5x"%results[index][i],end="") print() print() if quiet <3: print() print ("Delay",end=" ") for i in range(16): print ("Bit%dP"%i,end=" ") for i in range(16): print ("Bit%dM"%i,end=" ") print() for index in range (len(results)): dly=index+low enc_dly=combine_delay(dly) if (len (results[index])>0): print ("%d"%(dly),end=" ") for i in range(32): print("%d"%results[index][i],end=" ") print() print() return results def adjust_dq_idelay(self, 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): """ Adjust individual per-line DQ delays using read pattern mode DQS idelay(s) should be set 90-degrees from the final values low delay value (in 'hardware' format, sparse) high delay value (in 'hardware' format, sparse) number of 64-bit words to process 0 - early, 1 - late read command (shift by a SDCLK period) 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, In 'rising' mode (falling==0) - the shortest one number of times to run LPF less output Returns: list of 16 per-line delay values (sequential, not 'hardware') """ checkIntArgs(('low_delay','high_delay','num'),locals()) low = split_delay(low_delay) data_raw=self.scan_dq_idelay(low_delay,high_delay,num,sel,quiet) data=[] delays=[] for i,d in enumerate(data_raw): if len(d)>0: data.append(d) delays.append(i+low) if (quiet<2): print(delays) centerRaw=num*2.0# center value uncert=[] #"uncertanty of read for each bit and even/odd words. list of 32-element lists, each positive in the [0,1] interval rate=[] # data change rate lm1=len(data)-1 for i in range (0,len(data)): im1=(0, i-1)[i>0] ip1=(lm1,i+1)[i=16): r=-r r_uncert.append(1.0-((d-centerRaw)/centerRaw)**2) #0 and max -> 0, center ->1.0 r_rate.append(r/(2.0*centerRaw)) uncert.append(r_uncert) rate.append(r_rate) # print ("%d %s"%(i,str(r_uncert))) for _ in range(smooth): uncert=smooth2d(uncert) for _ in range(smooth): rate= smooth2d(rate) val=[] # list of 16-element rows of composite uncert*rate values, multiplied for odd/even values, hoping not to have # any bumps causes by asymmetry 0->1 and 1-->0 for i in range (0,len(data)): r_val=[] for j in range(16): sign=(-1,1)[rate[i][j]>0] rr=rate[i][j]*rate[i][j+16] # if falling: # sign=-sign if rr<0: sign=0 # different slope direction - ignore r_val.append(sign * rr * uncert[i][j] * uncert[i][j+16]) val.append(r_val) best_dlys=[None]*16 best_diffs=[None]*16 for i in range (len(val)): for j in range (16): v=val[i][j] if falling: v=-v if (best_dlys[j] is None) or (v>best_diffs[j]): best_dlys[j]= i+1 best_diffs[j]= v if quiet <2: for i in range (len(data)): print("%d "%(i),end="") for j in range (32): print("%f "%uncert[i][j],end="") for j in range (32): print("%f "%rate[i][j],end="") for j in range (16): print("%f "%(val[i][j]),end="") print() for i in range (16): print("%2d: %3d (0x%02x)"%(i,best_dlys[i],combine_delay(best_dlys[i]))) comb_delays=combine_delay(best_dlys) self.x393_mcntrl_timing.axi_set_dq_idelay((comb_delays[0:8],comb_delays[8:16])) return best_dlys def corr_delays(self, low, # absolute delay value of start scan avg_types, # weights of each of the 8 bit sequences res_bits, # individual per-bit results res_avg, # averaged eye data table, each line has 8 elements, or [] for bad measurements corr_fine, # fine delay correction ends_dist, # do not process if one of the primary interval ends is within this from 0.0 or 1.0 verbose ): """ Correct delays absolute delay value of start scan weights of each of the 8 bit sequences individual per-bit results averaged eye data table, each line has 8 elements, or [] for bad measurements fine delay correction do not process if one of the primary interval ends is within this from 0.0 or 1.0 Returns list of corrected delays """ # coarse adjustments - decimate arrays to use the same (0) value of the fine delay usable_types=[] for i,w in enumerate(avg_types): if (w>0) and not i in (0,7) : usable_types.append(i) if (verbose): print ("usable_types=",usable_types) def thr_sign(bit,typ,limit,data): # lim_l=limit # lim_u=1.0-limit if data[bit][typ] <= limit: return -1 if data[bit][typ] >= (1.0- limit): return 1 return 0 def thr_signs(typ,limit,data): signs="" for bit in range(15,-1,-1): signs+=("-","0","+")[thr_sign(bit,typ,limit,data)+1] def full_state(types,limit,data): #will NOT return None if any is undefined state="" for t in types: for bit in range(15,-1,-1): state+=("-","0","+")[thr_sign(bit,t,limit,data)+1] return state def full_same_state(types,limit,data): #will return None if any is undefined state="" for t in types: s0=thr_sign(15,t,limit,data) state+=("-","0","+")[s0+1] for bit in range(15,-1,-1): s=thr_sign(bit,t,limit,data) if (not s) or (s != s0) : return None return state def diff_state(state1,state2): for i,s in enumerate(state1): if s != state2[i]: return True return False # start_index=0; # if (low % NUM_FINE_STEPS) != 0: # start_index=NUM_FINE_STEPS-(low % NUM_FINE_STEPS) #find the first index where all bits are either above 1.0 -ends_dist or below ends_dist for index in range(len(res_avg)): print (" index=%d: %s"%(index,full_state(usable_types,ends_dist,res_bits[index]))) initial_state=full_same_state(usable_types,ends_dist,res_bits[index]) if initial_state: break else: print ("Could not find delay value where all bits/types are outside of undefined area (%f thershold)"%ends_dist) return None if (verbose): print ("start index=%d, start state=%s"%(index,initial_state)) #find end of that state for index in range(index+1,len(res_avg)): state=full_same_state(usable_types,ends_dist,res_bits[index]) if state != initial_state: break else: print ("Could not find delay value where initial state changes (%f thershold)"%ends_dist) return None last_initial_index=index-1 if (verbose): print ("last start state index=%d, new state=%s"%(last_initial_index,state)) #find new defined state for all bits for index in range(last_initial_index+1,len(res_avg)): #here repeat last delay new_state=full_same_state(usable_types,ends_dist,res_bits[index]) if new_state and (new_state != initial_state): break else: print ("Could not find delay value whith the new defined state (%f thershold)"%ends_dist) return None new_state_index=index if (verbose): print ("new defined state index=%d, new state=%s"%(new_state_index,new_state)) # remove states that do not have a transition filtered_types=[] for i,t in enumerate(usable_types): if (new_state[i]!=initial_state[i]): filtered_types.append(t) if (verbose): print ("filtered_types=",filtered_types) second_trans= 1 in filtered_types # use second transition, false - use first transition if (verbose): print("second_trans=",second_trans) # signs=((1,1,-1,-1),(1,-1,1,-1))[1 in filtered_types] signs=((0,0,1,1,-1,-1,0,0),(0,1,-1,0,0,1,-1,0))[1 in filtered_types] if (verbose): print("signs=",signs) for index in range(last_initial_index,new_state_index+1): if (verbose): print ("index=%3d, delay=%3d, state=%s"%(index,index+low,full_state(filtered_types,ends_dist,res_bits[index]))) #extend range, combine each bit and averages ext_low_index=last_initial_index-(new_state_index-last_initial_index) if ext_low_index<0: ext_low_index=0 ext_high_index=new_state_index+(new_state_index-last_initial_index) if ext_high_index>=len(res_bits): ext_high_index=len(res_bits)-1 if (verbose): print("ext_low_index=%d ext_high_index=%d"%(ext_low_index,ext_high_index)) bit_data=[] for i in range(16): bit_data.append([]) # [[]]*16 does not work! (shallow copy) avg_data=[] for index0 in range(ext_high_index-ext_low_index+1): index=index0+ext_low_index # if (verbose): print(res_bits[index]) bit_samples=[0.0]*16 avg_sample=0.0 weight=0.0 for t in filtered_types: w=avg_types[t] weight+=w sw=signs[t]*w avg_sample += sw * (2.0*res_avg[index][t]-1.0) # if (verbose): print ("%3d %d:"%(index,t),end=" ") for bit in range(16): bit_samples[bit] += sw*(2.0*res_bits[index][bit][t]-1.0) # if (verbose): print ("%.3f"%(res_bits[index][bit][t]),end=" ") # if (verbose): print() avg_sample /= weight avg_data.append(avg_sample) for bit in range(16): bit_samples[bit] /= weight # if (verbose): print ("bit_samples[%d]=%f"%(bit,bit_samples[bit])) bit_data[bit].append(bit_samples[bit]) # if (verbose): print ("bit_samples=",bit_samples) # if index0 <3: # if (verbose): print ("bit_data=",bit_data) # if (verbose): print ("\n\nbit_data=",bit_data) period_fine=len(corr_fine) for index in range(ext_high_index-ext_low_index+1): dly=low+index+ext_low_index corr_dly=dly+corr_fine[dly%period_fine] if (verbose): print ("%d %d %.2f %.3f"%(index,dly,corr_dly,avg_data[index]),end=" ") for bit in range(16): if (verbose): print ("%.3f"%(bit_data[bit][index]),end=" ") if (verbose): print() # Seems all above was an overkill, just find bit delays that result in most close to 0 delays=[] for bit in range(16): best_dist=1.0 best_index=None for index in range(ext_high_index-ext_low_index+1): if (abs(bit_data[bit][index]) absolute delay value of start scan weights of each of the 8 bit sequences averaged eye data tablle, each line has 8 elements, or [] for bad measurements do not process if one of the primary interval ends is within this from 0.0 or 1.0 : minimal difference between primary delay steps to process """ start_index=0; if (low % NUM_FINE_STEPS) != 0: start_index=NUM_FINE_STEPS-(low % NUM_FINE_STEPS) weights=[0.0]*( NUM_FINE_STEPS) corr=[0.0]*( NUM_FINE_STEPS) #[0] will stay 0 for index in range(start_index, len(res_avg)-NUM_FINE_STEPS,NUM_FINE_STEPS): if (len(res_avg[index])>0) and (len(res_avg[index+NUM_FINE_STEPS])>0): for t,w in enumerate(avg_types): if (w>0): f=res_avg[index][t]; s=res_avg[index+NUM_FINE_STEPS][t]; # print ("index=%d t=%d f=%f s=%s"%(index,t,f,s)) if ((f>ends_dist) and (s>ends_dist) and (f< (1-ends_dist)) and (s < (1-ends_dist)) and (abs(s-f)>min_diff)): diff=s-f wd=w* diff*diff # squared? or use abs? for j in range (1,NUM_FINE_STEPS): if ( (len(res_avg[index+j])>0)): v=res_avg[index+j][t]; #correction to the initial step==1 d=(v-f)/(s-f)*NUM_FINE_STEPS-j #average corr[j]+=wd*d weights[j]+=wd # print ("\n weights:") # print(weights) # print ("\n corr:") # print(corr) for i,w in enumerate(weights): if (w>0) : corr[i]/=w # will skip 0 print ("\ncorr:") # print(corr) for i,c in enumerate(corr): print ("%i %f"%(i,c)) return corr def scan_or_adjust_delay_random(self, low_delay, high_delay, use_dq, use_odelay, ends_dist, min_diff, adjust, verbose): """ Scan or adjust delays using random data write+read Low delay value to tru high delay value to try 0 - scan dqs, 1 - scan dq (common value, post-adjustment) 0 - use input delays, 1 - use output delays do not process if one of the primary interval ends is within this from 0.0 or 1.0 minimal difference between primary delay steps to process 0 - scan, 1 - adjust : verbose mode (more prints) Returns list of calculated delay values """ checkIntArgs(('low_delay','high_delay'),locals()) brc=(5, # 3'h5, # bank 0x1234, # 15'h1234, # row address 0x100) # 10'h100 # column address # global BASEADDR_PORT1_WR,VERBOSE; # saved_verbose=VERBOSE; # VERBOSE=False; low = split_delay(low_delay) high = split_delay(high_delay) rand16=[] for i in range(512): rand16.append(random.randint(0,65535)) wdata=convert_mem16_to_w32(rand16) if (verbose and not adjust): print("rand16:") for i in range(len(rand16)): if (i & 0x1f) == 0: if (verbose and not adjust): print("\n%03x:"%i,end=" ") if (verbose and not adjust): print("%04x"%rand16[i],end=" ") if (verbose and not adjust): print("\n") if (verbose and not adjust): print("wdata:") for i in range(len(wdata)): if (i & 0xf) == 0: if (verbose and not adjust): print("\n%03x:"%i,end=" ") if (verbose and not adjust): print("%08x"%wdata[i],end=" ") if (verbose and not adjust): print("\n") bit_type=[] # does not include first and last elements for i in range(1,511): types=[] for j in range(16): types.append((((rand16[i-1]>>j) & 1)<<2) | (((rand16[i ]>>j) & 1)<<1) | (((rand16[i+1]>>j) & 1))) bit_type.append(types) # if (verbose and not adjust): print ("i=%d",i) # if (verbose and not adjust): print(types) # total_types=[[0]*8]*16 # number of times each type occurred in the block for each DQ bit (separate for DG up/down?) total_types=[] # number of times each type occurred in the block for each DQ bit (separate for DG up/down?) for i in range(16): total_types.append([0]*8) for typ in bit_type: # if (verbose and not adjust): print(typ) for j in range(16): # total_types[j][typ[j]]+=1 total_types[j][typ[j]]=total_types[j][typ[j]]+1 if (verbose and not adjust): print("\ntotal_types:") if (verbose and not adjust): print (total_types) avg_types=[0.0]*8 N=0 for t in total_types: for j,n in enumerate(t): avg_types[j]+=n N+=n for i in range(len(avg_types)): avg_types[i]/=N if (verbose and not adjust): print("\avg_types:") if (verbose and not adjust): print (avg_types) #write blok buffer with 256x32bit data self.x393_mcntrl_buffers.write_block_buf_chn(0,0,wdata); # fill block memory (channel, page, number) self.x393_pio_sequences.set_write_block(*brc) #64 8-bursts, 1 extra DQ/DQS/ active cycle self.x393_pio_sequences.set_read_block(*brc) if (use_odelay==0) : self.x393_pio_sequences.write_block(0,1) # Wait for operation to complete if verbose: print("++++++++ block written once") #now scanning - first DQS, then try with DQ (post-adjustment - best fit) results = [] if verbose: print("******** use_odelay=%d use_dq=%d"%(use_odelay,use_dq)) alreadyWarned=False for dly in range (low, high+1): enc_dly=combine_delay(dly) if (use_odelay!=0): if (use_dq!=0): if verbose: print("******** axi_set_dq_odelay(0x%x)"%enc_dly) self.x393_mcntrl_timing.axi_set_dq_odelay(enc_dly) # set the same odelay for all DQ bits else: if verbose: print("******** axi_set_dqs_odelay(0x%x)"%enc_dly) self.x393_mcntrl_timing.axi_set_dqs_odelay(enc_dly) self.x393_pio_sequences.write_block(0,1) # Wait for operation to complete if verbose: print("-------- block written AGAIN") else: if (use_dq!=0): if verbose: print("******** axi_set_dq_idelay(0x%x)"%enc_dly) self.x393_mcntrl_timing.axi_set_dq_idelay(enc_dly)# set the same idelay for all DQ bits else: if verbose: print("******** axi_set_dqs_idelay(0x%x)"%enc_dly) self.x393_mcntrl_timing.axi_set_dqs_idelay(enc_dly) buf32=self.x393_pio_sequences.read_block( 256, # num, 0, # show_rslt, 1) # Wait for operation to complete if self.bad_data(buf32): results.append([]) else: # Warn about possible missing DQS pulses during writes alreadyWarned |= self.missing_dqs(buf32, alreadyWarned) read16=convert_w32_to_mem16(buf32) # 512x16 bit, same as DDR3 DQ over time if verbose and (dly==low): if (verbose and not adjust): print("buf32:") for i in range(len(buf32)): if (i & 0xf) == 0: if (verbose and not adjust): print("\n%03x:"%i,end=" ") if (verbose and not adjust): print("%08x"%buf32[i],end=" ") if (verbose and not adjust): print("\n") if (verbose and not adjust): print("read16:") for i in range(len(read16)): if (i & 0x1f) == 0: if (verbose and not adjust): print("\n%03x:"%i,end=" ") if (verbose and not adjust): print("%04x"%read16[i],end=" ") if (verbose and not adjust): print("\n") data=[] # number of times each type occurred in the block for each DQ bit (separate for DG up/down?) for i in range(16): data.append([0]*8) for i in range (1,511): w= read16[i] typ=bit_type[i-1] # first and last words are not used, no type was calculated for j in range(16): if (w & (1<0 ): data[i][t]*=1.0/total_types[i][t] results.append(data) if (verbose and not adjust): print ("%3d (0x%02x): "%(dly,enc_dly),end="") for i in range(16): if (verbose and not adjust): print("[",end="") for j in range(8): if (verbose and not adjust): print("%3d"%(round(100.0*data[i][j])),end=" ") if (verbose and not adjust): print("]",end=" ") if (verbose and not adjust): print() titles=["'000","'001","'010", "'011","'100","'101","'110","'111"] #calculate weighted averages #TODO: for DQ scan shift individual bits for the best match if use_dq: if (verbose and not adjust): print("TODO: shift individual bits for the best match before averaging") res_avg=[] for dly in range (len(results)): if (len(results[dly])>0): data=results[dly] avg=[0.0]*8 for t in range(8): weight=0; d=0.0 for i in range(16): weight+=total_types[i][t] d+=total_types[i][t]*data[i][t] if (weight>0): d/=weight avg[t] = d res_avg.append(avg) else: res_avg.append([]) corr_fine=self.calibrate_finedelay( low, # absolute delay value of start scan avg_types, # weights of weach of the 8 bit sequences res_avg, # averaged eye data tablle, each line has 8 elements, or [] for bad measurements ends_dist/256.0, # ends_dist, # do not process if one of the primary interval ends is within this from 0.0 or 1.0 min_diff/256.0) #min_diff): # minimal difference between primary delay steps to process period=len(corr_fine) if (not adjust): print("\n\n\n========== Copy below to the spreadsheet, use columns from corr_delay ==========") print("========== First are individual results for each bit, then averaged eye pattern ==========") print ("delay corr_delay",end=" ") for t in range(8): for i in range(16): if (not adjust): print("%02d:%s"%(i,titles[t]),end=" ") print() for index in range (len(results)): if (len(results[index])>0): dly=index+low corr_dly=dly+corr_fine[dly%period] print ("%d %.2f"%(dly,corr_dly),end=" ") for t in range(8): for i in range(16): try: print("%.4f"%(results[dly][i][t]),end=" ") #IndexError: list index out of range except: print(".????",end="") print() print("\n\n\n========== Copy below to the spreadsheet, use columns from corr_delay ==========") print("========== data above can be used for the individual bits eye patterns ==========") print ("delay corr_delay",end=" ") for t in range(8): print(titles[t],end=" ") print() for index in range (len(res_avg)): if (len(res_avg[index])>0): dly=index+low corr_dly=dly+corr_fine[dly%period] print ("%d %.2f"%(dly,corr_dly),end=" ") for t in range(8): try: print("%.4f"%(res_avg[dly][t]),end=" ") except: print(".????",end=" ") print() dly_corr=None if adjust: dly_corr=self.corr_delays( low, # absolute delay value of start scan avg_types, # weights of weach of the 8 bit sequences results, #individual per-bit results res_avg, # averaged eye data tablle, each line has 8 elements, or [] for bad measurements corr_fine, # fine delay correction ends_dist/256.0, # find where all bits are above/below that distance from 0.0/1.0margin verbose) # VERBOSE=verbose # print ("VERBOSE=",VERBOSE) print ("dly_corr=",dly_corr) print ("use_dq=",use_dq) if dly_corr and use_dq: # only adjusting DQ delays, not DQS dly_comb=combine_delay(dly_corr) if use_odelay: self.x393_mcntrl_timing.axi_set_dq_odelay((dly_comb[0:8],dly_comb[8:16])) """ for i in range (8): axi_set_dly_single(0,i,combine_delay(dly_corr[i])) for i in range (8): axi_set_dly_single(2,i,combine_delay(dly_corr[i+8])) """ else: self.x393_mcntrl_timing.axi_set_dq_idelay((dly_comb[0:8],dly_comb[8:16])) """ for i in range (8): axi_set_dly_single(1,i,combine_delay(dly_corr[i])) for i in range (8): axi_set_dly_single(3,i,combine_delay(dly_corr[i+8])) """ # use_dq, # 0 - scan dqs, 1 - scan dq (common valuwe, post-adjustment) # use_odelay, # VEBOSE=saved_verbose return dly_corr def scan_delay_random(self, low_delay, high_delay, use_dq, # 0 - scan dqs, 1 - scan dq (common valuwe, post-adjustment) use_odelay, # 0 - idelay, 1 - odelay ends_dist, # do not process if one of the primary interval ends is within this from 0.0 or 1.0 min_diff, # minimal difference between primary delay steps to process verbose): """ Scan delays using random data write+read Low delay value to tru high delay value to try 0 - scan dqs, 1 - scan dq (common value, post-adjustment) 0 - use input delays, 1 - use output delays do not process if one of the primary interval ends is within this from 0.0 or 1.0 minimal difference between primary delay steps to process : verbose mode (more prints) """ checkIntArgs(('low_delay','high_delay'),locals()) self.scan_or_adjust_delay_random( low_delay, high_delay, use_dq, # 0 - scan dqs, 1 - scan dq (common valuwe, post-adjustment) use_odelay, ends_dist, # do not process if one of the primary interval ends is within this from 0.0 or 1.0 min_diff, False, #scan, not adjust verbose) # minimal difference between primary delay steps to process