Commit e4dae58e authored by Andrey Filippov's avatar Andrey Filippov

debugging command/address timing adjustment

parent 1902d5ce
-v
-d TARGET_MODE=1
-f ../system_defines.vh
-f ../includes/x393_parameters.vh ../includes/x393_cur_params_target.vh ../includes/x393_localparams.vh
......
......@@ -61,7 +61,7 @@ __version__ = 0.1
__date__ = '2015-03-01'
__updated__ = '2015-03-01'
DEBUG = 1
DEBUG = 0 # 1
TESTRUN = 0
PROFILE = 0
QUIET=1 # more try/excepts
......@@ -209,7 +209,7 @@ USAGE
args = parser.parse_args()
if not args.exceptions:
args.exceptions=0
QUIET = (1,0)[args.exceptions]
# print ("args.exception=%d, QUIET=%d"%(args.exceptions,QUIET))
......@@ -223,6 +223,14 @@ USAGE
#print("--- commands=%s"% str(args.commands))
# paths = args.paths
verbose = args.verbose
if not verbose:
verbose=0
print("args=%s"%(str(args)))
print("sys.argv=%s"%(str(sys.argv)))
print("DEBUG=%s"%(str(DEBUG)))
print ("verbose=%d"%verbose)
paths=[]
if (args.paths):
for group in args.paths:
......@@ -247,7 +255,7 @@ USAGE
preDefines[kv[0].strip("`")]=kv[1]
#print("+++ defines=%s"% str(preDefines))
if verbose > 0:
if verbose > -1: # always
# print("Verbose mode on "+hex(verbose))
args.parameters.append(['VERBOSE=%d'%verbose]) # add as verilog parameter
......
......@@ -44,15 +44,11 @@ def set_name_field(vname,
<fieldIndex> byte field index (0 - lowest byte, 1 - bits[15:8], etc)
<value> value to set the specified byte to
"""
# v=vrlg.__dict__[vname]
v=globals()[vname]
# print ("old value for %s is %s"%(vname,str(vrlg.__dict__[vname])))
mask = 0xff << (8*fieldIndex)
val = value << (8*fieldIndex)
v = ((v ^ val) & mask) ^ v
# vrlg.__dict__[vname]=v
globals()[vname]=v
# print ("new value for %s is %s (0x%x)"%(vname,str(vrlg.__dict__[vname]),vrlg.__dict__[vname]))
def get_name_field(vname,
fieldIndex):
......@@ -62,6 +58,11 @@ def get_name_field(vname,
<fieldIndex> byte field index (0 - lowest byte, 1 - bits[15:8], etc)
Return specified byte
"""
# print ("value for %s is %s"%(vname,str(globals()[vname])))
# print ("dflt for %s is %s"%(vname,str(DEFAULTS[vname])))
# print ("value[%d] for %s is 0x%x"%(fieldIndex,vname,globals()[vname]))
# print ("dflt[%d] for %s is 0x%x"%(fieldIndex,vname,DEFAULTS[vname]))
return ( globals()[vname] >> (8*fieldIndex)) & 0xff
def get_default_field(vname,
......@@ -74,8 +75,11 @@ def get_default_field(vname,
Return specified byte
"""
global DEFAULTS
# print ("value for %s is %s"%(vname,str(globals()[vname])))
# print ("dflt for %s is %s"%(vname,str(DEFAULTS[vname])))
# print ("value[%d] for %s is 0x%x"%(fieldIndex,vname,globals()[vname]))
# print ("dflt[%d] for %s is 0x%x"%(fieldIndex,vname,DEFAULTS[vname]))
# return (vrlg.DEFAULTS[vname] >> (8*fieldIndex)) & 0xff
return (DEFAULTS[vname] >> (8*fieldIndex)) & 0xff
def get_default(vname):
......
......@@ -36,24 +36,122 @@ from x393_mem import X393Mem
from verilog_utils import hx
from time import time
import vrlg
enabled_channels=0 # currently enable channels
cke_en=0
cmda_en=0
sdrst_on=1
mcntrl_en=0
refresh_en=0
channel_priority=[None]*16
sequences_set=0
class X393AxiControlStatus(object):
DRY_MODE= True # True
DEBUG_MODE=1
# vpars=None
x393_mem=None
enabled_channels=0 # currently enable channels
FPGA_RST_CTRL=0xf8000240
# verbose=1
verbose=1
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)
try:
self.verbose=vrlg.VERBOSE
except:
pass
# self.__dict__.update(VerilogParameters.__dict__["_VerilogParameters__shared_state"]) # Add verilog parameters to the class namespace
'''
Maybe import parameters into the module, not class namespace to use directly, w/o self. ?
# __dict__.update(VerilogParameters.__dict__) # Add verilog parameters to the class namespace
'''
# Use 'import pickle' (exists in the camera) to save/restore state
def init_state(self):
global enabled_channels, cke_en, cmda_en, sdrst_on, mcntrl_en, channel_priority, refresh_en, sequences_set
"""
reset state (as after bitstream load)
"""
enabled_channels=0 # currently enable channels
cke_en=0
cmda_en=0
sdrst_on=1
mcntrl_en=0
channel_priority=[None]*16
refresh_en=0
sequences_set=0
if self.verbose>0:
print ("*** System state reset ****")
# TODO: Add state save/restore in tmpfs file (like /var/state/...) (/var/state does not exist initially)
def get_sequences_set(self,quiet=1):
global sequences_set
if quiet<2 :
print ("SEQUENCES SET = %d"%sequences_set)
return sequences_set
def set_sequences_set(self,val,quiet=1):
global sequences_set
val= (0,1)[val]
sequences_set=val
if quiet<2 :
print ("SEQUENCES SET = %d"%sequences_set)
def get_cke_en(self,quiet=1):
global cke_en
if quiet<2 :
print ("CKE EN = %d"%cke_en)
return cke_en
def get_cmda_en(self,quiet=1):
global cmda_en
if quiet<2 :
print ("CMDA EN = %d"%cmda_en)
return cmda_en
def get_sdrst_on(self,quiet=1):
global sdrst_on
if quiet<2 :
print ("SDRST ON = %d"%sdrst_on)
return sdrst_on
def get_mcntrl_en(self,quiet=1):
global mcntrl_en
if quiet<2 :
print ("MCNTRL ON = %d"%mcntrl_en)
return mcntrl_en
def get_refresh_en(self,quiet=1):
global refresh_en
if quiet<2 :
print ("REFRESH EN = %d"%refresh_en)
return refresh_en
def get_enabled_channels(self,quiet=1):
global enabled_channels
if quiet<2 :
print ("ENABLED_CHANNELS = 0x%x"%enabled_channels)
return enabled_channels
def get_channel_priorities(self,quiet=1):
global channel_priority
if quiet<2 :
print ("CHANNEL PRIORITIES:",end=" ")
for v in channel_priority:
if v is None:
print (" - ",end=" ")
else:
print ("%d"%v,end=" ")
print()
return channel_priority
def get_state(self,quiet=1):
return {
'cke_en': self.get_cke_en(quiet),
'cmda_en': self.get_cmda_en(quiet),
'sdrst_on': self.get_sdrst_on(quiet),
'mcntrl_en': self.get_mcntrl_en(quiet),
'enabled_channels': self.get_enabled_channels(quiet),
'channel_priorities': self.get_channel_priorities(quiet),
'refresh_en': self.get_refresh_en(quiet),
'sequences_set': self.get_sequences_set(quiet)
}
def write_contol_register(self, reg_addr, data):
"""
Write 32-bit word to the control register
......@@ -202,7 +300,12 @@ class X393AxiControlStatus(object):
Enable (disable) address, bank and command lines to the DDR3 memory
<en> - 1 - enable, 0 - disable
"""
global cmda_en
en=(0,1)[en]
if self.verbose>0:
print ("ENABLE CMDA %s"%str(en))
self.write_contol_register(vrlg.MCONTR_PHY_0BIT_ADDR + vrlg.MCONTR_PHY_0BIT_CMDA_EN + en, 0);
cmda_en=en
def enable_cke(self,
en): # input en;
......@@ -210,7 +313,12 @@ class X393AxiControlStatus(object):
Enable (disable) CKE - clock enable to DDR3 memory
<en> - 1 - enable, 0 - disable
"""
global cke_en
en=(0,1)[en]
if self.verbose>0:
print ("ENABLE CKE %s"%str(en))
self.write_contol_register(vrlg.MCONTR_PHY_0BIT_ADDR + vrlg.MCONTR_PHY_0BIT_CKE_EN + en, 0);
cke_en=en
def activate_sdrst(self,
en): # input en;
......@@ -218,32 +326,49 @@ class X393AxiControlStatus(object):
Activate SDRST (reset) to DDR3 memory
<en> - 1 - activate (low), 0 - deactivate (high)
"""
global sdrst_on
en=(0,1)[en]
if self.verbose>0:
print ("ACTIVATE SDRST %s"%str(en))
self.write_contol_register(vrlg.MCONTR_PHY_0BIT_ADDR + vrlg.MCONTR_PHY_0BIT_SDRST_ACT + en, 0);
sdrst_on=en
def enable_refresh(self,
en): # input en;
en): # input en;
"""
Enable (disable) refresh of the DDR3 memory
<en> - 1 - enable, 0 - disable
"""
global refresh_en
en=(0,1)[en]
if self.verbose>0:
print ("ENABLE REFRESH %s"%str(en))
self.write_contol_register(vrlg.MCONTR_TOP_0BIT_ADDR + vrlg.MCONTR_TOP_0BIT_REFRESH_EN + en, 0);
refresh_en=en
def enable_memcntrl(self,
en): # input en;
en): # input en;
"""
Enable memory controller module
<en> - 1 - enable, 0 - disable
"""
global mcntrl_en
en=(0,1)[en]
if self.verbose>0:
print ("ENABLE MEMCTRL %s"%str(en))
self.write_contol_register(vrlg.MCONTR_TOP_0BIT_ADDR + vrlg.MCONTR_TOP_0BIT_MCONTR_EN + en, 0);
mcntrl_en=en
def enable_memcntrl_channels(self,
chnen): # input [15:0] chnen; // bit-per-channel, 1 - enable;
"""
Enable memory controller channels (all at once control)
<chnen> - 16-bit control word with per-channel enable bits (bit0 - chn0, ... bit15 - chn15)
"""
self.enabled_channels = chnen; # currently enabled memory channels
self.write_contol_register(vrlg.MCONTR_TOP_16BIT_ADDR + vrlg.MCONTR_TOP_16BIT_CHN_EN, self.enabled_channels & 0xffff) # {16'b0,chnen});
global enabled_channels
enabled_channels = chnen # currently enabled memory channels
self.write_contol_register(vrlg.MCONTR_TOP_16BIT_ADDR + vrlg.MCONTR_TOP_16BIT_CHN_EN, enabled_channels & 0xffff) # {16'b0,chnen});
if self.verbose>0:
print ("ENABLED MEMCTRL CHANNELS 0x%x (word)"%enabled_channels)
def enable_memcntrl_en_dis(self,
chn, # input [3:0] chn;
......@@ -253,19 +378,26 @@ class X393AxiControlStatus(object):
<chn> - 4-bit channel select
<en> - 1 - enable, 0 - disable of the selected channel
"""
global enabled_channels
if en:
self.enabled_channels = self.enabled_channels | (1<<chn);
enabled_channels |= 1<<chn;
else:
self.enabled_channels = self.enabled_channels & ~(1<<chn);
self.write_contol_register(vrlg.MCONTR_TOP_16BIT_ADDR + self. MCONTR_TOP_16BIT_CHN_EN, self.enabled_channels & 0xffff) # {16'b0,ENABLED_CHANNELS});
enabled_channels &= ~(1<<chn);
self.write_contol_register(vrlg.MCONTR_TOP_16BIT_ADDR + self. MCONTR_TOP_16BIT_CHN_EN, enabled_channels & 0xffff) # {16'b0,ENABLED_CHANNELS});
if self.verbose>0:
print ("ENABLED MEMCTRL CHANNELS 0x%x (en/dis)"%enabled_channels)
def configure_channel_priority(self,
chn, # input [ 3:0] chn;
priority): #input [15:0] priority; // (higher is more important)
priority=0): #input [15:0] priority; // (higher is more important)
"""
Configure channel priority
<chn> - 4-bit channel select
<priority> - 16-bit priority value (higher value means more important)
"""
global channel_priority
self.write_contol_register(vrlg.MCONTR_ARBIT_ADDR + chn, priority & 0xffff)# {16'b0,priority});
if self.verbose>0:
print ("SET CHANNEL %d priority=0x%x"%(chn,priority))
channel_priority[chn]=priority
......@@ -28,13 +28,14 @@ __version__ = "3.0+"
__maintainer__ = "Andrey Filippov"
__email__ = "andrey@elphel.com"
__status__ = "Development"
#import sys
import sys
#import x393_mem
#x393_pio_sequences
import random
#from import_verilog_parameters import VerilogParameters
from x393_mem import X393Mem
from x393_axi_control_status import X393AxiControlStatus
#from x393_axi_control_status import X393AxiControlStatus
import x393_axi_control_status
from x393_pio_sequences import X393PIOSequences
from x393_mcntrl_timing import X393McntrlTiming
from x393_mcntrl_buffers import X393McntrlBuffers
......@@ -60,13 +61,14 @@ class X393McntrlAdjust(object):
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= 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=self.VERBOSE
self.verbose=vrlg.VERBOSE
except:
pass
#//SET DQ ODELAY=[['0xd9', '0xdb', '0xdc', '0xd4', '0xe0', '0xda', '0xd4', '0xd8'], ['0xdc', '0xe0', '0xf1', '0xdc', '0xe0', '0xdc', '0xdc', '0xdc']]
......@@ -101,7 +103,9 @@ class X393McntrlAdjust(object):
for d in dly:
rslt.append(self.split_delay(d))
return rslt
try:
try:
if isinstance(dly,float):
dly=int(dly+0.5)
dly_int=dly>>3
dly_fine=dly & 0x7
if dly_fine > (NUM_FINE_STEPS-1):
......@@ -122,6 +126,8 @@ class X393McntrlAdjust(object):
rslt.append(self.combine_delay(d))
return rslt
try:
if isinstance(dly,float):
dly=int(dly+0.5)
return ((dly/NUM_FINE_STEPS)<<3)+(dly%NUM_FINE_STEPS)
except:
return None
......@@ -992,6 +998,381 @@ class X393McntrlAdjust(object):
True, #adjust, not scan
verbose)
# if it will fail, re-try with phase shifted by 180 degrees (half SDCLK period)
# Consider "hinted" scan when initial estimation for cmd_odelay is known from previous incomplete measurement
# Then use this knowledge to keep delay in safe region (not too close to clock edge) during second scanning
def adjust_cmda_odelay(self,
start_phase=0,
reinits=1, #higher the number - more re-inits are used (0 - only where absolutely necessary
max_phase_err=0.1,
quiet=1
):
"""
<max_phase_err> maximal phase error for command and address line
as a fraction of SDCLK period to consider
"""
start_phase &= 0xff
if start_phase >=128:
start_phase -= 256 # -128..+127
recover_cmda_dly_step=0x20 # subtract/add from cmda_odelay (hardware!!!) and retry (same as 20 decimal)
max_lin_dly=159
wlev_address_bit=7
wlev_max_bad=0.01 # <= OK, > bad
def phase_step(phase,cmda_dly):
"""
Find marginal delay for address/comand lines for particular
clock pahse
Raises exception if failed to get write levelling data even after
changing cmda delay and restarting memory device
Returns a tuple of the current cmda_odelay (hardware) and a marginal one for a7
"""
cmda_dly_lin=self.split_delay(cmda_dly)
self.x393_mcntrl_timing.axi_set_phase(phase,quiet=quiet)
self.x393_mcntrl_timing.axi_set_cmda_odelay(cmda_dly,quiet=quiet)
wlev_rslt=self.x393_pio_sequences.write_levelling(1, quiet+1)
if wlev_rslt[2]>wlev_max_bad: # should be 0, if not - Try to recover
if quiet <4:
print("*** FAILED to read data in write levelling mode, restarting memory device")
print(" Retrying with the same cmda_odelay value = 0x%x"%cmda_dly)
self.x393_pio_sequences.restart_ddr3()
wlev_rslt=self.x393_pio_sequences.write_levelling(1, quiet)
if wlev_rslt[2]>wlev_max_bad: # should be 0, if not - change delay and restart memory
cmda_dly_old=cmda_dly
if cmda_dly >=recover_cmda_dly_step:
cmda_dly -= recover_cmda_dly_step
else:
cmda_dly += recover_cmda_dly_step
if quiet <4:
print("*** FAILED to read data in write levelling mode, restarting memory device")
print(" old cmda_odelay= 0x%x, new cmda_odelay =0x%x"%(cmda_dly_old,cmda_dly))
self.x393_mcntrl_timing.axi_set_cmda_odelay(cmda_dly,quiet=quiet)
self.x393_pio_sequences.restart_ddr3()
wlev_rslt=self.x393_pio_sequences.write_levelling(1, quiet)
if wlev_rslt[2]>wlev_max_bad: # should be 0, if not - change delay and restart memory
raise Exception("Failed to read in write levelling mode after modifying cmda_odelay, aborting")
# Try twice step before giving up (was not needed so far)
d_high=max_lin_dly
self.x393_mcntrl_timing.axi_set_address_odelay(
self.combine_delay(d_high),
wlev_address_bit,
quiet=quiet)
wlev_rslt=self.x393_pio_sequences.write_levelling(1, quiet+1)
if not wlev_rslt[2]>wlev_max_bad:
return (self.split_delay(cmda_dly),-1) # even maximal delay is not enough to make rising sdclk separate command from A7
# find marginal value of a7 delay to spoil write levelling mode
d_high=max_lin_dly
d_low=cmda_dly_lin
while d_high > d_low:
dly= (d_high + d_low)//2
self.x393_mcntrl_timing.axi_set_address_odelay(self.combine_delay(dly),wlev_address_bit,quiet=quiet)
wlev_rslt=self.x393_pio_sequences.write_levelling(1, quiet+1)
if wlev_rslt[2] > wlev_max_bad:
d_high=dly
else:
if d_low == dly:
break
d_low=dly
self.x393_mcntrl_timing.axi_set_cmda_odelay(cmda_dly,quiet=quiet)
return (self.split_delay(cmda_dly),d_low)
dly_steps=self.x393_mcntrl_timing.get_dly_steps()
if quiet<1:
print (dly_steps)
numPhaseSteps= int(dly_steps['SDCLK_PERIOD']/dly_steps['PHASE_STEP']+0.5)
if (start_phase+numPhaseSteps)>128:
old_start_phase=start_phase
while (start_phase+numPhaseSteps)>128:
start_phase -= numPhaseSteps
print("Selected scan phase range (%d..%d) does not fit into -128..+127, changing it to %d..%d)"%
(old_start_phase,old_start_phase+numPhaseSteps-1,start_phase,start_phase+numPhaseSteps-1))
#start_phase
cmda_marg_dly=[None]*numPhaseSteps
cmda_dly=0
safe_early=self.split_delay(recover_cmda_dly_step)/2
# print ("safe_early=%d(0x%x), recover_cmda_dly_step=%d(0x%x)"%(safe_early,safe_early,recover_cmda_dly_step,recover_cmda_dly_step))
if reinits>0:
self.x393_pio_sequences.restart_ddr3()
for phase in range(start_phase,start_phase+numPhaseSteps):
if quiet <3:
print ("%d:"%(phase),end=" ")
sys.stdout.flush()
phase_mod=phase % numPhaseSteps
dlys= phase_step(phase,cmda_dly)
cmda_marg_dly[phase_mod]=dlys # [1] # Marginal delay or -1
cmda_dly = self.combine_delay(dlys[0]) # update if it was modified during recover
# See if cmda_odelay is dangerously close - increase it (and re-init?)
if dlys[1]<0:
if quiet <3:
print ("X",end=" ")
sys.stdout.flush()
if reinits > 1: #re-init each time failed to find delay
if quiet <3:
print ("\nFailed to find marginal odelay for A7 - re-initializing DDR3 with odelay=0x%x",cmda_dly)
self.x393_mcntrl_timing.axi_set_cmda_odelay(cmda_dly,quiet=quiet)
self.x393_pio_sequences.restart_ddr3()
else:
if quiet <3:
print ("%d"%dlys[1],end=" ")
sys.stdout.flush()
lin_dly=self.split_delay(cmda_dly)
if (dlys[1]-lin_dly) < safe_early:
if (lin_dly > 0):
lin_dly=max(0,lin_dly-2*safe_early)
if (dlys[1]-lin_dly) < safe_early:
lin_dly=min(max_lin_dly,lin_dly+2*safe_early) # or just add safe_early to dlys[1]?
if lin_dly != self.split_delay(cmda_dly):
cmda_dly=self.combine_delay(lin_dly)
self.x393_mcntrl_timing.axi_set_cmda_odelay(cmda_dly,quiet=quiet)
if reinits > 0: #re-init each time failed to find delay
if quiet <3:
print ("\nMeasured marginal delay for A7 is too close to cmda_odelay,re-initializing DDR3 with odelay=0x%x"%cmda_dly)
self.x393_pio_sequences.restart_ddr3()
if quiet <2:
for i,d in enumerate(cmda_marg_dly):
print ("%d %d %d"%(i, d[0], d[1]))
#find the largest positive step of cmda_marg_dly while cyclically increasing phase
numValid=0
for i,d in enumerate(cmda_marg_dly):
if d[1]>0:
numValid += 1
if numValid < 2:
raise Exception("Too few points wioth measured marginal CMDA odelay: %d"%numValid)
maxPosSep=0
firstIndex=None
for i,d in enumerate(cmda_marg_dly):
if d[1]>0:
for j in range(1,numPhaseSteps):
d1=cmda_marg_dly[(i + j) % numPhaseSteps][1]
if d1 >= 0: # valid data
if (d1 - d[1]) > maxPosSep:
maxPosSep = d1 - d[1]
firstIndex=(i + j) % numPhaseSteps
break;
#now data from firstIndex to (firstIndex+numPhaseSteps)%numPhaseSteps is ~monotonic - apply linear approximation
if quiet <2:
print ("firstIndex=%d"%(firstIndex))
S0=0
SX=0
SY=0
SX2=0
SXY=0
for x in range(numPhaseSteps):
y=cmda_marg_dly[(x+firstIndex) % numPhaseSteps][1]
if y>=0:
y+=0.5
S0+=1
SX+=x
SY+=y
SX2+=x*x
SXY+=x*y
# print("x=%f, index=%d, y=%f, S0=%f, SX=%f, SY=%f, SX2=%f, SXY=%f"%(x, (x+firstIndex) % numPhaseSteps, y, S0, SX, SY, SX2, SXY))
a = (SXY*S0 - SY*SX) / (SX2*S0 - SX*SX)
b = (SY*SX2 - SXY*SX) / (SX2*S0 - SX*SX)
if quiet < 2:
print ("a=%f, b=%f"%(a,b))
# fine delay corrections
fineCorr= [0.0]*5
fineCorrN=[0]*5
for x in range(numPhaseSteps):
y=cmda_marg_dly[(x+firstIndex) % numPhaseSteps][1]
if (y>0):
i=y % 5
y+=0.5
diff=y- (a * x + b)
fineCorr[i] += diff
fineCorrN[i] += 1
for i in range(5):
if fineCorrN[i]>0:
fineCorr[i]/=fineCorrN[i]
if (quiet <2):
print ("fineCorr = %s"%str(fineCorr))
variantStep=-a*numPhaseSteps #how much b changes when moving over the full SDCLK period
if (quiet <2):
print ("Delay matching the full SDCLK period = %f"%(variantStep))
b-=a*firstIndex # recalculate b for phase=0
b_period=0
if (quiet <2):
print ("a=%f, b=%f"%(a,b))
#Make b fit into 0..max_lin_dly range
while (b>max_lin_dly):
b-=variantStep
b_period-=1
while (b<0):
b+=variantStep # can end up having b>max_lin_dly - if the phase adjust by delay is lower than full period
b_period+=1
if (quiet <2):
print ("a=%f, b=%f, b_period=%d"%(a,b,b_period))
# Find best minimal delay (with higher SDCLK frequency delay range can exceed the period and there could
# be more than one solution
bestSolPerErr=[] #list ot tuples, each containing(best cmda_odelay,number of added periods,error)
max_dly_err=abs(a)*max_phase_err*numPhaseSteps # maximal allowed delay error (in 160-step scale)
if (quiet <2):
print("Max dly error=%f"%(max_dly_err))
for phase in range (numPhaseSteps):
periods=0 # b_period
y=a*phase+b
y0=y
#find the lowest approximate solution to consider
if y0 > (-max_dly_err):
while (y0 >= (variantStep-max_dly_err)):
y0 -= variantStep
periods -= 1
else:
while (y0<(-max_dly_err)):
y0 += variantStep
periods += 1
dly_min= max(0,int(y0-4.5))
dly_max= min(max_lin_dly,int(y0+5.5))
dly_to_try=[]
for d in range(dly_min,dly_max+1):
dly_to_try.append((d,periods))
if (y0<0): # add a second range to try (higher delay values
y0+=variantStep
periods += 1
dly_min= max(0,int(y0-4.5))
dly_max= min(max_lin_dly,int(y0+5.5))
for d in range(dly_min,dly_max+1):
dly_to_try.append((d,periods))
bestDly=None
bestDiff=None
bestPeriods=None
for dp in dly_to_try:
actualDelay=dp[0]-fineCorr[dp[0] % 5] # delay corrected for the non-uniform 160-scale
diff=actualDelay-(y+variantStep*dp[1]) # dp[1] - number of added/removed full periods
if (bestDiff is None) or (abs(bestDiff) > abs(diff)):
bestDiff = diff
bestDly = dp[0]
bestPeriods= dp[1]
phase_rslt=() #Default, if nothing was found
if not bestDiff is None:
phase_rslt=(bestDly,bestPeriods,bestDiff)
if (quiet <2):
print ("%d: %s %s"%(phase, str(dly_to_try), str(phase_rslt)) )
\ No newline at end of file
bestSolPerErr.append(phase_rslt)
if (quiet <2):
for i in range(numPhaseSteps): # enumerate(cmda_marg_dly):
d=cmda_marg_dly[i]
print ("%d %d %d"%(i, d[0], d[1]),end=" ")
if (bestSolPerErr[i]):
print("%d %d %f"%(bestSolPerErr[i][0],bestSolPerErr[i][1],bestSolPerErr[i][2]))
else:
print()
#numPhaseSteps
#Add 180 dwegree shift (move cmda_odelay to EARLY of the marginal
period_shift=0
b_center= b- 0.5*variantStep
if b_center < 0: # have to move late
b_center+=variantStep
period_shift+=1
cmda_dly_per_err=[]
for phase in range (numPhaseSteps):
marg_phase=(phase+numPhaseSteps//2) % numPhaseSteps
extra_periods=(phase+numPhaseSteps//2) // numPhaseSteps
bspe= bestSolPerErr[marg_phase]
if bspe:
cmda_dly_per_err.append({'ldly':bspe[0],
'period':bspe[1]+period_shift+extra_periods+b_period, # b_period - shift from the branch
# where phase starts from the longest cmda_odelay and goes down
'err':bspe[2]})
else:
cmda_dly_per_err.append({}) # No solution for this phase value
rdict={"cmda_odly_a":a,
"cmda_odly_b":b_center,
"cmda_odly_period":period_shift+b_period, #
"cmda_fine_corr":fineCorr,
"cmda_bspe":cmda_dly_per_err}
if (quiet <3):
print("\ncmda_odelay adjustmet results:")
print('cmda_odly_a: %f'%(rdict['cmda_odly_a']))
print('cmda_odly_b: %f'%(rdict['cmda_odly_b']))
print('cmda_odly_period: %d'%(rdict['cmda_odly_period']))
print('cmda_fine_corr: %s'%(rdict['cmda_fine_corr']))
print("\nPhase DLY0 MARG_A7 CMDA PERIODS*10 ERR*10")
for i in range(numPhaseSteps): # enumerate(cmda_marg_dly):
d=cmda_marg_dly[i]
print ("%d %d %d"%(i, d[0], d[1]),end=" ")
if (rdict['cmda_bspe'][i]):
print("%d %d %f"%(rdict['cmda_bspe'][i]['ldly'],10*rdict['cmda_bspe'][i]['period'],10*rdict['cmda_bspe'][i]['err']))
else:
print()
#TODO: Add 180 shift to get center, not marginal cmda_odelay
return rdict
"""
With 400MHz range of dealys approximately matches the full period, but with higher
frequency it may be possible to use several cmda delays for the same phase shift
So we'll create a list for all the phase shifts (of the period), each having one or
several best pairs - cmda (integer 0..159) delays and error (in ns) that this delay
setting will cause for command/data setup/hold to SDCLK.
Actual optimal delays are shifted by numPhaseSteps/2 (180 degrees of SDCLK)
"""
"""
#max_phase_err=0.1
max_dly_err=a*max_phase_err*numPhaseSteps # maximal allowed delay error (in 160-step scale)
valid_cmda_delays=[[]]*numPhaseSteps
variantStep=a*numPhaseSteps # delay step to get the same phase (in normalized 160 step scale)
minBranchIndex=None
maxBranchIndex=None
for phase in range(numPhaseSteps):
x=phase-firstIndex
y0=a*x+b
#find the lowest approximate solution to consider
if y0 > (-max_dly_err):
while (y0 >= (variantStep-max_dly_err)):
y0 -= variantStep
else:
while (y0<(-max_dly_err)):
y0 += variantStep
while y0 <= (159+max_dly_err): #May be never when using higher delay reference clock (300MHz) with the same SDCLK
#try delays in the range of +/- 5 steps from "ideal" and find the lowest error
dly_min= max(0,int(y0-4.5))
dly_max= max(159,int(y0+5.5))
bestDly=None
bestDiff=None
for dly in range(dly_min,dly_max+1):
actualDelay=dly-fineCorr[dly % 5] # delay corrected for the non-uniform 160-scale
diff=actualDelay-y0
if (bestDiff is None) or (abs(bestDiff) > abs(diff)):
bestDiff = diff
bestDly = dly
if not bestDiff is None:
branchIndex=int(((y0-(a*x+b))/variantStep) + 0.5)
valid_cmda_delays[phase].append((bestDly,bestDiff,branchIndex))
if (minBranchIndex is None) or (branchIndex < minBranchIndex):
minBranchIndex = branchIndex
if (maxBranchIndex is None) or (branchIndex > maxBranchIndex):
maxBranchIndex = branchIndex
y0+=variantStep
#print for plotting - find min/max for
for phase in range(numPhaseSteps):
x=phase-firstIndex
y0=a*x+b
dlys={}
diffs={}
for i,v in enumerate(valid_cmda_delays[phase]):
dlys[v[2]]= v[0]
diffs[v[2]]=v[1]
print ("%3d: %3d"%(phase,cmda_marg_dly[phase][1]),end=" ")
for branch in range(minBranchIndex, maxBranchIndex+1):
if branch in dlys:
print("%d"%dlys[branch],end=" ")
else:
print("",end=" ")
for branch in range(minBranchIndex, maxBranchIndex+1):
if branch in diffs:
print("%f"%diffs[branch],end=" ")
else:
print("",end=" ")
## TODO: add 0.5 to result, split low/high bits (as done in adjust_random
"""
\ No newline at end of file
......@@ -33,7 +33,8 @@ __status__ = "Development"
#x393_pio_sequences
#from import_verilog_parameters import VerilogParameters
from x393_mem import X393Mem
from x393_axi_control_status import X393AxiControlStatus
#from x393_axi_control_status import X393AxiControlStatus
import x393_axi_control_status
#from verilog_utils import * # concat, bits
#from verilog_utils import hx, concat, bits, getParWidth
#from verilog_utils import concat, getParWidth
......@@ -50,10 +51,11 @@ class X393McntrlBuffers(object):
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=X393AxiControlStatus(debug_mode,dry_mode)
self.x393_axi_tasks=x393_axi_control_status.X393AxiControlStatus(debug_mode,dry_mode)
# self.__dict__.update(VerilogParameters.__dict__["_VerilogParameters__shared_state"]) # Add verilog parameters to the class namespace
try:
self.verbose=self.VERBOSE
self.verbose=vrlg.VERBOSE
except:
pass
def write_block_scanline_chn(self, #
......
......@@ -33,7 +33,8 @@ __status__ = "Development"
#x393_pio_sequences
#from import_verilog_parameters import VerilogParameters
from x393_mem import X393Mem
from x393_axi_control_status import X393AxiControlStatus
#from x393_axi_control_status import X393AxiControlStatus
import x393_axi_control_status
from x393_pio_sequences import X393PIOSequences
from x393_mcntrl_timing import X393McntrlTiming
from x393_mcntrl_buffers import X393McntrlBuffers
......@@ -57,14 +58,15 @@ class X393McntrlTests(object):
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= 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.x393_mcntrl_adjust= X393McntrlAdjust(debug_mode,dry_mode)
# self.__dict__.update(VerilogParameters.__dict__["_VerilogParameters__shared_state"]) # Add verilog parameters to the class namespace
try:
self.verbose=self.VERBOSE
self.verbose=vrlg.VERBOSE
except:
pass
......@@ -148,16 +150,16 @@ class X393McntrlTests(object):
self.x393_mcntrl_buffers.write_block_buf_chn(0,0,256); # fill block memory (channel, page, number)
# set all delays
##axi_set_delays - from tables, per-pin
if set_per_pin_delays:
self.x393_mcntrl_timing.axi_set_delays() # set all individual delays, aslo runs axi_set_phase()
else:
self.x393_mcntrl_timing.axi_set_same_delays(
vrlg.DLY_DQ_IDELAY,
vrlg.DLY_DQ_ODELAY,
vrlg.DLY_DQS_IDELAY,
vrlg.DLY_DQS_ODELAY,
vrlg.DLY_DM_ODELAY,
vrlg.DLY_CMDA_ODELAY)
# if set_per_pin_delays:
# Make it an only option TODO: do the same for the simulation!!
self.x393_mcntrl_timing.axi_set_delays() # set all individual delays, aslo runs axi_set_phase()
# else:
# self.x393_mcntrl_timing.axi_set_same_delays(vrlg.DLY_DQ_IDELAY,
# vrlg.DLY_DQ_ODELAY,
# vrlg.DLY_DQS_IDELAY,
# vrlg.DLY_DQS_ODELAY,
# vrlg.DLY_DM_ODELAY,
# vrlg.DLY_CMDA_ODELAY)
# set clock phase relative to DDR clk
# print("Debugging: sleeping for 1 second")
# sleep(1)
......@@ -195,82 +197,57 @@ class X393McntrlTests(object):
self.x393_pio_sequences.set_read_block (
5, # 3'h5, # bank
0x1234, # 15'h1234, # row address
0x100 # 10'h100 # column address
)
self.x393_axi_tasks.set_sequences_set(1) # Mark sequences as being set
def init_ddr3(self,
refresh=1,
wait_complete=True):
"""
Enable address/command pins, remove SDRST, enable CKE,
Setup PS PIO
Set DDR3 MR0..MR3 registers
Enable refresh
Optionally enable refresh
<wait_complete> Do not request a new transaction from the scheduler until previous memory transaction is finished
"""
# enable output for address/commands to DDR chip
self.x393_axi_tasks.enable_cmda(1)
# remove reset from DDR3 chip
self.x393_axi_tasks.activate_sdrst(0) # was enabled at system reset
sleep(0.1) # actually 500 usec required
self.x393_axi_tasks.enable_cke(1);
self.x393_axi_tasks.enable_memcntrl_channels(0x3) # only channel 0 and 1 are enabled
self.x393_axi_tasks.configure_channel_priority(0,0) # lowest priority channel 0
self.x393_axi_tasks.configure_channel_priority(1,0) # lowest priority channel 1
self.x393_pio_sequences.enable_reset_ps_pio(1,0) # enable, no reset
self.x393_pio_sequences.restart_ddr3(wait_complete)
# set MR registers in DDR3 memory, run DCI calibration (long)
self.x393_pio_sequences.wait_ps_pio_ready(vrlg.DEFAULT_STATUS_MODE, 1, 2.0); # wait FIFO not half full, sync sequences, timeout 2 sec
self.x393_pio_sequences.schedule_ps_pio ( # schedule software-control memory operation (may need to check FIFO status first)
vrlg.INITIALIZE_OFFSET, # input [9:0] seq_addr; # sequence start address
0, # input [1:0] page; # buffer page number
0, # input urgent; # high priority request (only for competion with other channels, wiil not pass in this FIFO)
0, # input chn; # channel buffer to use: 0 - memory read, 1 - memory write
wait_complete ); # wait_complete; # Do not request a newe transaction from the scheduler until previous memory transaction is finished
# Wait PS PIO sequence DOEN
self.x393_pio_sequences.wait_ps_pio_done(vrlg.DEFAULT_STATUS_MODE, 1 , 2.0); # wait FIFO not half full, sync sequences, timeout 2 sec
self.x393_axi_tasks.enable_refresh(1)
# axi_set_dqs_odelay('h78); #??? defaults - wrong? DLY_DQS_ODELAY=0x74
self.x393_axi_tasks.enable_refresh(refresh)
def test_write_levelling(self,
wait_complete, # Wait for operation to complete
wlev_dqs_dly= 0x80,
norm_dqs_odly=None):
dqs_odly= None,
wbuf_dly = None,
wait_complete=1, # Wait for operation to complete
quiet=0):
"""
Test write levelling mode
<dqs_dly> DQS output delay for write levelling mode. If it is not None,
the default DQS output delay will be restored in the end
<wbuf_dly> Write buffer latency (currently 9) If it is not None,
the default wbuf delay will be restored in the end
<wait_complete> wait write levelling operation to complete (0 - may initiate multiple PS PIO operations)
<wlev_dqs_dly> DQS output delay for write levelling mode (default 0x80)
<norm_dqs_odly> DQS output delay for normal (not write levelling) mode (default 0x78)
returns a pair of ratios for getting "1" for 2 lanes
<quiet> reduce output
returns a pair of ratios for getting "1" for 2 lanes and problem marker (should be 0)
"""
numBufWords=32 # twice nrep in set_write_lev
if norm_dqs_odly is None:
norm_dqs_odly=vrlg.DLY_DQS_ODELAY
# Set special values for DQS idelay for write leveling
self.x393_pio_sequences.wait_ps_pio_done(vrlg.DEFAULT_STATUS_MODE,1); # not no interrupt running cycle - delays are changed immediately
## self.x393_mcntrl_timing.axi_set_dqs_idelay_wlv()
if not dqs_odly is None:
self.x393_mcntrl_timing.axi_set_dqs_odelay(dqs_odly)
# Set write buffer (from DDR3) WE signal delay for write leveling mode
if not wbuf_dly is None:
self.x393_mcntrl_timing.axi_set_wbuf_delay(wbuf_dly)
rslt= self.x393_pio_sequences.write_levelling(
wait_complete,
quiet)
#restore values to defaults (only if changed)
if not dqs_odly is None:
self.x393_mcntrl_timing.axi_set_dqs_odelay()
# Set write buffer (from DDR3) WE signal delay for write leveling mode
## self.x393_mcntrl_timing.axi_set_wbuf_delay(vrlg.WBUF_DLY_WLV)
# TODO: Set configurable delay time instead of #80
## self.x393_mcntrl_timing.axi_set_dqs_odelay(wlev_dqs_dly) # 'h80); # 'h80 - inverted, 'h60 - not - 'h80 will cause warnings during simulation
self.x393_pio_sequences.schedule_ps_pio (# schedule software-control memory operation (may need to check FIFO status first)
vrlg.WRITELEV_OFFSET, # input [9:0] seq_addr; # sequence start address
0, # input [1:0] page; # buffer page number
0, # input urgent; # high priority request (only for competition with other channels, will not pass in this FIFO)
0, # input chn; # channel buffer to use: 0 - memory read, 1 - memory write
wait_complete) # `PS_PIO_WAIT_COMPLETE );# wait_complete; # Do not request a newe transaction from the scheduler until previous memory transaction is finished
self.x393_pio_sequences.wait_ps_pio_done(vrlg.DEFAULT_STATUS_MODE,1); # wait previous memory transaction finished before changing delays (effective immediately)
buf=self.x393_mcntrl_buffers.read_block_buf_chn (0, 0, numBufWords, (0,1)[self.verbose>1]) # chn=0, page=0, number of 32-bit words=32, show_rslt
#calculate 1-s ratio for both lanes
rslt=[0.0,0.0]
for i in range(0,numBufWords):
rslt[i & 1]+=(buf[i] & 1) + ((buf[i] >> 8) & 1) + ((buf[i] >> 16) & 1) + ((buf[i] >> 24) & 1)
for i in range(2):
rslt[i]/=2*numBufWords
## self.x393_mcntrl_timing.axi_set_dqs_idelay_nominal()
## self.x393_mcntrl_timing.axi_set_dqs_odelay(norm_dqs_odly) # 'h78);
## self.x393_mcntrl_timing.axi_set_wbuf_delay(vrlg.WBUF_DLY_DFLT); #DFLT_WBUF_DELAY
if not wbuf_dly is None:
self.x393_mcntrl_timing.axi_set_wbuf_delay()
# if quiet <2:
# print ("WLEV lanes ratios: %f %f, non 0x00/0x01 bytes: %f"%(rslt[0],rslt[1],rslt[2]))
return rslt
def test_read_pattern(self,
......
......@@ -33,7 +33,8 @@ __status__ = "Development"
#x393_pio_sequences
#from import_verilog_parameters import VerilogParameters
from x393_mem import X393Mem
from x393_axi_control_status import X393AxiControlStatus
#from x393_axi_control_status import X393AxiControlStatus
import x393_axi_control_status
#from verilog_utils import * # concat, bits
#from verilog_utils import hx, concat, bits, getParWidth
from verilog_utils import concat, getParWidth,hexMultiple
......@@ -43,35 +44,51 @@ import vrlg # global parameters
class X393McntrlTiming(object):
DRY_MODE= True # True
DEBUG_MODE=1
# vpars=None
x393_mem=None
x393_axi_tasks=None #x393X393AxiControlStatus
x393_utils=None
# target_phase=0 # TODO: set!
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)
# vrlg=X393Utils(debug_mode,dry_mode)
self.x393_axi_tasks=x393_axi_control_status.X393AxiControlStatus(debug_mode,dry_mode)
# self.__dict__.update(VerilogParameters.__dict__["_VerilogParameters__shared_state"]) # Add verilog parameters to the class namespace
def get_dly_steps(self):
#hardwired in phy_top.v
# CLKOUT0_DIVIDE_F= 2.000
CLKOUT1_DIVIDE = 2
# CLKOUT2_DIVIDE = 4
fCLK_IN=1000.0/vrlg.CLKIN_PERIOD
fVCO=fCLK_IN*vrlg.CLKFBOUT_MULT
fSDCLK=fVCO/CLKOUT1_DIVIDE
tSDCLK=1000.0/fSDCLK # in ns
phaseStep=1000.0/(fVCO*56.0) # 1 unit of phase shift (now 112 for the full period
fREF=fCLK_IN*vrlg.CLKFBOUT_MULT_REF/vrlg.CLKFBOUT_DIV_REF
dlyStep=1000.0/fREF/32/2 # Approximate, depending on calibration
dlyFStep=0.01 # fine step
return{"SDCLK_PERIOD":tSDCLK,
"PHASE_STEP":phaseStep,
"DLY_STEP":dlyStep,
"DLY_FINE_STEP":dlyFStep}
def axi_set_phase(self,
phase=None, # input [PHASE_WIDTH-1:0] phase;
wait_phase_en=True,
wait_seq=False):
wait_seq=False,
quiet=1):
"""
Set clock phase
Set clock phase TODO: Add refresh off/on for changing phase
<phase> 8-bit clock phase value (None will use default)
<wait_phase_en> compare phase shift to programmed (will not work if the program was restarted)
<wait_seq> read and re-send status request to make sure status reflects new data (just for testing, too fast for Python)
<quiet> reduce output
Returns 1 if success, 0 if timeout (or no wait was performed)
"""
if phase is None:
phase= vrlg.get_default("DLY_PHASE")
vrlg.DLY_PHASE=phase & ((1<<vrlg.PHASE_WIDTH)-1)
if self.DEBUG_MODE > 1:
if quiet<2:
print("SET CLOCK PHASE=0x%x"%(vrlg.DLY_PHASE))
self.x393_axi_tasks.write_contol_register(vrlg.LD_DLY_PHASE,vrlg.DLY_PHASE) # {{(32-PHASE_WIDTH){1'b0}},phase}); // control register address
self.x393_axi_tasks.write_contol_register(vrlg.DLY_SET,0)
......@@ -156,7 +173,7 @@ class X393McntrlTiming(object):
self.axi_set_dqs_idelay()
self.axi_set_dq_odelay()
self.axi_set_dqs_odelay()
self.axi_set_dqm_odelay()
self.axi_set_dm_odelay()
self.axi_set_cmda_odelay()
self.axi_set_phase()
......@@ -256,78 +273,117 @@ class X393McntrlTiming(object):
self.x393_axi_tasks.write_contol_register(vrlg.DLY_SET,0) # set all delays
def axi_set_cmda_odelay(self,
delay=None): # input [7:0] delay;
delay=None, # input [7:0] delay;
indx=None, # address index
quiet=1):
"""
Set all command/address output delays to the same value (or a list/tuple of the individual ones)
<delay> 8-bit (5+3) delay value to use or list/tuple containing individual values
List elements may be None, those values will not be overwritten
if delay is None will restore default values
<indx> if present, delay only applies to the specified index (delay should be int/long)
<quiet> reduce output
"""
if delay is None:
delay=[]
for i in range(0,32):
delay.append(vrlg.get_default_field("LD_DLY_CMDA",i))
if (indx is None) or (i == indx) :
delay.append(vrlg.get_default_field("DLY_CMDA",i))
else:
delay.append(None)
if isinstance(delay,(int,long)):
delay=(delay,)*32 # all address/commands
if self.DEBUG_MODE > 1:
delay=[delay]*32 # all address/commands
if not indx is None:
for i in range(len(delay)):
if (i != indx):
delay[i]=None
if quiet < 2:
print("SET COMMAND and ADDRESS ODELAY"+hexMultiple(delay))
self.axi_set_multiple_delays(vrlg.LD_DLY_CMDA, 0, 32, delay, "DLY_CMDA");
self.x393_axi_tasks.write_contol_register(vrlg.DLY_SET,0) # set all delays
def axi_set_address_odelay(self,
delay=None): # input [7:0] delay;
delay=None, # input [7:0] delay;
indx=None, # address index
quiet=1):
"""
Set output delays for address lines only
<delay> 8-bit (5+3) delay value to use or list/tuple containing individual values
List elements may be None, those values will not be overwritten
<delay> 8-bit (5+3) delay value to use or list/tuple containing individual values
List elements may be None, those values will not be overwritten
if delay is None will restore default values
<indx> if present, delay only applies to the specified index (delay should be int/long)
"""
if delay is None:
delay=[]
for i in range(0,vrlg.ADDRESS_NUMBER):
delay.append(vrlg.get_default_field("LD_DLY_CMDA",i))
if (indx is None) or (i == indx) :
delay.append(vrlg.get_default_field("DLY_CMDA",i))
else:
delay.append(None)
if isinstance(delay,(int,long)):
delay=(delay,)*vrlg.ADDRESS_NUMBER
if self.DEBUG_MODE > 1:
delay=[delay]*vrlg.ADDRESS_NUMBER
if not indx is None:
for i in range(len(delay)):
if (i != indx):
delay[i]=None
if quiet < 2:
print("SET ADDRESS ODELAY="+hexMultiple(delay))
self.axi_set_multiple_delays(vrlg.LD_DLY_CMDA, 0, 0, delay, "DLY_CMDA")
self.x393_axi_tasks.write_contol_register(vrlg.DLY_SET,0) # set all delays
def axi_set_bank_odelay(self,
delay=None): # input [7:0] delay;
delay=None, # input [7:0] delay;
indx=None): # address index
"""
Set output delays for bank lines only
<delay> 8-bit (5+3) delay value to use or list/tuple containing individual values
List elements may be None, those values will not be overwritten
if delay is None will restore default values
<indx> if present, delay only applies to the specified index (delay should be int/long)
"""
bank_offset=24
if delay is None:
delay=[]
for i in range(3):
delay.append(vrlg.get_default_field("LD_DLY_CMDA",i+bank_offset))
if (indx is None) or (i == indx) :
delay.append(vrlg.get_default_field("DLY_CMDA",i+bank_offset))
else:
delay.append(None)
if isinstance(delay,(int,long)):
delay=(delay,)*3
delay=[delay]*3
if not indx is None:
for i in range(len(delay)):
if (i != indx):
delay[i]=None
if self.DEBUG_MODE > 1:
print("SET BANK ODELAY="+hexMultiple(delay))
self.axi_set_multiple_delays(vrlg.LD_DLY_CMDA, bank_offset, 0,delay, "DLY_CMDA") # length will be determined by len(delay)
self.x393_axi_tasks.write_contol_register(vrlg.DLY_SET,0) # set all delays
def axi_set_cmd_odelay(self,
delay=None): # input [7:0] delay;
delay=None, # input [7:0] delay;
indx=None): # address index
"""
Set output delays for command lines only. command=(we,ras,cas,cke,odt)
<delay> 8-bit (5+3) delay value to use or list/tuple containing individual values
List elements may be None, those values will not be overwritten
if delay is None will restore default values
<indx> if present, delay only applies to the specified index (delay should be int/long)
"""
command_offset=24+3
if delay is None:
delay=[]
for i in range(5):
delay.append(vrlg.get_default_field("LD_DLY_CMDA",i+command_offset))
if (indx is None) or (i == indx) :
delay.append(vrlg.get_default_field("DLY_CMDA",i+command_offset))
else:
delay.append(None)
if isinstance(delay,(int,long)):
delay=(delay,)*5
delay=[delay]*5
if not indx is None:
for i in range(len(delay)):
if (i != indx):
delay[i]=None
if self.DEBUG_MODE > 1:
print("SET COMMAND ODELAY="+hexMultiple(delay))
self.axi_set_multiple_delays(vrlg.LD_DLY_CMDA, command_offset, 0,delay, "DLY_CMDA") # length will be determined by len(delay)
......@@ -371,7 +427,7 @@ class X393McntrlTiming(object):
if self.DRY_MODE: break
def axi_set_wbuf_delay(self,
delay): # input [3:0] delay;
delay=None): # input [3:0] delay;
"""
Set write to buffer latency
<delay> 4-bit write to buffer signal delay (in mclk clock cycles)
......@@ -446,15 +502,20 @@ class X393McntrlTiming(object):
self.x393_axi_tasks.write_contol_register(vrlg.MCONTR_PHY_16BIT_ADDR +vrlg.MCONTR_PHY_16BIT_PATTERNS_TRI, delays) # DQSTRI_LAST, DQSTRI_FIRST, DQTRI_LAST, DQTRI_FIRST});
def axi_set_dqs_dqm_patterns(self,
patt=None):
dqs_patt=None,
dqm_patt=None):
"""
Set sequencer patterns for the DQ lines ON/OFF (defined by parameters)
<patt> DQS toggle pattern (if None - use MCONTR_PHY_16BIT_PATTERNS (currently 0x55)
"""
if patt is None:
patt=vrlg.MCONTR_PHY_16BIT_PATTERNS
<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
"""
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:
print("SET DQS+DQM PATTERNS, patt= 0x%x"%patt)
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):
......
......@@ -33,12 +33,15 @@ __status__ = "Development"
#x393_pio_sequences
#from import_verilog_parameters import VerilogParameters
from x393_mem import X393Mem
from x393_axi_control_status import X393AxiControlStatus
#from x393_axi_control_status import X393AxiControlStatus
import x393_axi_control_status
from x393_mcntrl_buffers import X393McntrlBuffers
#from verilog_utils import * # concat, bits
from verilog_utils import concat, bits
#from x393_axi_control_status import concat, bits
import vrlg # global parameters
from time import sleep
class X393PIOSequences(object):
DRY_MODE= True # True
DEBUG_MODE=1
......@@ -50,7 +53,8 @@ class X393PIOSequences(object):
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=X393AxiControlStatus(debug_mode,dry_mode)
self.x393_axi_tasks=x393_axi_control_status.X393AxiControlStatus(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
'''
......@@ -949,3 +953,79 @@ class X393PIOSequences(object):
wait_complete) # `PS_PIO_WAIT_COMPLETE )# wait_complete; # Do not request a newer transaction from the scheduler until previous memory transaction is finished
# 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_levelling(self,
wait_complete=1, # Wait for operation to complete
quiet=1):
"""
Read data in write levelling mode
<wait_complete> wait write levelling operation to complete (0 - may initiate multiple PS PIO operations)
<quiet> reduce output
returns a pair of ratios for getting "1" for 2 lanes and problem marker (should be 0)
"""
numBufWords=32 # twice nrep in set_write_lev
self.wait_ps_pio_done(vrlg.DEFAULT_STATUS_MODE,1); # not no interrupt running cycle - delays are changed immediately
self.schedule_ps_pio (# schedule software-control memory operation (may need to check FIFO status first)
vrlg.WRITELEV_OFFSET, # input [9:0] seq_addr; # sequence start address
0, # input [1:0] page; # buffer page number
0, # input urgent; # high priority request (only for competition with other channels, will not pass in this FIFO)
0, # input chn; # channel buffer to use: 0 - memory read, 1 - memory write
wait_complete) # `PS_PIO_WAIT_COMPLETE );# wait_complete; # Do not request a newe transaction from the scheduler until previous memory transaction is finished
self.wait_ps_pio_done(vrlg.DEFAULT_STATUS_MODE,1); # wait previous memory transaction finished before changing delays (effective immediately)
buf=self.x393_mcntrl_buffers.read_block_buf_chn (0, 0, numBufWords, (0,1)[quiet<1]) # chn=0, page=0, number of 32-bit words=32, show_rslt
#calculate 1-s ratio for both lanes
rslt=[0.0,0.0,0.0] # last word - number of "problem" bytes that have non-ones in bits [7:1]
for i in range(0,numBufWords):
rslt[i & 1] += ((buf[i] & 1) +
((buf[i] >> 8) & 1) +
((buf[i] >> 16) & 1) +
((buf[i] >> 24) & 1))
rslt[2] += ((0,1)[(buf[i] & 0xfe) != 0]+
(0,1)[(buf[i] & 0xfe00) != 0]+
(0,1)[(buf[i] & 0xfe0000) != 0]+
(0,1)[(buf[i] & 0xfe000000) != 0])
for i in range(2):
rslt[i]/=2*numBufWords
rslt[2]/=4*numBufWords
if quiet <1:
print ("WLEV lanes ratios: %f %f, non 0x00/0x01 bytes: %f"%(rslt[0],rslt[1],rslt[2]))
return rslt
def restart_ddr3(self,
wait_complete=True,
quiet=1):
"""
Activate SDRST, enable address/command pins, remove SDRST, enable CKE,
Setup PS PIO
Set DDR3 MR0..MR3 registers
<wait_complete> Do not request a new transaction from the scheduler until previous memory transaction is finished
<quiet> reduce output
"""
# enable output for address/commands to DDR chip
self.x393_axi_tasks.enable_cmda(1)
self.x393_axi_tasks.activate_sdrst(1) # reset DDR3
sleep(0.1)
# remove reset from DDR3 chip
self.x393_axi_tasks.activate_sdrst(0) # was enabled at system reset
sleep(0.1) # actually 500 usec required
self.x393_axi_tasks.enable_cke(1);
self.x393_axi_tasks.enable_memcntrl_channels(0x3) # only channel 0 and 1 are enabled
self.x393_axi_tasks.configure_channel_priority(0,0) # lowest priority channel 0
self.x393_axi_tasks.configure_channel_priority(1,0) # lowest priority channel 1
self.enable_reset_ps_pio(1,0) # enable, no reset
# set MR registers in DDR3 memory, run DCI calibration (long)
self.wait_ps_pio_ready(vrlg.DEFAULT_STATUS_MODE, 1, 2.0); # wait FIFO not half full, sync sequences, timeout 2 sec
self.schedule_ps_pio ( # schedule software-control memory operation (may need to check FIFO status first)
vrlg.INITIALIZE_OFFSET, # input [9:0] seq_addr; # sequence start address
0, # input [1:0] page; # buffer page number
0, # input urgent; # high priority request (only for competion with other channels, wiil not pass in this FIFO)
0, # input chn; # channel buffer to use: 0 - memory read, 1 - memory write
wait_complete ); # wait_complete; # Do not request a newe transaction from the scheduler until previous memory transaction is finished
# Wait PS PIO sequence DOEN
self.wait_ps_pio_done(vrlg.DEFAULT_STATUS_MODE, 1 , 2.0); # wait FIFO not half full, sync sequences, timeout 2 sec
......@@ -37,6 +37,7 @@ from x393_mem import X393Mem
#from subprocess import call
from time import sleep
import vrlg # global parameters
import x393_axi_control_status
DEFAULT_BITFILE="/usr/local/verilog/x393.bit"
FPGA_RST_CTRL= 0xf8000240
......@@ -50,6 +51,7 @@ class X393Utils(object):
x393_mem=None
enabled_channels=0 # currently enable channels
saveFileName=None
x393_axi_tasks=None
# verbose=1
def __init__(self, debug_mode=1,dry_mode=True,saveFileName=None):
self.DEBUG_MODE=debug_mode
......@@ -57,6 +59,8 @@ class X393Utils(object):
if saveFileName:
self.saveFileName=saveFileName.strip()
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.__dict__.update(VerilogParameters.__dict__["_VerilogParameters__shared_state"]) # Add verilog parameters to the class namespace
def reset_get(self):
"""
......@@ -117,6 +121,7 @@ class X393Utils(object):
self.x393_mem.write_mem(FPGA0_THR_CTRL,0)
print ("Reset OFF")
self.reset(0xa)
self.x393_axi_tasks.init_state()
def exp_gpio (self,
mode="in",
......
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