x393_mcntrl_timing.py 27.9 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 67 68 69 70 71 72 73
    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}
74
        
Andrey Filippov's avatar
Andrey Filippov committed
75
    def axi_set_phase(self,
76
                      phase=None,      # input [PHASE_WIDTH-1:0] phase;
Andrey Filippov's avatar
Andrey Filippov committed
77
                      wait_phase_en=True,
78 79
                      wait_seq=False,
                      quiet=1):
Andrey Filippov's avatar
Andrey Filippov committed
80
        """
81
        Set clock phase TODO: Add refresh off/on for changing phase
82
        <phase>    8-bit clock phase value (None will use default)
Andrey Filippov's avatar
Andrey Filippov committed
83 84
        <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)
85
        @param quiet reduce output
Andrey Filippov's avatar
Andrey Filippov committed
86 87
        Returns 1 if success, 0 if timeout (or no wait was performed)
        """
88 89 90
        if phase is None:
            phase= vrlg.get_default("DLY_PHASE") 
        vrlg.DLY_PHASE=phase & ((1<<vrlg.PHASE_WIDTH)-1)
91
        if quiet<2:
92 93 94 95
            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)
#        self.target_phase = phase
Andrey Filippov's avatar
Andrey Filippov committed
96 97 98 99 100 101 102 103 104 105 106 107 108
        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
        """
109
        patt = 0x3000000 | vrlg.DLY_PHASE
Andrey Filippov's avatar
Andrey Filippov committed
110 111 112 113
        mask = 0x3000100
        if check_phase_value:
            mask |= 0xff
        return self.x393_axi_tasks.wait_status_condition(
114 115
                              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
116 117 118 119 120 121 122 123
                              3,                                                              # status_mode,
                              patt,                                                           # pattern,
                              mask,                                                           # mask
                              0,                                                              # invert_match
                              wait_seq,                                                       # wait_seq;
                              1.0)                                                            # maximal timeout (0 - no timeout)
       
        
124
    def get_target_phase(self):
125 126 127
        """
        Returns previously set clock phase value
        """
128
        return vrlg.DLY_PHASE
129 130 131 132 133 134 135
    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;
136 137 138 139 140 141 142 143 144 145 146 147 148 149
        """
        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))
150 151 152 153 154 155 156 157
        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):
158 159 160
        """
        Set DQS input delays to values defined for the write levelling mode (parameter-defined)
        """
161 162 163 164 165
        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")
#        self.x393_axi_tasks.write_contol_register(vrlg.LD_DLY_LANE0_IDELAY + 8,      vrlg.DLY_LANE0_DQS_WLV_IDELAY)
#        self.x393_axi_tasks.write_contol_register(vrlg.LD_DLY_LANE1_IDELAY + 8,      vrlg.DLY_LANE1_DQS_WLV_IDELAY)
        self.x393_axi_tasks.write_contol_register(vrlg.DLY_SET,0)
166

167
    def axi_set_delays(self,quiet=1): #  set all individual delays
168
        """
169 170 171
        Set all DDR3 I/O delays to individual parameter-defined values (using default values,
        current ones are supposed to be synchronized)
        """
172 173 174 175 176 177 178
        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)
179 180
        
    def axi_set_dq_idelay(self,   #  sets same delay to all dq idelay
181 182
                          delay=None, # input [7:0] delay;
                          quiet=1):
183 184
        """
        Set all DQ input delays to the same value
185
        @param delay 8-bit (5+3) delay value to use or a tuple/list with a pair for (lane0, lane1)
186
                Each of the two elements in the delay tuple/list may be a a common integer or a list/tuple itself
187
                if delay is None will restore default values
188
                Alternatively it can be a one-level list/tuple covering all (16) delays
189
        @param quiet reduce output                  
190
        """
191 192
#        print("====axi_set_dq_idelay %s"%str(delay))
        
193 194 195 196 197 198
        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)):
199
            delay=(delay,delay)
200 201 202 203 204
        elif len(delay) % 8 == 0 :
            delay2=[]
            for lane in range(len(delay)//8):
                delay2.append(delay[8*lane:8*(lane+1)])
            delay=delay2
205
        if quiet < 2:
206
            print("SET DQ IDELAY="+hexMultiple(delay)) # hexMultiple
207 208 209
        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")
        self.x393_axi_tasks.write_contol_register  (vrlg.DLY_SET,0);# // set all delays
210 211
        
    def axi_set_dq_odelay(self,
212 213 214
                          delay=None, # input [7:0] delay;
                          quiet=1):

215 216
        """
        Set all DQ OUTput delays to the same value
217
        @param delay 8-bit (5+3) delay value to use or a tuple/list with a pair for (lane0, lane1)
218
                Each of the two elements in the delay tuple/list may be a a common integer or a list/tuple itself
219
                if delay is None will restore default values
220
                Alternatively it can be a one-level list/tuple covering all (16) delays
221
        @param quiet reduce output                  
222 223 224 225 226 227 228
        """
        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)):
229
            delay=(delay,delay)
