x393_mcntrl_timing.py 28.7 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
from __future__ import print_function
'''
# Copyright (C) 2015, Elphel.inc.
# Methods that mimic Verilog tasks used for simulation  
# 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 <http://www.gnu.org/licenses/>.

@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 sys
#import x393_mem
#x393_pio_sequences
34
#from import_verilog_parameters import VerilogParameters
35
from x393_mem import X393Mem
36 37
#from x393_axi_control_status import X393AxiControlStatus
import x393_axi_control_status
38 39
#from verilog_utils import * # concat, bits 
#from verilog_utils import hx, concat, bits, getParWidth 
40 41
from verilog_utils import concat, getParWidth,hexMultiple
#from x393_axi_control_status import concat, bits
42 43
import vrlg # global parameters
#from x393_utils import X393Utils
44 45 46 47 48
class X393McntrlTiming(object):
    DRY_MODE= True # True
    DEBUG_MODE=1
    x393_mem=None
    x393_axi_tasks=None #x393X393AxiControlStatus
49
    x393_utils=None
50 51 52 53
    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)
54
        self.x393_axi_tasks=x393_axi_control_status.X393AxiControlStatus(debug_mode,dry_mode)
55
#        self.__dict__.update(VerilogParameters.__dict__["_VerilogParameters__shared_state"]) # Add verilog parameters to the class namespace
Andrey Filippov's avatar
Andrey Filippov committed
56

57 58 59 60 61 62 63 64 65 66
    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
67 68
#        fREF=fCLK_IN*vrlg.CLKFBOUT_MULT_REF/vrlg.CLKFBOUT_DIV_REF
        fREF=fCLK_IN*vrlg.MULTICLK_MULT/vrlg.MULTICLK_DIV_DLYREF/vrlg.MULTICLK_DIVCLK
69 70 71 72 73 74
        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}
75
        
Andrey Filippov's avatar
Andrey Filippov committed
76
    def axi_set_phase(self,
77
                      phase=None,      # input [PHASE_WIDTH-1:0] phase;
Andrey Filippov's avatar
Andrey Filippov committed
78
                      wait_phase_en=True,
79 80
                      wait_seq=False,
                      quiet=1):
Andrey Filippov's avatar
Andrey Filippov committed
81
        """
82
        Set clock phase TODO: Add refresh off/on for changing phase
83
        <phase>    8-bit clock phase value (None will use default)
Andrey Filippov's avatar
Andrey Filippov committed
84 85
        <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)
86
        @param quiet reduce output
Andrey Filippov's avatar
Andrey Filippov committed
87 88
        Returns 1 if success, 0 if timeout (or no wait was performed)
        """
89 90 91
        if phase is None:
            phase= vrlg.get_default("DLY_PHASE") 
        vrlg.DLY_PHASE=phase & ((1<<vrlg.PHASE_WIDTH)-1)
92 93 94 95 96 97 98 99 100
        if vrlg.CLKFBOUT_USE_FINE_PS:
            phase_value = (-vrlg.DLY_PHASE) & ((1<<vrlg.PHASE_WIDTH)-1)
            if quiet<2:
                print("SET INVERTED CLOCK PHASE=0x%x (actual value is 0x%x)"%(vrlg.DLY_PHASE, phase_value))
            self.x393_axi_tasks.write_control_register(vrlg.LD_DLY_PHASE, phase_value) # {{(32-PHASE_WIDTH){1'b0}},phase}); // control register address
        else:    
            if quiet<2:
                print("SET CLOCK PHASE=0x%x"%(vrlg.DLY_PHASE))
            self.x393_axi_tasks.write_control_register(vrlg.LD_DLY_PHASE,vrlg.DLY_PHASE) # {{(32-PHASE_WIDTH){1'b0}},phase}); // control register address
101
        self.x393_axi_tasks.write_control_register(vrlg.DLY_SET,0)
102
#        self.target_phase = phase
Andrey Filippov's avatar
Andrey Filippov committed
103 104 105 106 107 108 109 110 111 112 113 114 115
        if wait_phase_en:
            return self.wait_phase(True, wait_seq)
        return 0    

    def wait_phase(self,
                   check_phase_value=True,
                   wait_seq=False):
        """
        Wait for the phase shifter
        <check_phase_value> 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)
        Returns 1 if success, 0 if timeout
        """
116 117 118 119
        if vrlg.CLKFBOUT_USE_FINE_PS:
            patt = 0x3000000 | ((-vrlg.DLY_PHASE) & 0xff)
        else:    
            patt = 0x3000000 | vrlg.DLY_PHASE
Andrey Filippov's avatar
Andrey Filippov committed
120 121 122 123
        mask = 0x3000100
        if check_phase_value:
            mask |= 0xff
        return self.x393_axi_tasks.wait_status_condition(
124 125
                              vrlg.MCONTR_PHY_STATUS_REG_ADDR,                                # status_address,
                              vrlg.MCONTR_PHY_16BIT_ADDR + vrlg.MCONTR_PHY_STATUS_CNTRL,      # status_control_address,
Andrey Filippov's avatar
Andrey Filippov committed
126 127 128 129 130 131 132 133
                              3,                                                              # status_mode,
                              patt,                                                           # pattern,
                              mask,                                                           # mask
                              0,                                                              # invert_match
                              wait_seq,                                                       # wait_seq;
                              1.0)                                                            # maximal timeout (0 - no timeout)
       
        
134
    def get_target_phase(self):
135 136 137
        """
        Returns previously set clock phase value
        """
138
        return vrlg.DLY_PHASE
139 140 141 142 143 144 145
    def axi_set_same_delays(self,         #
                            dq_idelay,    # input [7:0] dq_idelay;
                            dq_odelay,    # input [7:0] dq_odelay;
                            dqs_idelay,   # input [7:0] dqs_idelay;
                            dqs_odelay,   # input [7:0] dqs_odelay;
                            dm_odelay,    # input [7:0] dm_odelay;
                            cmda_odelay): # input [7:0] cmda_odelay;
146 147 148 149 150 151 152 153 154 155 156 157 158 159
        """
        Set I/O delays for the DDR3 memory, same delay for all signals in the same class
        Each delay value is 8-bit, 5 MSB program in equal steps (=360/32 degrees each),
        and 3 LSB (valid values are 0..4) add additional non-calibrated 10ps delay 
        <dq_idelay>    input delay for DQ lines
        <dq_odelay>    output delay for DQ lines
        <dqs_idelay>   input delay for DQS lines
        <dqs_odelay>   output delay for DQS lines
        <dm_odelay>     input delay for DM lines
        <cmda_odelay>  output delay for DM lines
        """
        
        if self.DEBUG_MODE > 1:
            print("SET DELAYS(0x%x,0x%x,0x%x,0x%x,0x%x,0x%x)"%(dq_idelay,dq_odelay,dqs_idelay,dqs_odelay,dm_odelay,cmda_odelay))
160 161 162 163 164 165 166 167
        self.axi_set_dq_idelay(dq_idelay)
        self.axi_set_dq_odelay(dq_odelay)
        self.axi_set_dqs_idelay(dqs_idelay)
        self.axi_set_dqs_odelay(dqs_odelay)
        self.axi_set_dm_odelay(dm_odelay)
        self.axi_set_cmda_odelay(cmda_odelay)

    def axi_set_dqs_idelay_wlv(self):
168 169 170
        """
        Set DQS input delays to values defined for the write levelling mode (parameter-defined)
        """
171 172
        self.axi_set_multiple_delays(vrlg.LD_DLY_LANE0_IDELAY, 8, 1, vrlg.DLY_LANE0_DQS_WLV_IDELAY, "DLY_LANE0_IDELAY")
        self.axi_set_multiple_delays(vrlg.LD_DLY_LANE1_IDELAY, 8, 1, vrlg.DLY_LANE1_DQS_WLV_IDELAY, "DLY_LANE1_IDELAY")
173 174 175
#        self.x393_axi_tasks.write_control_register(vrlg.LD_DLY_LANE0_IDELAY + 8,      vrlg.DLY_LANE0_DQS_WLV_IDELAY)
#        self.x393_axi_tasks.write_control_register(vrlg.LD_DLY_LANE1_IDELAY + 8,      vrlg.DLY_LANE1_DQS_WLV_IDELAY)
        self.x393_axi_tasks.write_control_register(vrlg.DLY_SET,0)
176

177
    def axi_set_delays(self,quiet=1): #  set all individual delays
178
        """
179 180 181
        Set all DDR3 I/O delays to individual parameter-defined values (using default values,
        current ones are supposed to be synchronized)
        """
182 183 184 185 186 187 188
        self.axi_set_dq_idelay(quiet=quiet)
        self.axi_set_dqs_idelay(quiet=quiet)
        self.axi_set_dq_odelay(quiet=quiet)
        self.axi_set_dqs_odelay(quiet=quiet)
        self.axi_set_dm_odelay(quiet=quiet)
        self.axi_set_cmda_odelay(quiet=quiet)
        self.axi_set_phase(quiet=quiet)
189 190
        
    def axi_set_dq_idelay(self,   #  sets same delay to all dq idelay
191 192
                          delay=None, # input [7:0] delay;
                          quiet=1):
193 194
        """
        Set all DQ input delays to the same value
195
        @param delay 8-bit (5+3) delay value to use or a tuple/list with a pair for (lane0, lane1)
196
                Each of the two elements in the delay tuple/list may be a a common integer or a list/tuple itself
197
                if delay is None will restore default values
198
                Alternatively it can be a one-level list/tuple covering all (16) delays
199
        @param quiet reduce output                  
200
        """
201 202
#        print("====axi_set_dq_idelay %s"%str(delay))
        
203 204 205 206 207 208
        if delay is None:
            delay=[[],[]]
            for i in range(8):
                delay[0].append(vrlg.get_default_field("DLY_LANE0_IDELAY",i))
                delay[1].append(vrlg.get_default_field("DLY_LANE1_IDELAY",i))
        if isinstance(delay,(int,long)):
209
            delay=(delay,delay)
210 211 212 213 214
        elif len(delay) % 8 == 0 :
            delay2=[]
            for lane in range(len(delay)//8):
                delay2.append(delay[8*lane:8*(lane+1)])
            delay=delay2
215
        if quiet < 2:
216
            print("SET DQ IDELAY="+hexMultiple(delay)) # hexMultiple
217 218
        self.axi_set_multiple_delays(vrlg.LD_DLY_LANE0_IDELAY, 0, 8, delay[0], "DLY_LANE0_IDELAY")
        self.axi_set_multiple_delays(vrlg.LD_DLY_LANE1_IDELAY, 0, 8, delay[1], "DLY_LANE1_IDELAY")
219
        self.x393_axi_tasks.write_control_register  (vrlg.DLY_SET,0);# // set all delays
220 221
        
    def axi_set_dq_odelay(self,
222 223 224
                          delay=None, # input [7:0] delay;
                          quiet=1):

225 226
        """
        Set all DQ OUTput delays to the same value
227
        @param delay 8-bit (5+3) delay value to use or a tuple/list with a pair for (lane0, lane1)
228
                Each of the two elements in the delay tuple/list may be a a common integer or a list/tuple itself
229
                if delay is None will restore default values
230
                Alternatively it can be a one-level list/tuple covering all (16) delays
231
        @param quiet reduce output                  
232 233 234 235 236 237 238
        """
        if delay is None:
            delay=[[],[]]
            for i in range(8):
                delay[0].append(vrlg.get_default_field("DLY_LANE0_ODELAY",i))
                delay[1].append(vrlg.get_default_field("DLY_LANE1_ODELAY",i))
        if isinstance(delay,(int,long)):
239
            delay=(delay,delay)
240 241 242 243 244
        elif len(delay) % 8 == 0 :
            delay2=[]
            for lane in range(len(delay)//8):
                delay2.append(delay[8*lane:8*(lane+1)])
            delay=delay2
245
        if quiet < 2:
246
            print("SET DQ ODELAY="+hexMultiple(delay)) # hexMultiple
247 248
        self.axi_set_multiple_delays(vrlg.LD_DLY_LANE0_ODELAY, 0, 8, delay[0], "DLY_LANE0_ODELAY");
        self.axi_set_multiple_delays(vrlg.LD_DLY_LANE1_ODELAY, 0, 8, delay[1], "DLY_LANE1_ODELAY");
249
        self.x393_axi_tasks.write_control_register(vrlg.DLY_SET,0); # set all delays
250 251
        
    def axi_set_dqs_idelay(self,
252 253
                           delay=None, # input [7:0] delay;
                           quiet=1):
254 255
        """
        Set all DQs input delays to the same value
256
        @param delay 8-bit (5+3) delay value to use or a tuple/list with a pair for (lane0, lane1)
257
                if delay is None will restore default values
258
        @param quiet reduce output                  
259
        """
260 261 262
        if delay is None:
            delay=(vrlg.get_default_field("DLY_LANE0_IDELAY",8),vrlg.get_default_field("DLY_LANE1_IDELAY",8))
        if isinstance(delay,(int,long)):
263
            delay=(delay,delay)
264
        if quiet < 2:
265
            print("SET DQS IDELAY="+hexMultiple(delay)) # hexMultiple
266 267
        self.axi_set_multiple_delays(vrlg.LD_DLY_LANE0_IDELAY, 8, 1, delay[0], "DLY_LANE0_IDELAY")
        self.axi_set_multiple_delays(vrlg.LD_DLY_LANE1_IDELAY, 8, 1, delay[1], "DLY_LANE1_IDELAY")
268
        self.x393_axi_tasks.write_control_register(vrlg.DLY_SET,0); # set all delays
269 270

    def axi_set_dqs_odelay(self,
271 272
                           delay=None, # input [7:0] delay;
                           quiet=1):
273 274
        """
        Set all DQs OUTput delays to the same value
275
        @param delay 8-bit (5+3) delay value to use or a tuple/list with a pair for (lane0, lane1)
276
                if delay is None will restore default values
277
        @param quiet reduce output                  
278
                
279
        """
280 281 282
        if delay is None:
            delay=(vrlg.get_default_field("DLY_LANE0_ODELAY",8),vrlg.get_default_field("DLY_LANE1_ODELAY",8))
        if isinstance(delay,(int,long)):
283
            delay=(delay,delay)
284
        if quiet < 2:
285
            print("SET DQS ODELAY="+hexMultiple(delay)) # hexMultiple
286 287
        self.axi_set_multiple_delays(vrlg.LD_DLY_LANE0_ODELAY, 8, 1, delay[0], "DLY_LANE0_ODELAY")
        self.axi_set_multiple_delays(vrlg.LD_DLY_LANE1_ODELAY, 8, 1, delay[1], "DLY_LANE1_ODELAY")
288
        self.x393_axi_tasks.write_control_register(vrlg.DLY_SET,0); # set all delays
289 290

    def axi_set_dm_odelay (self,
291 292
                           delay=None, # input [7:0] delay;
                           quiet=1):
293 294
        """
        Set all DM output delays to the same value
295
        @param delay 8-bit (5+3) delay value to use or a tuple/list with a pair for (lane0, lane1)
296
                if delay is None will restore default values
297
        @param quiet reduce output                  
298
        """
299 300 301
        if delay is None:
            delay=(vrlg.get_default_field("DLY_LANE0_ODELAY",9),vrlg.get_default_field("DLY_LANE1_ODELAY",9))
        if isinstance(delay,(int,long)):
302
            delay=(delay,delay)
303
        if quiet < 2:
304
            print("SET DQM IDELAY="+hexMultiple(delay)) # hexMultiple
305 306
        self.axi_set_multiple_delays(vrlg.LD_DLY_LANE0_ODELAY, 9, 1, delay[0], "DLY_LANE0_ODELAY")
        self.axi_set_multiple_delays(vrlg.LD_DLY_LANE1_ODELAY, 9, 1, delay[1], "DLY_LANE1_ODELAY")
307
        self.x393_axi_tasks.write_control_register(vrlg.DLY_SET,0) #  set all delays
308 309

    def axi_set_cmda_odelay(self,
310 311 312
                               delay=None, # input [7:0] delay;
                               indx=None, # address index
                               quiet=1):
313
        """
314
        Set all command/address output delays to the same value (or a list/tuple of the individual ones)
315
        @param delay 8-bit (5+3) delay value to use or list/tuple containing individual values
316 317
                List elements may be None, those values will not be overwritten
                if delay is None will restore default values
318 319
        @param indx  if present, delay only applies to the specified index (delay should be int/long)
        @param quiet reduce output                  
320 321 322 323
        """
        if delay is None:
            delay=[]
            for i in range(0,32):
324 325 326 327
                if (indx is None) or (i == indx) :
                    delay.append(vrlg.get_default_field("DLY_CMDA",i))
                else:
                    delay.append(None)
328
        if isinstance(delay,(int,long)):
329 330 331 332 333 334
            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:
335
            print("SET COMMAND and ADDRESS ODELAY"+hexMultiple(delay))
336
        self.axi_set_multiple_delays(vrlg.LD_DLY_CMDA, 0, 32, delay, "DLY_CMDA");
337
        self.x393_axi_tasks.write_control_register(vrlg.DLY_SET,0)  # set all delays
338 339

    def axi_set_address_odelay(self,
340 341 342
                               delay=None, # input [7:0] delay;
                               indx=None, # address index
                               quiet=1):
343 344
        """
        Set output delays for address lines only
345
        @param delay 8-bit (5+3) delay value to use or list/tuple containing individual values
346
                List elements may be None, those values will not be overwritten
347
                if delay is None will restore default values
348
        @param indx  if present, delay only applies to the specified index (delay should be int/long)                  
349
        @param quiet reduce output                  
350 351 352 353
        """
        if delay is None:
            delay=[]
            for i in range(0,vrlg.ADDRESS_NUMBER):
354 355 356 357
                if (indx is None) or (i == indx) :
                    delay.append(vrlg.get_default_field("DLY_CMDA",i))
                else:
                    delay.append(None)
358
        if isinstance(delay,(int,long)):
359 360 361 362 363 364
            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:
365
            print("SET ADDRESS ODELAY="+hexMultiple(delay))
366
        self.axi_set_multiple_delays(vrlg.LD_DLY_CMDA, 0, 0, delay, "DLY_CMDA") 
367
        self.x393_axi_tasks.write_control_register(vrlg.DLY_SET,0)  # set all delays
368 369
        
    def axi_set_bank_odelay(self,
370
                            delay=None, # input [7:0] delay;
371 372 373
                            indx=None, # address index
                            quiet=1):
                            
374 375
        """
        Set output delays for bank lines only
376
        @param delay    8-bit (5+3) delay value to use or list/tuple containing individual values
377
                   List elements may be None, those values will not be overwritten
378
                if delay is None will restore default values
379
        @param indx  if present, delay only applies to the specified index (delay should be int/long)                  
380
        @param quiet reduce output                  
381 382
        """
        bank_offset=24
383 384 385
        if delay is None:
            delay=[]
            for i in range(3):
386 387 388 389
                if (indx is None) or (i == indx) :
                    delay.append(vrlg.get_default_field("DLY_CMDA",i+bank_offset))
                else:
                    delay.append(None)
390
        if isinstance(delay,(int,long)):
391 392 393 394 395
            delay=[delay]*3
            if not indx is None:
                for i in range(len(delay)):
                    if (i != indx):
                        delay[i]=None
396
        if quiet < 2:
397
            print("SET BANK ODELAY="+hexMultiple(delay))
398
        self.axi_set_multiple_delays(vrlg.LD_DLY_CMDA, bank_offset, 0,delay, "DLY_CMDA")  # length will be determined by len(delay)
399
        self.x393_axi_tasks.write_control_register(vrlg.DLY_SET,0)  # set all delays
400 401

    def axi_set_cmd_odelay(self,
402
                           delay=None, # input [7:0] delay;
403 404
                           indx=None, # address index
                           quiet=1):
405 406
        """
        Set output delays for command lines only. command=(we,ras,cas,cke,odt)
407
        @param delay    8-bit (5+3) delay value to use or list/tuple containing individual values
408
                   List elements may be None, those values will not be overwritten
409
                   if delay is None will restore default values
410 411
        @param indx  if present, delay only applies to the specified index (delay should be int/long)
        @param quiet reduce output                  
412 413
        """
        command_offset=24+3
414 415 416
        if delay is None:
            delay=[]
            for i in range(5):
417 418 419 420
                if (indx is None) or (i == indx) :
                    delay.append(vrlg.get_default_field("DLY_CMDA",i+command_offset))
                else:
                    delay.append(None)
421
        if isinstance(delay,(int,long)):
422 423 424 425 426
            delay=[delay]*5
            if not indx is None:
                for i in range(len(delay)):
                    if (i != indx):
                        delay[i]=None
427
        if quiet < 2:
428
            print("SET COMMAND ODELAY="+hexMultiple(delay))
429
        self.axi_set_multiple_delays(vrlg.LD_DLY_CMDA, command_offset, 0,delay, "DLY_CMDA")  # length will be determined by len(delay)
430
        self.x393_axi_tasks.write_control_register(vrlg.DLY_SET,0)  # set all delays
431
        
432 433 434
        
    def axi_set_multiple_delays(self,
                                reg_addr, #input [29:0] reg_addr;
435
                                offset,   # add this offset to address
436
                                number,   # input integer number;
437 438
                                delay,    # input [7:0]  delay;
                                vname):   # Verilog parameter name (if None - do not update Verilog parameter value (it is already it)
439 440 441
        """
        Set same delay to a range of I/O delay registers
        <reg_addr> control register address of the first register in the range
442
        <offset>   add this offset to address
443
        <number>   number of registers to write
444
        @param delay    8-bit (5+3) delay value to use or list/tuple containing individual values
445
                   List elements may be None, those values will not be overwritten
446
        <vname>    Verilog parameter name
447
        """
448
#        print ("===axi_set_multiple_delays(0x%x,%d,%s"%(reg_addr,number,delay))
449
        if delay is None: return # Do nothing, that's OK
450
        if isinstance(delay,(int,long)):
451
            delay=[delay]*number
452
        if len(delay) < number:
453
            delay= delay + [None]*(number-len(delay)) #
454 455
        for i, d in enumerate(delay):
            if not d is None:
456
                self.x393_axi_tasks.write_control_register(reg_addr + (offset + i), d)
457 458
                if vname:
                    vrlg.set_name_field(vname, offset + i, d)
459

460
    def wait_phase_shifter_ready(self):
461 462 463
        """
        Wait until clock phase shifter is ready
        """
464
        data=self.x393_axi_tasks.read_status(vrlg.MCONTR_PHY_STATUS_REG_ADDR)
465 466 467
        expected_phase = vrlg.DLY_PHASE
        if (vrlg.CLKFBOUT_USE_FINE_PS):
            expected_phase = (-expected_phase) & 0xff;
468 469
        while (((data & vrlg.STATUS_PSHIFTER_RDY_MASK) == 0) or (((data ^ vrlg.DLY_PHASE) & 0xff) != 0)):
            data=self.x393_axi_tasks.read_status(vrlg.MCONTR_PHY_STATUS_REG_ADDR)
470 471
            if self.DRY_MODE: break

472
    def axi_set_wbuf_delay(self,
473
                            delay=None): # input [3:0] delay;
474 475
        """
        Set write to buffer latency
476
        @param delay    4-bit write to buffer signal delay (in mclk clock cycles)
477
                   if delay is None will restore default values
478
        """
479 480 481 482
        if delay is None:
            delay= vrlg.get_default("DFLT_WBUF_DELAY")
             
        vrlg.DFLT_WBUF_DELAY=delay
483 484
        if self.DEBUG_MODE > 1:
            print("SET WBUF DELAY=0x%x"%delay)
485
        self.x393_axi_tasks.write_control_register(vrlg.MCONTR_PHY_16BIT_ADDR+vrlg.MCONTR_PHY_16BIT_WBUF_DELAY, delay & 0xf) # {28'h0, delay});
486
#set dq /dqs tristate on/off patterns
487 488 489

    def axi_set_tristate_patterns(self,
                                  strPattern=None):
490 491
        """
        Set sequencer patterns for the tristate ON/OFF (defined by parameters)
492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508
        <strPattern> - optional up to 4-letter pattern. Each letter is one of 3:
                       'E'- early, "N" - nominal and 'L' - late, first for DQ start,
                       second - for DQS start, then DQ end and DQS end. If no pattern
                       is provided, all will be set to Verilog parameter values (DQ*TRI_*),
                       if only 1 - it will be applied to all, if 2 - it will be
                       repeated twice, 3 will use  the same value for DQS end as for DQS start
        """
        modes={'E':0,'N':1,'L':2}
        evNames=('DQ_FIRST', 'DQS_FIRST', 'DQ_LAST','DQS_LAST')
        
        patVals={evNames[0]: (0x3,0x7,0xf), # DQ_FIRST:  early, nominal, late
                 evNames[1]: (0x1,0x3,0x7), # DQS_FIRST: early, nominal, late
                 evNames[2]: (0xf,0xe,0xc), # DQ_LAST:   early, nominal, late
                 evNames[3]: (0xe,0xc,0x8)} # DQS_LAST:  early, nominal, late
        
        if not strPattern:
            delays=concat(((0,16), #  {16'h0, 
509 510 511 512
                           (vrlg.DQSTRI_LAST, getParWidth(vrlg.DQSTRI_LAST__TYPE)),      #  DQSTRI_LAST,
                           (vrlg.DQSTRI_FIRST,getParWidth(vrlg.DQSTRI_FIRST__TYPE)),     #  DQSTRI_FIRST,
                           (vrlg.DQTRI_LAST,  getParWidth(vrlg.DQTRI_LAST__TYPE)),       #   DQTRI_LAST,
                           (vrlg.DQTRI_FIRST, getParWidth(vrlg.DQTRI_FIRST__TYPE)))      #   DQTRI_FIRST});
513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532
                          )[0]
        else:
            strPattern=strPattern.upper()
            if len(strPattern) == 1:
                strPattern*=4
            elif len(strPattern) == 2:
                strPattern*=2
            elif len(strPattern) == 3:
                strPattern+=strPattern[1]
            strPattern=strPattern[:4]
            vals={}
            for i,n in enumerate(evNames):
                try:
                    vals[n]=patVals[n][modes[strPattern[i]]]
                except:
                    msg="axi_set_tristate_patterns(%s): Failed to determine delay mode for %s, got %s"%(strPattern,n,strPattern[i])
                    print (msg)
                    Exception(msg)              
            print ("axi_set_tristate_patterns(%s) : %s"%(strPattern,str(vals)))
            delays=concat(((0,16), #  {16'h0, 
533 534 535 536
                           (vals['DQS_LAST'],4),  # vrlg.DQSTRI_LAST, getParWidth(vrlg.DQSTRI_LAST__TYPE)),      #  DQSTRI_LAST,
                           (vals['DQS_FIRST'],4), # vrlg.DQSTRI_FIRST,getParWidth(vrlg.DQSTRI_FIRST__TYPE)),     #  DQSTRI_FIRST,
                           (vals['DQ_LAST'],4),   # vrlg.DQTRI_LAST,  getParWidth(vrlg.DQTRI_LAST__TYPE)), #   DQTRI_LAST,
                           (vals['DQ_FIRST'],4))  # vrlg.DQTRI_FIRST, getParWidth(vrlg.DQTRI_FIRST__TYPE)))       #   DQTRI_FIRST});
537 538
                          )[0]
                 
539
        # may fail if some of the parameters used have undefined width
540 541
        print("DQTRI_FIRST=%s, DQTRI_FIRST__TYPE=%s"%(str(vrlg.DQTRI_FIRST),str(vrlg.DQTRI_FIRST__TYPE)))
        print("DQTRI_LAST=%s, DQTRI_LAST__TYPE=%s"%(str(vrlg.DQTRI_LAST),str(vrlg.DQTRI_LAST__TYPE)))
542
        if self.DEBUG_MODE > 1:
Andrey Filippov's avatar
Andrey Filippov committed
543
            print("SET TRISTATE PATTERNS, combined delays=%s"%str(delays))    
544
            print("SET TRISTATE PATTERNS, combined delays=0x%x"%delays)    
545
        self.x393_axi_tasks.write_control_register(vrlg.MCONTR_PHY_16BIT_ADDR +vrlg.MCONTR_PHY_16BIT_PATTERNS_TRI, delays) #  DQSTRI_LAST, DQSTRI_FIRST, DQTRI_LAST, DQTRI_FIRST});
546

547
    def axi_set_dqs_dqm_patterns(self,
548
                                 dqs_patt=None,
549 550
                                 dqm_patt=None,
                                 quiet=1):
551 552
        """
        Set sequencer patterns for the DQ lines ON/OFF (defined by parameters)
553 554 555
        @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
556 557 558 559 560 561
        """
        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)
562 563 564
        vrlg.dqs_dqm_patt=patt
        if quiet < 2 :
            print("axi_set_dqs_dqm_patterns(): SET DQS+DQM PATTERNS, patt= 0x%08x (TODO:reduce quiet threshold)"%patt)
565
# set patterns for DM (always 0) and DQS - always the same (may try different for write lev.)        
566
        self.x393_axi_tasks.write_control_register(vrlg.MCONTR_PHY_16BIT_ADDR + vrlg.MCONTR_PHY_16BIT_PATTERNS, patt) # 32'h0055);
567
        
568 569 570 571 572 573
    def get_dqs_dqm_patterns(self):
        #print ('vrlg.dqs_dqm_patt=',vrlg.dqs_dqm_patt)
        try:
            return (vrlg.dqs_dqm_patt & 0xff,(vrlg.dqs_dqm_patt >> 8) & 0xff)
        except:
            return None    
574 575 576 577 578 579 580 581
    def util_test4(self):
#        print("vrlg.globals():")
#        print(vrlg.globals())
#        print("vrlg.__dict__")
#        print(vrlg.__dict__)
        print ("DLY_PHASE = 0x%x"%vrlg.DLY_PHASE)
        for k,v in vrlg.__dict__.items():
            print ("%s = %s"%(k,str(v)))