230 231 232 233 234
        elif len(delay) % 8 == 0 :
            delay2=[]
            for lane in range(len(delay)//8):
                delay2.append(delay[8*lane:8*(lane+1)])
            delay=delay2
235
        if quiet < 2:
236
            print("SET DQ ODELAY="+hexMultiple(delay)) # hexMultiple
237 238 239
        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");
        self.x393_axi_tasks.write_contol_register(vrlg.DLY_SET,0); # set all delays
240 241
        
    def axi_set_dqs_idelay(self,
242 243
                           delay=None, # input [7:0] delay;
                           quiet=1):
244 245
        """
        Set all DQs input delays to the same value
246
        @param delay 8-bit (5+3) delay value to use or a tuple/list with a pair for (lane0, lane1)
247
                if delay is None will restore default values
248
        @param quiet reduce output                  
249
        """
250 251 252
        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)):
253
            delay=(delay,delay)
254
        if quiet < 2:
255
            print("SET DQS IDELAY="+hexMultiple(delay)) # hexMultiple
256 257 258
        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")
        self.x393_axi_tasks.write_contol_register(vrlg.DLY_SET,0); # set all delays
259 260

    def axi_set_dqs_odelay(self,
261 262
                           delay=None, # input [7:0] delay;
                           quiet=1):
263 264
        """
        Set all DQs OUTput delays to the same value
265
        @param delay 8-bit (5+3) delay value to use or a tuple/list with a pair for (lane0, lane1)
266
                if delay is None will restore default values
267
        @param quiet reduce output                  
268
                
269
        """
270 271 272
        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)):
273
            delay=(delay,delay)
274
        if quiet < 2:
275
            print("SET DQS ODELAY="+hexMultiple(delay)) # hexMultiple
276 277 278
        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")
        self.x393_axi_tasks.write_contol_register(vrlg.DLY_SET,0); # set all delays
279 280

    def axi_set_dm_odelay (self,
281 282
                           delay=None, # input [7:0] delay;
                           quiet=1):
283 284
        """
        Set all DM output delays to the same value
285
        @param delay 8-bit (5+3) delay value to use or a tuple/list with a pair for (lane0, lane1)
286
                if delay is None will restore default values
287
        @param quiet reduce output                  
288
        """
289 290 291
        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)):
292
            delay=(delay,delay)
293
        if quiet < 2:
294
            print("SET DQM IDELAY="+hexMultiple(delay)) # hexMultiple
295 296 297
        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")
        self.x393_axi_tasks.write_contol_register(vrlg.DLY_SET,0) #  set all delays
298 299

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

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

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

450
    def wait_phase_shifter_ready(self):
451 452 453
        """
        Wait until clock phase shifter is ready
        """
454 455 456
        data=self.x393_axi_tasks.read_status(vrlg.MCONTR_PHY_STATUS_REG_ADDR)
        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)
457 458
            if self.DRY_MODE: break

459
    def axi_set_wbuf_delay(self,
460
                            delay=None): # input [3:0] delay;
461 462
        """
        Set write to buffer latency
463
        @param delay    4-bit write to buffer signal delay (in mclk clock cycles)
464
                   if delay is None will restore default values
465
        """
466 467 468 469
        if delay is None:
            delay= vrlg.get_default("DFLT_WBUF_DELAY")
             
        vrlg.DFLT_WBUF_DELAY=delay
470 471
        if self.DEBUG_MODE > 1:
            print("SET WBUF DELAY=0x%x"%delay)
472
        self.x393_axi_tasks.write_contol_register(vrlg.MCONTR_PHY_16BIT_ADDR+vrlg.MCONTR_PHY_16BIT_WBUF_DELAY, delay & 0xf) # {28'h0, delay});
473
#set dq /dqs tristate on/off patterns
474 475 476

    def axi_set_tristate_patterns(self,
                                  strPattern=None):
477 478
        """
        Set sequencer patterns for the tristate ON/OFF (defined by parameters)
479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495
        <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, 
496 497 498 499
                           (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});
500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519
                          )[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, 
520 521 522 523
                           (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});
524 525
                          )[0]
                 
526
        # may fail if some of the parameters used have undefined width
527 528
        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)))
529
        if self.DEBUG_MODE > 1:
Andrey Filippov's avatar
Andrey Filippov committed
530
            print("SET TRISTATE PATTERNS, combined delays=%s"%str(delays))    
531
            print("SET TRISTATE PATTERNS, combined delays=0x%x"%delays)    
532
        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});
533

534
    def axi_set_dqs_dqm_patterns(self,
535
                                 dqs_patt=None,
536 537
                                 dqm_patt=None,
                                 quiet=1):
538 539
        """
        Set sequencer patterns for the DQ lines ON/OFF (defined by parameters)
540 541 542
        @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
543 544 545 546 547 548
        """
        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)
549 550 551
        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)
552
# set patterns for DM (always 0) and DQS - always the same (may try different for write lev.)        
553
        self.x393_axi_tasks.write_contol_register(vrlg.MCONTR_PHY_16BIT_ADDR + vrlg.MCONTR_PHY_16BIT_PATTERNS, patt) # 32'h0055);
554
        
555 556 557 558 559 560
    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    
561 562 563 564 565 566 567 568
    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)))