x393_pio_sequences.py 80 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_mcntrl_timing      import X393McntrlTiming
36
from x393_mem import X393Mem
37 38
#from x393_axi_control_status import X393AxiControlStatus
import x393_axi_control_status
39
from x393_mcntrl_buffers     import X393McntrlBuffers
40
#from verilog_utils import * # concat, bits 
41
from verilog_utils import concat, bits, convert_mem16_to_w32, convert_w32_to_mem16 
42 43
#from x393_axi_control_status import concat, bits
import vrlg # global parameters
44 45
from time import sleep

46 47 48 49 50 51
class X393PIOSequences(object):
    DRY_MODE= True # True
    DEBUG_MODE=1
#    vpars=None
    x393_mem=None
    x393_axi_tasks=None #x393X393AxiControlStatus
52
    x393_mcntrl_timing=None
53 54 55 56 57
    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)
58 59
#        self.x393_axi_tasks=X393AxiControlStatus(debug_mode,dry_mode)
        self.x393_axi_tasks=x393_axi_control_status.X393AxiControlStatus(debug_mode,dry_mode)
60
        self.x393_mcntrl_buffers= X393McntrlBuffers(debug_mode,dry_mode)
61
        self.x393_mcntrl_timing=  X393McntrlTiming(debug_mode,dry_mode)
62
#        self.__dict__.update(VerilogParameters.__dict__["_VerilogParameters__shared_state"]) # Add verilog parameters to the class namespace
63 64 65 66 67
        '''
        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
        '''
        
68
    def schedule_ps_pio(self,          #; // schedule software-control memory operation (may need to check FIFO status first)
69 70 71 72 73
                        seq_addr,      # input [9:0] seq_addr; // sequence start address
                        page,          # input [1:0] page;     // buffer page number
                        urgent,        # input       urgent;   // high priority request (only for competion wityh other channels, wiil not pass in this FIFO)
                        chn,           # input       chn;      // channel buffer to use: 0 - memory read, 1 - memory write
                        wait_complete): # input       wait_complete; // Do not request a newe transaction from the scheduler until previous memory transaction is finished
74 75 76 77 78 79 80 81 82
        """
        Schedule PS PIO memory transaction 
        <seq_addr>       10-bit sequence start address
        <page>           buffer page address to use (0..3)
        <urgent>         high priority request (only for competition with other channels,
                         will not pass other commands in this module FIFO)  
        <chn>            sub-channel to use: 0 - memory read, 1 - memory write
        <wait_complete>  Do not request a new transaction from the scheduler until previous memory transaction is finished
        """
83
        self.x393_axi_tasks.write_contol_register(vrlg.MCNTRL_PS_ADDR + vrlg.MCNTRL_PS_CMD,
84 85 86 87 88 89
                                                  # {17'b0,
                                                  ((0,1)[wait_complete]<<14) |
                                                  ((0,1)[chn]<<13) |
                                                  ((0,1)[urgent]<<12) |
                                                  ((page & 3) << 10) |
                                                  (seq_addr & 0x3ff))
90
 
91 92 93 94
    def wait_ps_pio_ready(self,         #; // wait PS PIO module can accept comamnds (fifo half empty)
                          mode,         # input [1:0] mode;
                          sync_seq,     # input       sync_seq; //  synchronize sequences
                          timeout=2.0): # maximal timeout in seconds
95 96 97 98 99 100
        """
        Wait until PS PIO module can accept comamnds (fifo half empty) 
        <mode>           status mode (0..3) - see 'help program_status'
        <synq_seq>       status sequence number - see 'help program_status'
        """
        
101
        self.x393_axi_tasks.wait_status_condition (
102 103
            vrlg.MCNTRL_PS_STATUS_REG_ADDR,
            vrlg.MCNTRL_PS_ADDR + vrlg.MCNTRL_PS_STATUS_CNTRL,
104 105
            mode & 3,
            0,
106
            2 << vrlg.STATUS_2LSB_SHFT,
107 108 109
            0,
            sync_seq)

Andrey Filippov's avatar
Andrey Filippov committed
110 111 112 113
    def wait_ps_pio_done(self,         # // wait PS PIO module has no pending/running memory transaction
                         mode,         # input [1:0] mode;
                         sync_seq,     # input       sync_seq; //  synchronize sequences
                         timeout=2.0): # maximal timeout in seconds
114 115 116 117 118
        """
        Wait PS PIO module has no pending/running memory transaction
        <mode>           status mode (0..3) - see 'help program_status'
        <synq_seq>       status sequence number - see 'help program_status'
        """
119
        self.x393_axi_tasks.wait_status_condition (
120 121
            vrlg.MCNTRL_PS_STATUS_REG_ADDR,
            vrlg.MCNTRL_PS_ADDR + vrlg.MCNTRL_PS_STATUS_CNTRL,
122 123
            mode & 3,
            0,
124
            3 << vrlg.STATUS_2LSB_SHFT,
125
            0,
Andrey Filippov's avatar
Andrey Filippov committed
126 127
            sync_seq,
            timeout)
128 129 130 131
    '''
    x393_mcontr_encode_cmd
    '''
    def func_encode_cmd(self,      # function [31:0] 
132
                        addr,      # input               [14:0] addr;       // 15-bit row/column address
133 134 135 136 137 138 139 140 141 142 143 144 145
                        bank,      # input                [2:0] bank;       // bank (here OK to be any)
                        rcw,       # input                [2:0] rcw;        // RAS/CAS/WE, positive logic
                        odt_en,    # input                      odt_en;     // enable ODT
                        cke,       # input                      cke;        // disable CKE
                        sel,       # input                      sel;        // first/second half-cycle, other will be nop (cke+odt applicable to both)
                        dq_en,     # input                      dq_en;      // enable (not tristate) DQ  lines (internal timing sequencer for 0->1 and 1->0)
                        dqs_en,    # input                      dqs_en;     // enable (not tristate) DQS lines (internal timing sequencer for 0->1 and 1->0)
                        dqs_toggle,# input                      dqs_toggle; // enable toggle DQS according to the pattern
                        dci,       # input                      dci;        // DCI disable, both DQ and DQS lines (internal logic and timing sequencer for 0->1 and 1->0)
                        buf_wr,    # input                      buf_wr;     // connect to external buffer (but only if not paused)
                        buf_rd,    # input                      buf_rd;     // connect to external buffer (but only if not paused)
                        nop,       # input                      nop;        // add NOP after the current command, keep other data
                        buf_rst):  # input                      buf_rst;    // connect to external buffer (but only if not paused)
146 147
        """
        Encode data into memory controller sequencer word
148
        <addr>       15-bit row/column address
149 150 151 152 153 154 155 156 157 158 159 160 161 162
        <bank>       3-bit bank address
        <rcw>        3-bit combined {RAS,CAS,WE}, positive logic
        <odt_en>     enable ODT
        <cke>        disable CKE
        <sel>        first(0)/second(1) half-cycle, other half-cycle will be NOP (cke+odt applicable to both)
        <dq_en>      enable (turn tristate off) DQ  lines (internal timing sequencer for 0->1 and 1->0)
        <dqs_en>     enable (turn tristate off) DQS lines (internal timing sequencer for 0->1 and 1->0)
        <dqs_toggle> enable toggle DQS lines according to the pattern
        <dci>        DCI disable, both DQ and DQS lines (internal logic and timing sequencer for 0->1 and 1->0)
        <buf_wr>     generate external buffer write/address increment
        <buf_rd>     generate external buffer read/address increment
        <nop>        add NOP after the current command, keep other data
        <buf_rst>    reset external buffer page address to 0, increment page number
        """
163
        return (
164
            ((addr & 0x7fff) << 17) | # addr[14:0], // 15-bit row/column address
165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
            ((bank & 0x7)    << 14) | # bank [2:0], // bank
            ((rcw  & 0x7)    << 11) | # rcw[2:0],   // RAS/CAS/WE
            ((0,1)[odt_en]   << 10) | # odt_en,     // enable ODT
            ((0,1)[cke]      <<  9) | # cke,        // may be optimized (removed from here)?
            ((0,1)[sel]      <<  8) | # sel,        // first/second half-cycle, other will be nop (cke+odt applicable to both)
            ((0,1)[dq_en]    <<  7) | # dq_en,      // enable (not tristate) DQ  lines (internal timing sequencer for 0->1 and 1->0)
            ((0,1)[dqs_en]   <<  6) | # dqs_en,     // enable (not tristate) DQS  lines (internal timing sequencer for 0->1 and 1->0)
            ((0,1)[dqs_toggle]<< 5) | # dqs_toggle, // enable toggle DQS according to the pattern
            ((0,1)[dci]      <<  4) | # dci,        // DCI disable, both DQ and DQS lines (internal logic and timing sequencer for 0->1 and 1->0)
            ((0,1)[buf_wr]   <<  3) | # buf_wr,     // phy_buf_wr,   // connect to external buffer (but only if not paused)
            ((0,1)[buf_rd]   <<  2) | # buf_rd,     // phy_buf_rd,    // connect to external buffer (but only if not paused)
            ((0,1)[nop]      <<  1) | # nop,        // add NOP after the current command, keep other data
            ((0,1)[buf_rst]  <<  0)   # buf_rst     // Reset buffer address/ increase buffer page
           )

    def func_encode_skip(self,       # function [31:0]
                          skip,       # input [CMD_PAUSE_BITS-1:0] skip;       // number of extra cycles to skip (and keep all the other outputs)
                          done,       # input                      done;       // end of sequence 
                          bank,       # input [2:0]                bank;       // bank (here OK to be any)
                          odt_en,     # input                      odt_en;     // enable ODT
                          cke,        # input                      cke;        // disable CKE
                          sel,        # input                      sel;        // first/second half-cycle, other will be nop (cke+odt applicable to both)
                          dq_en,      # input                      dq_en;      // enable (not tristate) DQ  lines (internal timing sequencer for 0->1 and 1->0)
                          dqs_en,     # input                      dqs_en;     // enable (not tristate) DQS lines (internal timing sequencer for 0->1 and 1->0)
                          dqs_toggle, # input                      dqs_toggle; // enable toggle DQS according to the pattern
                          dci,        # input                      dci;        // DCI disable, both DQ and DQS lines (internal logic and timing sequencer for 0->1 and 1->0)
                          buf_wr,     # input                      buf_wr;     // connect to external buffer (but only if not paused)
                          buf_rd,     # input                      buf_rd;     // connect to external buffer (but only if not paused)
193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
                          buf_rst):   #input                       buf_rst;    // connect to external buffer (but only if not paused)
        """
        Encode skip cycles command into memory controller sequencer word. NOP will be present on RCW(RAS/CAS/WE) lines
        <skip>       10-bit number of cycles to skip minus 1
        <done>       10-bit number of cycles to skip minus 1
        <bank>       3-bit bank address
        <odt_en>     enable ODT
        <cke>        disable CKE
        <sel>        first(0)/second(1) half-cycle, other half-cycle will be NOP (cke+odt applicable to both)
        <dq_en>      enable (turn tristate off) DQ  lines (internal timing sequencer for 0->1 and 1->0)
        <dqs_en>     enable (turn tristate off) DQS lines (internal timing sequencer for 0->1 and 1->0)
        <dqs_toggle> enable toggle DQS lines according to the pattern
        <dci>        DCI disable, both DQ and DQS lines (internal logic and timing sequencer for 0->1 and 1->0)
        <buf_wr>     generate external buffer write/address increment
        <buf_rd>     generate external buffer read/address increment
        <buf_rst>    reset external buffer page address to 0, increment page number
        """
210
        return self.func_encode_cmd (
211 212
                ((0,1)[done] << vrlg.CMD_PAUSE_BITS) |    # {{14-CMD_DONE_BIT{1'b0}}, done, 
                (skip & ((1 << vrlg.CMD_PAUSE_BITS)-1)), # skip[CMD_PAUSE_BITS-1:0]},       // 15-bit row/column address
213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256
                bank & 7,   # bank[2:0],  // bank (here OK to be any)
                0,          # 3'b0,       // RAS/CAS/WE, positive logic
                odt_en,     #// enable ODT
                cke,        #// disable CKE
                sel,        #// first/second half-cycle, other will be nop (cke+odt applicable to both)
                dq_en,      #// enable (not tristate) DQ  lines (internal timing sequencer for 0->1 and 1->0)
                dqs_en,     #// enable (not tristate) DQS lines (internal timing sequencer for 0->1 and 1->0)
                dqs_toggle, #// enable toggle DQS according to the pattern
                dci,        #// DCI disable, both DQ and DQS lines (internal logic and timing sequencer for 0->1 and 1->0)
                buf_wr,     #// connect to external buffer (but only if not paused)
                buf_rd,     #// connect to external buffer (but only if not paused)
                0,          # 1'b0,       // nop
                buf_rst)    #
        
    def func_ddr3_mr0(self, # ; # function [ADDRESS_NUMBER+2:0]
                      pd, # input       pd; // precharge power down 0 - dll off (slow exit), 1 - dll on (fast exit) 
                      wr, # input [2:0] wr; // write recovery:
                          # 3'b000: 16
                          # 3'b001:  5
                          # 3'b010:  6
                          # 3'b011:  7
                          # 3'b100:  8
                          # 3'b101: 10
                          # 3'b110: 12
                          # 3'b111: 14
                      dll_rst,  # input       dll_rst; // 1 - dll reset (self clearing bit)
                      cl, # input [3:0] cl; // CAS latency (>=15ns):
                          # 0000: reserved                   
                          # 0010:  5                   
                          # 0100:  6                   
                          # 0110:  7                 
                          # 1000:  8                 
                          # 1010:  9                 
                          # 1100: 10                   
                          # 1110: 11                   
                          # 0001: 12                  
                          # 0011: 13                  
                          # 0101: 14
                      bt, #input       bt; # read burst type: 0 sequential (nibble), 1 - interleaved
                      bl):  #input [1:0] bl; # burst length:
        #                   2'b00 - fixed BL8
        #                   2'b01 - 4 or 8 on-the-fly by A12                                     
        #                   2'b10 - fixed BL4 (chop)
        #                   2'b11 - reserved
257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289
        """
        Encode DDR3 MR0 register data
        <pd>  precharge power down 0 - dll off (slow exit), 1 - dll on (fast exit) 
        <wr>  write recovery:
            000: 16
            001:  5
            010:  6
            011:  7
            100:  8
            101: 10
            110: 12
            111: 14
        <dll_rst> 1 - dll reset (self clearing bit)
        <cl> CAS latency (>=15ns):
            0000: reserved                   
            0010:  5                   
            0100:  6                   
            0110:  7                 
            1000:  8                 
            1010:  9                 
            1100: 10                   
            1110: 11                   
            0001: 12                  
            0011: 13                  
            0101: 14
        <bt>  read burst type: 0 sequential (nibble), 1 - interleaved
        <bl>  burst length:
            00 - fixed BL8
            01 - 4 or 8 on-the-fly by A12                                     
            10 - fixed BL4 (chop)
            11 - reserved
        """
        
290 291
        return concat((
              (0,3),                      # 3'b0,
292
              (0,vrlg.ADDRESS_NUMBER-13), #  {ADDRESS_NUMBER-13{1'b0}},
293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323
              (pd,1),              # pd,       # MR0.12 
              (wr,3),                     # wr,       # MR0.11_9
              (dll_rst,1),                # dll_rst,  # MR0.8
              (0,1),                      # 1'b0,     # MR0.7
              (cl>>1,3),                  # cl[3:1],  # MR0.6_4
              (bt,1),                     # bt,       # MR0.3
              (cl&1,1),                   # cl[0],    # MR0.2
              (bl,2)))[0]                 # bl[1:0]}; # MR0.1_0

    def func_ddr3_mr1(self, # function [ADDRESS_NUMBER+2:0] 
                      qoff, # input       qoff; # output enable: 0 - DQ, DQS operate in normal mode, 1 - DQ, DQS are disabled
                      tdqs, # input       tdqs; # termination data strobe (for x8 devices) 0 - disabled, 1 - enabled
                      rtt,  # input [2:0] rtt;  # on-die termination resistance:
                          #  3'b000 - disabled
                          #  3'b001 - RZQ/4 (60 Ohm)
                          #  3'b010 - RZQ/2 (120 Ohm)
                          #  3'b011 - RZQ/6 (40 Ohm)
                          #  3'b100 - RZQ/12(20 Ohm)
                          #  3'b101 - RZQ/8 (30 Ohm)
                          #  3'b11x - reserved
                      wlev, #input       wlev; # write leveling
                      ods, # input [1:0] ods;  # output drive strength:
                          #  2'b00 - RZQ/6 - 40 Ohm
                          #  2'b01 - RZQ/7 - 34 Ohm
                          #  2'b1x - reserved
                      al, # input [1:0] al;   # additive latency:
                          #  2'b00 - disabled (AL=0)
                          #  2'b01 - AL=CL-1;
                          #  2'b10 - AL=CL-2
                          #  2'b11 - reserved
                      dll): #input       dll;  # 0 - DLL enabled (normal), 1 - DLL disabled
324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347
        """
        Encode DDR3 MR1 register data
        <qoff>  output enable: 0 - DQ, DQS operate in normal mode, 1 - DQ, DQS are disabled
        <tdqs>  termination data strobe (for x8 devices) 0 - disabled, 1 - enabled
        <rtt>   on-die termination resistance:
            000 - disabled
            001 - RZQ/4 (60 Ohm)
            010 - RZQ/2 (120 Ohm)
            011 - RZQ/6 (40 Ohm)
            100 - RZQ/12(20 Ohm)
            101 - RZQ/8 (30 Ohm)
            11x - reserved
        <wlev>  write leveling mode
        <ods>   output drive strength:
            00 - RZQ/6 - 40 Ohm
            01 - RZQ/7 - 34 Ohm
            1x - reserved
        <al>    additive latency:
            00 - disabled (AL=0)
            01 - AL=CL-1;
            10 - AL=CL-2
            11 - reserved
        <dll>   0 - DLL enabled (normal), 1 - DLL disabled
        """ 
348 349
        return concat (( #    ddr3_mr1 = {
              (1,3), # 3'h1,
350
              (0, vrlg.ADDRESS_NUMBER-13), # {ADDRESS_NUMBER-13{1'b0}},
351 352 353 354 355 356 357 358 359 360 361
              (qoff,1),                    # qoff,       # MR1.12 
              (tdqs,1),                    # tdqs,       # MR1.11
              (0,1),                       # 1'b0,       # MR1.10
              (rtt>>2,1),                  # rtt[2],     # MR1.9
              (0,1),                       # 1'b0,       # MR1.8
              (wlev,1),                    # wlev,       # MR1.7 
              (rtt>>1,1),                  # rtt[1],     # MR1.6 
              (ods>>1,1),                  # ods[1],     # MR1.5 
              (al,2),                      # al[1:0],    # MR1.4_3 
              (rtt,1),                     # rtt[0],     # MR1.2 
              (ods,1),                     # ods[0],     # MR1.1 
Andrey Filippov's avatar
Andrey Filippov committed
362
              (dll,1)))[0]                 #dll};       # MR1.0 
363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379
    
    def func_ddr3_mr2(self, # ; function [ADDRESS_NUMBER+2:0] 
                        rtt_wr, # input [1:0] rtt_wr; # Dynamic ODT :
                        #  2'b00 - disabled
                        #  2'b01 - RZQ/4 = 60 Ohm
                        #  2'b10 - RZQ/2 = 120 Ohm
                        #  2'b11 - reserved
                        srt,  # input       srt;    # Self-refresh temperature 0 - normal (0-85C), 1 - extended (<=95C)
                        asr,  # input       asr;    # Auto self-refresh 0 - disabled (manual), 1 - enabled (auto)
                        cwl): # input [2:0] cwl;    # CAS write latency:
                        #  3'b000  5CK (           tCK >= 2.5ns)  
                        #  3'b001  6CK (1.875ns <= tCK < 2.5ns)  
                        #  3'b010  7CK (1.5ns   <= tCK < 1.875ns)  
                        #  3'b011  8CK (1.25ns  <= tCK < 1.5ns)  
                        #  3'b100  9CK (1.071ns <= tCK < 1.25ns)  
                        #  3'b101 10CK (0.938ns <= tCK < 1.071ns)  
                        #  3'b11x reserved
380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397
        """                
        Encode DDR3 MR2 register data
        <rtt_wr>  Dynamic ODT :
            00 - disabled
            01 - RZQ/4 = 60 Ohm
            10 - RZQ/2 = 120 Ohm
            11 - reserved
        <srt>     Self-refresh temperature 0 - normal (0-85C), 1 - extended (<=95C)
        <asr>     Auto self-refresh 0 - disabled (manual), 1 - enabled (auto)
        <cwl>     CAS write latency:
            000  5CK (           tCK >= 2.5ns)  
            001  6CK (1.875ns <= tCK < 2.5ns)  
            010  7CK (1.5ns   <= tCK < 1.875ns)  
            011  8CK (1.25ns  <= tCK < 1.5ns)  
            100  9CK (1.071ns <= tCK < 1.25ns)  
            101 10CK (0.938ns <= tCK < 1.071ns)  
            11x reserved
        """ 
398 399
        return concat ((                  
                (2,3),                       #   3'h2,
400
                (0, vrlg.ADDRESS_NUMBER-11), # {ADDRESS_NUMBER-11{1'b0}},
401 402 403 404 405 406 407 408 409 410 411 412
                (rtt_wr,2),                  # rtt_wr[1:0], # MR2.10_9
                (0,1),                       # 1'b0,        # MR2.8
                (srt,1),                     # srt,         # MR2.7
                (asr,1),                     # asr,         # MR2.6
                (cwl,3),                     # cwl[2:0],    # MR2.5_3
                (0,3)))[0]                   # 3'b0};       # MR2.2_0 

    def func_ddr3_mr3(self,       # function [ADDRESS_NUMBER+2:0]
                      mpr,        # input       mpr;    # MPR mode: 0 - normal, 1 - dataflow from MPR
                      mpr_rf):    # input [1:0] mpr_rf; # MPR read function:
                            #  2'b00: predefined pattern 0101...
                            #  2'b1x, 2'bx1 - reserved
413 414 415 416 417 418 419
        """                
        Encode DDR3 MR3 register data
        <mpr>      MPR mode: 0 - normal, 1 - dataflow from MPR
        <mpr_rf>   MPR read function:
            00: predefined pattern 0101...
            1x, 2'bx1 - reserved
        """ 
420
        return concat((
Andrey Filippov's avatar
Andrey Filippov committed
421
                (3,3),                     # 3'h3,
422
                (0,vrlg.ADDRESS_NUMBER-3), # {ADDRESS_NUMBER-3{1'b0}},
Andrey Filippov's avatar
Andrey Filippov committed
423 424
                (mpr, 1),                  # mpr,          # MR3.2
                (mpr_rf,2)))[0]            # mpr_rf[1:0]}; # MR3.1_0 
425 426 427 428 429 430 431
        
    '''
    x393_tasks_pio_sequences
    '''
    def enable_reset_ps_pio(self, #; // control reset and enable of the PS PIO channel;
                            en,   # input en;
                            rst): #input rst;
432 433 434 435 436 437
        """
        Enable/disable and reset PS PIO channel
        <en>   1 - enable, 0 - disable (only influences request for arbitration, started transactions will finish if disabled)
        <rst>  1 - reset active, 0 - reset off
        """
        
438
        self.x393_axi_tasks.write_contol_register(vrlg.MCNTRL_PS_ADDR + vrlg.MCNTRL_PS_EN_RST,
439 440 441 442 443 444 445
                                   ((0,1)[en]<<1) | #{30'b0,en,
                                   (1,0)[rst])  #~rst});
   
   
    def set_read_block(self, #
                       ba,   # input [ 2:0] ba;
                       ra,   # input [14:0] ra;
446
                       ca,  #input [ 9:0] ca;
447 448
                       num8=64,
                       sel=1, 
449
                       verbose=0):
450 451
        """
        Setup read block sequence at parameter defined address in the sequencer memory
452 453 454 455 456 457
        @ba   3-bit memory bank address
        @ra  15-bit memory row address
        @ca  10-bit memory column address
        @num8 - number of 8-bursts to read (maximal 64, min- 2)
        @sel - 0 - early, 1 - late read command
        @verbose print data being written (default: False)
458
        """
459
        cmd_addr = vrlg.MCONTR_CMD_WR_ADDR + vrlg.READ_BLOCK_OFFSET
460 461 462
# activate
        #                           addr                bank     RCW ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD NOP, B_RST
        data=self.func_encode_cmd(  ra,                  ba,      4,  0,  0,  0,  0,    0,    0,    0,  0,   0,   0,   0)
463
        self.x393_mem.axi_write_single_w(cmd_addr, data, verbose)
464 465 466 467
        cmd_addr += 1
# see if pause is needed . See when buffer read should be started - maybe before WR command
        #                          skip     done        bank         ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD      B_RST
        data=self.func_encode_skip( 1,       0,          0,           0,  0,  0,  0,    0,    0,    0,  0,   0,        0)
468
        self.x393_mem.axi_write_single_w(cmd_addr, data, verbose)
469 470 471 472
        cmd_addr+=1
# first read
# read
        #                          addr                 bank     RCW ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD NOP, B_RST
473
        data=self.func_encode_cmd(ca&0x3ff,              ba,      2,  0,  0, sel, 0,    0,    0,    1,  1,   0,   0,   0)
474
        self.x393_mem.axi_write_single_w(cmd_addr, data, verbose)
475 476 477
        cmd_addr += 1
# nop
        #                          skip     done        bank         ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD      B_RST
478
        data=self.func_encode_skip( 0,       0,          ba,          0,  0, sel, 0,    0,    0,    1,  1,   0,        0)
479
        self.x393_mem.axi_write_single_w(cmd_addr, data, verbose)
480 481
        cmd_addr += 1
#repeat remaining reads             
482
        for i in range(1,num8):
483 484
# read
#                                  addr                 bank     RCW ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD NOP, B_RST
485
            data=self.func_encode_cmd((ca & 0x3ff)+(i<<3),ba,     2,  0,  0, sel, 0,    0,    0,    1,  1,   0,   1,   0)
486
            self.x393_mem.axi_write_single_w(cmd_addr, data, verbose)
487 488 489
            cmd_addr += 1
# nop - all 3 below are the same? - just repeat?
        #                          skip     done        bank         ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD      B_RST
490
        data=self.func_encode_skip(  0,       0,         ba,          0,  0, sel, 0,    0,    0,    1,  0,   0,        0)
491
        self.x393_mem.axi_write_single_w(cmd_addr, data, verbose)
492 493 494
        cmd_addr += 1
# nop
        #                          skip     done        bank         ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD      B_RST
495
        data=self.func_encode_skip(  0,       0,         ba,          0,  0, sel, 0,    0,    0,    1,  0,   0,        0)
496
        self.x393_mem.axi_write_single_w(cmd_addr, data, verbose)
497 498 499
        cmd_addr += 1
# nop
        #                          skip     done        bank         ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD      B_RST
500
        data=self.func_encode_skip(  0,       0,         ba,          0,  0, sel, 0,    0,    0,    1,  0,   0,        0)
501
        self.x393_mem.axi_write_single_w(cmd_addr, data, verbose)
502 503 504 505 506
        cmd_addr += 1
# tRTP = 4*tCK is already satisfied, no skip here
# precharge, end of a page (B_RST)         
        #                          addr                 bank     RCW ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD NOP, B_RST
        data=self.func_encode_cmd(  ra,                  ba,      5,  0,  0,  0,  0,    0,    0,    1,  0,   0,   0,   1)
507
        self.x393_mem.axi_write_single_w(cmd_addr, data, verbose)
508 509 510
        cmd_addr += 1
        #                          skip     done        bank         ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD      B_RST
        data=self.func_encode_skip(  2,       0,         0,           0,  0,  0,  0,    0,    0,    1,  0,   0,        0)
511
        self.x393_mem.axi_write_single_w(cmd_addr, data, verbose)
512 513 514 515
        cmd_addr += 1
# Turn off DCI, set DONE
        #                          skip     done        bank         ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD      B_RST
        data=self.func_encode_skip(  0,       1,         0,           0,  0,  0,  0,    0,    0,    0,  0,   0,        0)
516
        self.x393_mem.axi_write_single_w(cmd_addr, data, verbose)
517 518
        cmd_addr += 1

519
    def set_write_block(self,#):
520 521
                        ba,  # input[2:0]ba;
                        ra,  # input[14:0]ra;
522 523
                        ca,  # input[9:0]ca;
                        num8=64,
524
                        extraTgl=0, #
525
                        sel=1,
526 527
                        verbose=0):

528 529
        """
        Setup write block sequence at parameter defined address in the sequencer memory
530 531 532 533 534 535 536
        @param ba   3-bit memory bank address
        @param ra  15-bit memory row address
        @param ca  10-bit memory column address
        @param num8 - number of 8-bursts (default=64, should be >2)
        @param extraTgl add extra 8-burst of toggling DQS
        @param sel - 0 - early, 1 - late read command
        @param verbose print data being written (default: False)
537
        """
538 539
        if verbose > 0:
            print("===set_write_block ba=0x%x, ra=0x%x, ca=0x%x, num8=%d extraTgl=%d, sel=%d, verbose=%d"%(ba,ra,ca,num8,extraTgl,sel, verbose))
540
        cmd_addr = vrlg.MCONTR_CMD_WR_ADDR + vrlg.WRITE_BLOCK_OFFSET
541 542 543
# activate
        #                          addr                 bank     RCW ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD NOP, B_RST
        data=self.func_encode_cmd( ra,                   ba,      4,  0,  0,  0,  0,    0,    0,    0,  0,   1,   0,   0)
544
        self.x393_mem.axi_write_single_w(cmd_addr, data, verbose)
545 546 547 548
        cmd_addr += 1
# see if pause is needed . See when buffer read should be started - maybe before WR command
        #                          skip     done        bank         ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD      B_RST
        data=self.func_encode_skip( 1,       0,          0,           0,  0,  0,  0,    0,    0,    0,  0,   1,        0) # tRCD - 2 read bufs
549
        self.x393_mem.axi_write_single_w(cmd_addr, data, verbose)
550 551 552 553
        cmd_addr += 1
# first write, 3 rd_buf
# write
        #                          addr                 bank     RCW ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD NOP, B_RST
554
        data=self.func_encode_cmd(ca&0x3ff,              ba,      3,  1,  0, sel, 0,    0,    0,    0,  0,   1,   0,   0) # B_RD moved 1 cycle earlier 
555
        self.x393_mem.axi_write_single_w(cmd_addr, data, verbose)
556 557 558
        cmd_addr += 1
# nop 4-th rd_buf
        #                          skip     done        bank         ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD      B_RST
Andrey Filippov's avatar
Andrey Filippov committed
559 560
#       data=self.func_encode_skip( 0,       0,          ba,          1,  0,  0,  1,    1,    0,    0,  0,   1,        0)
        data=self.func_encode_skip( 0,       0,          ba,          1,  0,  0,  0,    0,    0,    0,  0,   1,        0)
561
        self.x393_mem.axi_write_single_w(cmd_addr, data, verbose)
562 563
        cmd_addr += 1
#repeat remaining writes
564
        for i in range(1,num8-2): # 62) : #(i = 1; i < 62; i = i + 1) begin
565 566
# write
        #                          addr                 bank     RCW ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD NOP, B_RST
567
            data=self.func_encode_cmd((ca&0x3ff)+(i<<3), ba,      3,  1,  0, sel, 1,    1,    1,    0,  0,   1,   1,   0) 
568
            self.x393_mem.axi_write_single_w(cmd_addr, data, verbose)
569 570
            cmd_addr += 1
        #                          addr                 bank     RCW ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD NOP, B_RST
571 572
#        data=self.func_encode_cmd((ca&0x3ff)+(62<<3),    ba,     3,  1,  0, sel, 1,    1,    1,    0,  0,   1,   0,   0) # write w/o nop
        data=self.func_encode_cmd((ca&0x3ff)+((num8-2)<<3), ba,   3,  1,  0, sel, 1,    1,    1,    0,  0,   1,   0,   0) # write w/o nop
573
        self.x393_mem.axi_write_single_w(cmd_addr, data, verbose)
574 575 576
        cmd_addr += 1
#nop
        #                          skip     done        bank         ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD      B_RST
577
        data=self.func_encode_skip( 0,       0,          ba,          1,  0, sel, 1,    1,    1,    0,  0,   0,        0) # nop with buffer read off
578
        self.x393_mem.axi_write_single_w(cmd_addr, data, verbose)
579 580 581 582
        cmd_addr += 1
        
# One last write pair w/o buffer
        #                          addr                 bank     RCW ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD NOP, B_RST
583 584
#        data=self.func_encode_cmd((ca&0x3ff)+(63<<3),    ba,     3,  1,  0, sel, 1,    1,    1,    0,  0,   0,   1,   0) # write with nop
        data=self.func_encode_cmd((ca&0x3ff)+((num8-1)<<3),ba,    3,  1,  0, sel, 1,    1,    1,    0,  0,   0,   1,   0) # write with nop
585
        self.x393_mem.axi_write_single_w(cmd_addr, data, verbose)
586 587 588 589
        cmd_addr += 1
# nop
        #                          skip     done        bank         ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD      B_RST
        data=self.func_encode_skip( 0,       0,          ba,          1,  0,  0,  1,    1,    1,    0,  0,   0,        0)
590
        self.x393_mem.axi_write_single_w(cmd_addr, data, verbose)
591 592 593 594
        cmd_addr += 1
# nop
        #                          skip     done        bank         ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD      B_RST
        data=self.func_encode_skip( 0,       0,          ba,          1,  0,  0,  1,    1,    1,    0,  0,   0,        1) # removed B_RD 1 cycle earlier
595
        self.x393_mem.axi_write_single_w(cmd_addr, data, verbose)
596 597 598
        cmd_addr += 1
# nop
        #                          skip     done        bank         ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD      B_RST
599
        data=self.func_encode_skip( extraTgl,       0,          ba,          sel, 0,  0,  1,    1,    1,    0,  0,   0,        0)
600
        self.x393_mem.axi_write_single_w(cmd_addr, data, verbose)
601 602 603 604
        cmd_addr += 1
# ODT off, it has latency
        #                          skip     done        bank         ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD      B_RST
        data=self.func_encode_skip( 2,       0,          ba,          0,  0,  0,  0,    0,    0,    0,  0,   0,        0)
605
        self.x393_mem.axi_write_single_w(cmd_addr, data, verbose)
606 607 608 609
        cmd_addr += 1
# precharge, ODT off
        #                          addr                 bank     RCW ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD NOP, B_RST
        data=self.func_encode_cmd(  ra,                  ba,      5,  0,  0,  0,  0,    0,    0,    0,  0,   0,   0,   0)
610
        self.x393_mem.axi_write_single_w(cmd_addr, data, verbose)
611 612 613
        cmd_addr += 1
        #                          skip     done        bank         ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD      B_RST
        data=self.func_encode_skip( 2,       0,          ba,          0,  0,  0,  0,    0,    0,    0,  0,   0,        0)
614
        self.x393_mem.axi_write_single_w(cmd_addr, data, verbose)
615 616 617 618
        cmd_addr += 1
# Finalize, set DONE        
        #                          skip     done        bank         ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD      B_RST
        data=self.func_encode_skip( 0,       1,          0,           0,  0,  0,  0,    0,    0,    0,  0,   0,        0);
619
        self.x393_mem.axi_write_single_w(cmd_addr, data, verbose)
620 621 622 623
        cmd_addr += 1

# Set MR3, read nrep*8 words, save to buffer (port0). No ACTIVATE/PRECHARGE are needed/allowed   
    def set_read_pattern (self, 
624 625
                          nrep,  # input integer nrep;
                          sel=1, # 0 - early, 1 - late read command (shift by a SDCLK period) 
626 627
                          verbose=0):
                          
628 629
        """
        Setup read pattern sequence at parameter defined address in the sequencer memory
630
        <nrep>   number of times pattern burst is read
631
        <sel>    0 - early, 1 - late read command (shift by a SDCLK period)
632 633
        <verbose> print data being written (default: False)
            
634 635
        """
        
636
        cmd_addr = vrlg.MCONTR_CMD_WR_ADDR + vrlg.READ_PATTERN_OFFSET
637 638 639 640 641 642 643 644 645
        mr3_norm = self.func_ddr3_mr3(
           0, # 1'h0,     //       mpr;    // MPR mode: 0 - normal, 1 - dataflow from MPR
           0) # 2'h0);    // [1:0] mpr_rf; // MPR read function: 2'b00: predefined pattern 0101...
        mr3_patt = self.func_ddr3_mr3(
           1, # 1'h1,     //       mpr;    // MPR mode: 0 - normal, 1 - dataflow from MPR
           0) # 2'h0);    // [1:0] mpr_rf; // MPR read function: 2'b00: predefined pattern 0101...
# Set pattern mode
        #                           addr                 bank                   RCW ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD NOP, B_RST
        data=self.func_encode_cmd(bits(mr3_patt,(14,0)), bits(mr3_patt,(17,15)), 7,  0,  0,  0,  0,    0,    0,    0,  0,   0,   0,   0)
646
        self.x393_mem.axi_write_single_w(cmd_addr, data, verbose)
647 648
        cmd_addr += 1
        #                          skip      done        bank                       ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD      B_RST
649
        data=self.func_encode_skip( 5,        0,           0,                        0,  0,  0,  0,    0,    0,    0,  0,   0,        0)# tMOD
650
        self.x393_mem.axi_write_single_w(cmd_addr, data, verbose)
651 652 653 654
        cmd_addr += 1
# first read
#@ read
        #                           addr                 bank                   RCW ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD NOP, B_RST
655
        data=self.func_encode_cmd(    0,                   0,                    2,  0,  0, sel, 0,    0,    0,    1,  1,   0,   0,   0)
656
        self.x393_mem.axi_write_single_w(cmd_addr, data, verbose)
657 658 659
        cmd_addr += 1
# nop (combine with previous?)
        #                          skip      done        bank                       ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD      B_RST
660
        data=self.func_encode_skip(   0,       0,          0,                        0,  0, sel, 0,    0,    0,    1,  1,   0,        0)
661
        self.x393_mem.axi_write_single_w(cmd_addr, data, verbose)
662 663 664 665 666
        cmd_addr += 1
#repeat remaining reads
#        for (i = 1; i < nrep; i = i + 1) begin
        for _ in range(1,nrep):
        #                           addr                 bank                   RCW ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD NOP, B_RST
667
            data=self.func_encode_cmd( 0,                  0,                    2,  0,  0, sel, 0,    0,    0,    1,  1,   0,   1,   0)
668
            self.x393_mem.axi_write_single_w(cmd_addr, data, verbose)
669 670 671
            cmd_addr += 1
# nop - all 3 below are the same? - just repeat?
        #                          skip      done        bank                       ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD      B_RST
672
        data=self.func_encode_skip(   0,       0,          0,                        0,  0, sel, 0,    0,    0,    1,  0,   0,        0)
673
        self.x393_mem.axi_write_single_w(cmd_addr, data, verbose)
674 675 676
        cmd_addr += 1
# nop
        #                          skip      done        bank                       ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD      B_RST
677
        data=self.func_encode_skip(   0,       0,          0,                        0,  0, sel, 0,    0,    0,    1,  0,   0,        0)
678
        self.x393_mem.axi_write_single_w(cmd_addr, data, verbose)
679 680 681
        cmd_addr += 1
# nop
        #                          skip      done        bank                       ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD      B_RST
682
        data=self.func_encode_skip(   0,       0,          0,                        0,  0, sel, 0,    0,    0,    1,  0,   0,        0)
683
        self.x393_mem.axi_write_single_w(cmd_addr, data, verbose)
684 685 686
        cmd_addr += 1
# nop, no write buffer - next page
        #                          skip      done        bank                       ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD      B_RST
687
        data=self.func_encode_skip(   0,       0,          0,                        0,  0, sel, 0,    0,    0,    1,  0,   0,        1)
688
        self.x393_mem.axi_write_single_w(cmd_addr, data, verbose)
689 690
        cmd_addr += 1
        #                          skip      done        bank                       ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD      B_RST
691
        data=self.func_encode_skip(   1,       0,          0,                        0,  0, sel, 0,    0,    0,    1,  0,   0,        0)
692
        self.x393_mem.axi_write_single_w(cmd_addr, data, verbose)
693 694 695 696
        cmd_addr += 1
# Turn off read pattern mode
        #                           addr                 bank                   RCW ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD NOP, B_RST
        data=self.func_encode_cmd(bits(mr3_norm,(14,0)), bits(mr3_norm,(17,15)), 7,  0,  0,  0,  0,    0,    0,    1,  0,   0,   0,   0)
697
        self.x393_mem.axi_write_single_w(cmd_addr, data, verbose)
698 699 700 701
        cmd_addr += 1
# tMOD (keep DCI enabled)
        #                          skip      done        bank                       ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD      B_RST
        data=self.func_encode_skip(   5,       0,          0,                        0,  0,  0,  0,    0,    0,    1,  0,   0,        0)
702
        self.x393_mem.axi_write_single_w(cmd_addr, data, verbose)
703 704 705 706
        cmd_addr += 1
# Turn off DCI
        #                          skip      done        bank                       ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD      B_RST
        data=self.func_encode_skip(   0,       0,          0,                        0,  0,  0,  0,    0,    0,    0,  0,   0,        0)
707
        self.x393_mem.axi_write_single_w(cmd_addr, data, verbose)
708 709 710 711
        cmd_addr += 1
# Finalize (set DONE)
        #                          skip      done        bank                       ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD      B_RST
        data=self.func_encode_skip(   0,       1,          0,                        0,  0,  0,  0,    0,    0,    0,  0,   0,        0)
712
        self.x393_mem.axi_write_single_w(cmd_addr, data, verbose)
713 714 715
        cmd_addr += 1

    def set_write_lev(self,
716
                      nrep,  #input[CMD_PAUSE_BITS-1:0]nrep;
717
                      make_bad=False, # do not turn write levelling mode on to test device is not stuck
718
                      verbose=0):
719 720
        """
        Setup write levelling sequence at parameter defined address in the sequencer memory
721 722
        <nrep>  number of times write levelling burst is repeated
        <verbose> print data being written (default: False)
723
        """
724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741
        dqs_low_rpt = 8
        nrep_minus_1 = nrep - 1;
        mr1_norm = self.func_ddr3_mr1(
            0, # 1'h0,     #       qoff; # output enable: 0 - DQ, DQS operate in normal mode, 1 - DQ, DQS are disabled
            0, # 1'h0,     #       tdqs; # termination data strobe (for x8 devices) 0 - disabled, 1 - enabled
            2, # 3'h2,     # [2:0] rtt;  # on-die termination resistance: #  3'b010 - RZQ/2 (120 Ohm)
            0, # 1'h0,     #       wlev; # write leveling
            0, # 2'h0,     #       ods;  # output drive strength: #  2'b00 - RZQ/6 - 40 Ohm
            0, # 2'h0,     # [1:0] al;   # additive latency: 2'b00 - disabled (AL=0)
            0) # 1'b0);    #       dll;  # 0 - DLL enabled (normal), 1 - DLL disabled
        mr1_wlev = self.func_ddr3_mr1(
            0, # 1'h0,     #       qoff; # output enable: 0 - DQ, DQS operate in normal mode, 1 - DQ, DQS are disabled
            0, # 1'h0,     #       tdqs; # termination data strobe (for x8 devices) 0 - disabled, 1 - enabled
            2, # 3'h2,     # [2:0] rtt;  # on-die termination resistance: #  3'b010 - RZQ/2 (120 Ohm)
            1, # 1'h1,     #       wlev; # write leveling
            0, # 2'h0,     #       ods;  # output drive strength: #  2'b00 - RZQ/6 - 40 Ohm
            0, # 2'h0,     # [1:0] al;   # additive latency: 2'b00 - disabled (AL=0)
            0) # 1'b0);    #       dll;  # 0 - DLL enabled (normal), 1 - DLL disabled
742
        cmd_addr = vrlg.MCONTR_CMD_WR_ADDR + vrlg.WRITELEV_OFFSET
743 744
# Enter write leveling mode
        #                           addr                 bank                   RCW ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD NOP, B_RST
745 746 747 748
        if make_bad:
            data=self.func_encode_cmd(bits(mr1_norm,(14,0)),bits(mr1_norm,(17,15)),7,0,  0,  0,  0,    0,    0,    0,  0,   0,   0,   0)
        else:
            data=self.func_encode_cmd(bits(mr1_wlev,(14,0)),bits(mr1_wlev,(17,15)),7,0,  0,  0,  0,    0,    0,    0,  0,   0,   0,   0)
749
        self.x393_mem.axi_write_single_w(cmd_addr, data, verbose)
750 751 752
        cmd_addr += 1
        #                          skip      done        bank                       ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD      B_RST
        data=self.func_encode_skip( 13,       0,          0,                         0,  0,  0,  0,    0,    0,    0,  0,   0,        0) # tWLDQSEN=25tCK
753
        self.x393_mem.axi_write_single_w(cmd_addr, data, verbose)
754 755 756 757
        cmd_addr += 1
# enable DQS output, keep it low (15 more tCK for the total of 40 tCK
        #                          skip      done        bank                       ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD      B_RST
        data=self.func_encode_skip(dqs_low_rpt,0,         0,                         1,  0,  0,  0,    1,    0,    0,  0,   0,        0)
758
        self.x393_mem.axi_write_single_w(cmd_addr, data, verbose)
759 760 761 762
        cmd_addr += 1
# Toggle DQS as needed for write leveling, write to buffer
        #                          skip      done        bank                       ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD      B_RST
        data=self.func_encode_skip(nrep_minus_1,0,        0,                         1,  0,  0,  0,    1,    1,    1,  1,   0,        0)
763
        self.x393_mem.axi_write_single_w(cmd_addr, data, verbose)
764 765 766 767
        cmd_addr += 1
# continue toggling (5 times), but disable writing to buffer (used same wbuf latency as for read) 
        #                          skip      done        bank                       ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD      B_RST
        data=self.func_encode_skip( 4,        0,          0,                         1,  0,  0,  0,    1,    1,    1,  0,   0,        0)
768
        self.x393_mem.axi_write_single_w(cmd_addr, data, verbose)
769 770 771 772
        cmd_addr += 1
        # Keep DCI (but not ODT) active  ODT should be off befor MRS
        #                          skip      done        bank                       ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD      B_RST
        data=self.func_encode_skip( 2,        0,          0,                         0,  0,  0,  0,    0,    0,    1,  0,   0,        0)
773
        self.x393_mem.axi_write_single_w(cmd_addr, data, verbose)
774 775 776 777
        cmd_addr += 1
        # exit write leveling mode, ODT off, DCI off
        #                           addr                 bank                   RCW ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD NOP, B_RST
        data=self.func_encode_cmd(bits(mr1_norm,(14,0)),bits(mr1_norm,(17,15)),  7,  0,  0,  0,  0,    0,    0,    0,  0,   0,   0,   0)
778
        self.x393_mem.axi_write_single_w(cmd_addr, data, verbose)
779 780 781
        cmd_addr += 1
        #                          skip      done        bank                       ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD      B_RST
        data=self.func_encode_skip( 5,        0,         0,                          0,  0,  0,  0,    0,    0,    0,  0,   0,        0) # tMOD
782
        self.x393_mem.axi_write_single_w(cmd_addr, data, verbose)
783 784 785 786
        cmd_addr += 1
        # Finalize. See if DONE can be combined with B_RST, if not - insert earlier
        #                          skip      done        bank                       ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD      B_RST
        data=self.func_encode_skip(  0,       1,           0,                        0,  0,  0,  0,    0,    0,    0,  0,   0,        1) # can DONE be combined with B_RST?
787
        self.x393_mem.axi_write_single_w(cmd_addr, data, verbose)
788 789 790 791 792
        cmd_addr += 1

    def set_refresh(self, #
                t_rfc,   # input[9:0]t_rfc; # =50 for tCK=2.5ns
                t_refi, # input[7:0]t_refi; # 48/97 for normal, 8 - for simulation
793
                en_refresh=0,
794 795
                ra=0, # used only for calibration of the address line output delay
                ba=0,
796
                verbose=0):
797 798 799
        """
        Setup refresh sequence at parameter defined address in the sequencer memory
        <t_rfc>       tRFC =50 for tCK=2.5ns
800
        <t_refi>      tREFI 48/97 for hardware, 16 - for simulation
801
        <en_refresh>  enable refresh immediately 
802
        <verbose> print data being written (default: False)
803
        """
804
        print("**** SET REFRESH: tRFC=%d, tREFI=%d"%(t_rfc,t_refi))
805
        cmd_addr = vrlg.MCONTR_CMD_WR_ADDR + vrlg.REFRESH_OFFSET
806
        #                           addr                 bank                   RCW ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD NOP, B_RST
807
        data=self.func_encode_cmd(   ra,                  ba,                    6,  0,  0,  0,  0,    0,    0,    0,  0,   0,   0,   0)
808
        self.x393_mem.axi_write_single_w(cmd_addr, data, verbose)
809 810 811 812
        cmd_addr += 1
        # =50 tREFI=260 ns before next ACTIVATE or REFRESH, @2.5ns clock, @5ns cycle
        #                          skip      done        bank                       ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD      B_RST
        data=self.func_encode_skip( t_rfc,     0,          0,                        0,  0,  0,  0,    0,    0,    0,  0,   0,        0)
813
        self.x393_mem.axi_write_single_w(cmd_addr, data, verbose)
814 815 816 817
        cmd_addr += 1
# Ready for normal operation
        #                          skip      done        bank                       ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD      B_RST
        data=self.func_encode_skip(  0,       1,           0,                        0,  0,  0,  0,    0,    0,    0,  0,   0,        0)
818
        self.x393_mem.axi_write_single_w(cmd_addr, data, verbose)
819 820
        cmd_addr += 1
#            write_contol_register(DLY_SET,0);
821 822
        self.x393_axi_tasks.write_contol_register(vrlg.MCONTR_TOP_16BIT_ADDR + vrlg.MCONTR_TOP_16BIT_REFRESH_ADDRESS, vrlg.REFRESH_OFFSET)
        self.x393_axi_tasks.write_contol_register(vrlg.MCONTR_TOP_16BIT_ADDR + vrlg.MCONTR_TOP_16BIT_REFRESH_PERIOD, t_refi)
823 824
        # enable refresh - should it be done here?
        if en_refresh:
825
            self.x393_axi_tasks.write_contol_register(vrlg.MCONTR_PHY_0BIT_ADDR +  vrlg.MCONTR_TOP_0BIT_REFRESH_EN + 1, 0)
826 827 828


    def set_mrs(self,       # will also calibrate ZQ
829 830
                reset_dll, # input reset_dll;
                verbose=0):
831
        """
832
        Setup sequence (at paramter-defined address) to write MR0, MR1, MR2 and MR3 mode registers of DDR3 memory
833
        <reset_dll>    reset memory DLL when running this sequence
834
        <verbose> print data being written (default: False)
835
        """
836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861
        mr0 = self.func_ddr3_mr0(
            0,         # 1'h0,      #       pd; # precharge power down 0 - dll off (slow exit), 1 - dll on (fast exit)
            2,         # 3'h2,      # [2:0] wr; # write recovery (encode ceil(tWR/tCK)) # 3'b010:  6
            reset_dll, # reset_dll, #       dll_rst; # 1 - dll reset (self clearing bit)
            4,         # 4'h4,      # [3:0] cl; # CAS latency: # 0100:  6 (time 15ns)
            0,         # 1'h0,      #       bt; # read burst type: 0 sequential (nibble), 1 - interleave
            0)         # 2'h0);       # [1:0] bl; # burst length: # 2'b00 - fixed BL8

        mr1 = self.func_ddr3_mr1(
            0,         # 1'h0,     #       qoff; # output enable: 0 - DQ, DQS operate in normal mode, 1 - DQ, DQS are disabled
            0,         # 1'h0,     #       tdqs; # termination data strobe (for x8 devices) 0 - disabled, 1 - enabled
            2,         # 3'h2,     # [2:0] rtt;  # on-die termination resistance: #  3'b010 - RZQ/2 (120 Ohm)
            0,         # 1'h0,     #       wlev; # write leveling
            0,         # 2'h0,     #       ods;  # output drive strength: #  2'b00 - RZQ/6 - 40 Ohm
            0,         # 2'h0,     # [1:0] al;   # additive latency: 2'b00 - disabled (AL=0)
            0)         # 1'b0);    #       dll;  # 0 - DLL enabled (normal), 1 - DLL disabled

        mr2 = self.func_ddr3_mr2(
            0,         # 2'h0,     # [1:0] rtt_wr; # Dynamic ODT : #  2'b00 - disabled, 2'b01 - RZQ/4 = 60 Ohm, 2'b10 - RZQ/2 = 120 Ohm
            0,         # 1'h0,     #       srt;    # Self-refresh temperature 0 - normal (0-85C), 1 - extended (<=95C)
            0,         # 1'h0,     #       asr;    # Auto self-refresh 0 - disabled (manual), 1 - enabled (auto)
            0)         # 3'h0);    # [2:0] cwl;    # CAS write latency:3'b000  5CK (tCK >= 2.5ns), 3'b001  6CK (1.875ns <= tCK < 2.5ns)

        mr3 = self.func_ddr3_mr3(
            0,         # 1'h0,     #       mpr;    # MPR mode: 0 - normal, 1 - dataflow from MPR
            0)         # 2'h0);    # [1:0] mpr_rf; # MPR read function: 2'b00: predefined pattern 0101...
862
        cmd_addr = vrlg.MCONTR_CMD_WR_ADDR + vrlg.INITIALIZE_OFFSET;
863
        if self.DEBUG_MODE > 1:
Andrey Filippov's avatar
Andrey Filippov committed
864 865 866 867
            print("mr0=0x%05x"%mr0);
            print("mr1=0x%05x"%mr1);
            print("mr2=0x%05x"%mr2);
            print("mr3=0x%05x"%mr3);
868 869
        #                           addr                 bank                   RCW ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD NOP, B_RST
        data=self.func_encode_cmd(bits(mr2,(14,0)),     bits(mr2,(17,15)),       7,  0,  0,  0,  0,    0,    0,    0,  0,   0,   0,   0)
870
        self.x393_mem.axi_write_single_w(cmd_addr, data, verbose)
871 872 873
        cmd_addr += 1
        #                          skip      done        bank                       ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD      B_RST
        data=self.func_encode_skip(  1,       0,           0,                        0,  0,  0,  0,    0,    0,    0,  0,   0,        0);
874
        self.x393_mem.axi_write_single_w(cmd_addr, data, verbose)
875 876 877 878
        cmd_addr += 1
        #                           addr                 bank                   RCW ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD NOP, B_RST
        data=self.func_encode_cmd(bits(mr3,(14,0)),     bits(mr3,(17,15)),       7,  0,  0,  0,  0,    0,    0,    0,  0,   0,   0,   0)
        
879
        self.x393_mem.axi_write_single_w(cmd_addr, data, verbose)
880 881 882
        cmd_addr += 1
        #                          skip      done        bank                       ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD      B_RST
        data=self.func_encode_skip(  0,      0,           0,                         0,  0,  0,  0,    0,    0,    0,  0,   0,        0);
883
        self.x393_mem.axi_write_single_w(cmd_addr, data, verbose)
884 885 886 887
        cmd_addr += 1
        #                           addr                 bank                   RCW ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD NOP, B_RST
        data=self.func_encode_cmd(bits(mr1,(14,0)),     bits(mr1,(17,15)),       7,  0,  0,  1,  0,    0,    0,    0,  0,   0,   0,   0) # SEL==1 - just testing?
        
888
        self.x393_mem.axi_write_single_w(cmd_addr, data, verbose)
889 890 891
        cmd_addr += 1
        #                          skip      done        bank                       ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD      B_RST
        data=self.func_encode_skip(  2,       0,          0,                         0,  0,  0,  0,    0,    0,    0,  0,   0,        0);
892
        self.x393_mem.axi_write_single_w(cmd_addr, data, verbose)
893 894 895
        cmd_addr += 1
        #                           addr                 bank                   RCW ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD NOP, B_RST
        data=self.func_encode_cmd(bits(mr0,(14,0)),     bits(mr0,(17,15)),       7,  0,  0,  0,  0,    0,    0,    0,  0,   0,   0,   0)
896
        self.x393_mem.axi_write_single_w(cmd_addr, data, verbose)
897 898 899
        cmd_addr += 1
        #                          skip      done        bank                       ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD      B_RST
        data=self.func_encode_skip(  5,       0,          0,                         0,  0,  0,  0,    0,    0,    0,  0,   0,        0);
900
        self.x393_mem.axi_write_single_w(cmd_addr, data, verbose)
901 902 903 904
        cmd_addr += 1
        # encode ZQCL:
        #                           addr                 bank                   RCW ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD NOP, B_RST
        data=self.func_encode_cmd( 0x400,                 0,                     1,  0,  0,  0,  0,    0,    0,    0,  0,   0,   0,   0);
905
        self.x393_mem.axi_write_single_w(cmd_addr, data, verbose)
906 907 908 909
        cmd_addr += 1
        # 512 clock cycles after ZQCL
        #                          skip      done        bank                       ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD      B_RST
        data=self.func_encode_skip( 256,      0,          0,                         0,  0,  0,  0,    0,    0,    0,  0,   0,        0);
910
        self.x393_mem.axi_write_single_w(cmd_addr, data, verbose)
911 912 913 914
        cmd_addr += 1
        # sequence done bit, skip length is ignored
        #                          skip      done        bank                       ODT CKE SEL DQEN DQSEN DQSTGL DCI B_WR B_RD      B_RST
        data=self.func_encode_skip( 10,       1,          0,                         0,  0,  0,  0,    0,    0,    0,  0,   0,        0);
915
        self.x393_mem.axi_write_single_w(cmd_addr, data, verbose)
916 917
        cmd_addr += 1

918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955
    def set_all_sequences(self, quiet=1):
        """
        Set all sequences:  MRS, REFRESH, WRITE LEVELLING, READ PATTERN, WRITE BLOCK, READ BLOCK 
        """
        if quiet < 3 :
            print("SET MRS")    
        self.set_mrs(1) # reset DLL
        if quiet < 3 :
            print("SET REFRESH")    
        self.set_refresh(
                                            vrlg.T_RFC, # input [ 9:0] t_rfc; # =50 for tCK=2.5ns
                                            vrlg.T_REFI) #input [ 7:0] t_refi; # 48/97 for normal, 16 - for simulation
        if quiet < 3:
            print("SET WRITE LEVELING")    
        self.set_write_lev(16) # write leveling, 16 times   (full buffer - 128) 
        if quiet < 3:
            print("SET READ PATTERNt")    
        self.set_read_pattern(8) # 8x2*64 bits, 32x32 bits to read
        if quiet < 3:
            print("SET WRITE BLOCK")    
        self.set_write_block(
                                                5,        # 3'h5,     # bank
                                                0x1234,   # 15'h1234, # row address
                                                0x100     # 10'h100   # column address
        )
           
        if quiet < 3:
            print("SET READ BLOCK");    
        self.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



956 957 958 959 960 961
    def read_pattern(self,
                     num,
                     show_rslt,
                     wait_complete=1): # Wait for operation to complete
        """
        Read pattern 
962 963 964 965
        @param num           number of 32-bit words to read
        @param show_rslt  print buffer data read 1 - column, 16 - as 16-bit (memory words), 32 - as 32-bit (data words)
        @param wait_complete wait read pattern operation to complete (0 - may initiate multiple PS PIO operations)
        @return list of the read data
966 967
        """

968
        self.schedule_ps_pio ( # schedule software-control memory operation (may need to check FIFO status first)
969
                        vrlg.READ_PATTERN_OFFSET,   # input [9:0] seq_addr; # sequence start address
970 971 972 973
                        2,                          # input [1:0] page;     # buffer page number
                        0,                          # input       urgent;   # high priority request (only for competion 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
974
        self.wait_ps_pio_done(vrlg.DEFAULT_STATUS_MODE,1) # wait previous memory transaction finished before changing delays (effective immediately)
975 976 977
        return self.x393_mcntrl_buffers.read_block_buf_chn (0, 2, num, show_rslt )    # chn=0, page=2, number of 32-bit words=num, show_rslt

    def read_block(self,
978 979 980
                   num,
                   show_rslt,
                   wait_complete=1): # Wait for operation to complete
981 982
        """
        Read block in PS PIO mode 
983 984 985 986
        @param num      number of 32-bit words to read
        @param show_rslt          print buffer data read 1 - column, 16 - as 16-bit (memory words), 32 - as 32-bit (data words)
        @param wait_complete wait read pattern operation to complete (0 - may initiate multiple PS PIO operations)
        @return list of the read data
987 988
        """
    
989
        self.schedule_ps_pio ( # schedule software-control memory operation (may need to check FIFO status first)
990
                        vrlg.READ_BLOCK_OFFSET,   # input [9:0] seq_addr; # sequence start address
991 992 993 994
                        3,                     # input [1:0] page;     # buffer page number
                        0,                     # input       urgent;   # high priority request (only for competion with other channels, will 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
995
        self.wait_ps_pio_done(vrlg.DEFAULT_STATUS_MODE,1); # wait previous memory transaction finished before changing delays (effective immediately)
996 997 998
        return self.x393_mcntrl_buffers.read_block_buf_chn (0, 3, num, show_rslt ) # chn=0, page=3, number of 32-bit words=num, show_rslt

    def write_block(self,
999 1000
                    page=0,
                    wait_complete=1): # Wait for operation to complete
1001 1002
        """
        Write block in PS PIO mode 
1003 1004
        @param page buffer page to use
        @param wait_complete wait write block operation to complete (0 - may initiate multiple PS PIO operations)
1005 1006
        """
#    write_block_buf_chn; # fill block memory - already set in set_up task
1007
        self.schedule_ps_pio ( # schedule software-control memory operation (may need to check FIFO status first)
1008 1009 1010 1011 1012
                        vrlg.WRITE_BLOCK_OFFSET, # input [9:0] seq_addr; # sequence start address
                        page,                    # input [1:0] page;     # buffer page number
                        0,                       # input       urgent;   # high priority request (only for competion with other channels, will not pass in this FIFO)
                        1,                       # input       chn;      # channel buffer to use: 0 - memory read, 1 - memory write
                        wait_complete)           # `PS_PIO_WAIT_COMPLETE )#  wait_complete; # Do not request a newer transaction from the scheduler until previous memory transaction is finished
1013
# temporary - for debugging:
1014
#        self.wait_ps_pio_done(vrlg.DEFAULT_STATUS_MODE,1) # wait previous memory transaction finished before changing delays (effective immediately)
1015

1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120
    def write_block_inc(self,
                        num8=64, # max 512 16-bit words
                        startValue=0,
                        ca=0,
                        ra=0,
                        ba=0,
                        extraTgl=0, #
                        sel=1,
                        quiet=1):       
        """
        Program sequencer, fill buffer with incremented 16-bit wors (startValue, startValue+1...startValue+nrep*8-1)
        and write buffer to memory 
        @param num8  number of 8-bursts (default=64, should be >2)
        @param startValue - value of the first word to write
        @param ca  10-bit memory column address
        @param ra  15-bit memory row address
        @param ba   3-bit memory bank address
        @param extraTgl add extra 8-burst of toggling DQS
        @param sel  0 - early, 1 - late read command
        @param quiet reduce output
        """
        self.set_write_block(ba=ba,  # input[2:0]ba;
                             ra=ra,  # input[14:0]ra;
                             ca=ca,  # input[9:0]ca;
                             num8=num8,
                             extraTgl=extraTgl, #
                             sel=sel,
                             verbose=(0,1)[quiet < 2])
        wdata16=[startValue+i for i in range(num8*8)]
        wdata32=convert_mem16_to_w32(wdata16)
        self.x393_mcntrl_buffers.write_block_buf_chn(0,0,wdata32,quiet) # fill block memory (channel, page, number)
        self.write_block()

    def set_and_read(self,
                     show_rslt=16,
                     num8=64, # max 512 16-bit words
                     ca=0,
                     ra=0,
                     ba=0,
                     sel=1,
                     quiet=1):       
        """
        Program sequencer, read block from memory and optionally print it
        @param show_rslt: 0 - silent, 1 - as column, 16 - as 16-bit memory words, 32 - as 32-bit (system) words
        @param num8  number of 8-bursts (default=64, should be >2)
        @param ca  10-bit memory column address
        @param ra  15-bit memory row address
        @param ba   3-bit memory bank address
        @param sel  0 - early, 1 - late read command
        @param quiet reduce output
        @return read data as 32-bit words
        """
        self.set_read_block(ba=ba,  # input[2:0]ba;
                            ra=ra,  # input[14:0]ra;
                            ca=ca,  # input[9:0]ca;
                            num8=num8,
                            sel=sel,
                            verbose=(0,1)[quiet < 2])
        return  self.read_block(num= num8*4,
                                show_rslt=show_rslt,
                                wait_complete=1) # Wait for operation to complete

    def set_and_read_inc(self,
                         num8=64, # max 512 16-bit words
                         ca=0,
                         ra=0,
                         ba=0,
                         sel=1,
                         quiet=1):       
        """
        Program sequencer, read block from memory,optionally print it
        Epecting incremental 16-bit data block, calculate number of leading and trailing
        non-consecutive words and return them as a tuple
        @param num8  number of 8-bursts (default=64, should be >2)
        @param ca  10-bit memory column address
        @param ra  15-bit memory row address
        @param ba   3-bit memory bank address
        @param sel  0 - early, 1 - late read command
        @param quiet reduce output
        @return read data as 32-bit words
        """
        data32=self.set_and_read(
                     show_rslt=(0,16)[quiet<2],
                     num8=num8, # max 512 16-bit words
                     ca=ca,
                     ra=ra,
                     ba=ba,
                     sel=sel,
                     quiet=quiet+1)
        data16=convert_w32_to_mem16(data32)
        mid_index=len(data16)//2
        data0= data16[mid_index]-mid_index
        for i in range(mid_index-1,-1,-1):
            if data16[i] != data0 + i:
                first_bad=i+1
                break
        else:
            first_bad= 0
            
        for i in range(mid_index+1,len(data16)):
            if data16[i] != data0 + i:
                last_bad=len(data16)-i
                break
        else:
            last_bad= 0
1121
        rslt=(first_bad, last_bad, data16[mid_index],mid_index)
1122
        if quiet < 3:
1123 1124
            print ("non_consecutive leading/trailing: %d /%d, middle data=0x%x, index=0x%x"%rslt)    
        return rslt
1125 1126 1127
                 
                 

1128 1129 1130

    def write_levelling(self,
                        wait_complete=1, # Wait for operation to complete
1131
                        nburst=16,
1132 1133 1134
                        quiet=1):       
        """
        Read data in write levelling mode 
1135 1136 1137 1138
        @param wait_complete wait write levelling operation to complete (0 - may initiate multiple PS PIO operations)
        @param nburst  number of 8-bursts written (should match sequence!) 
        @param quiet    reduce output
        @eturn a pair of ratios for getting "1" for 2 lanes and problem marker (should be 0)
1139
        """
1140
        numBufWords=2*nburst # twice nrep in set_write_lev
1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170
        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
    
1171 1172
    def read_levelling(self,
                       nrep,
1173
                       sel=1, # 0 - early, 1 - late read command (shift by a SDCLK period), -1 - use current sequence
1174 1175 1176 1177
                       quiet=1):
        """
        Read and process data in 'read patter' mode
        refresh may be off, delays: cmda_edelay, dq_idelay, dqs_idelauy should be set
1178 1179 1180
        @param nrep   number of times pattern burst is read (8-bursts), actually will be read nrep+3, nut the first/last will be discarded
        @param sel    0 - early, 1 - late read command (shift by a SDCLK period) -1 - use pre-programmed sequence,
                     -2 - use (pre-programmed) read_block sequence
1181 1182 1183
        """
        if sel>=0:
            self.set_read_pattern(nrep+3,sel) # do not use first/last pair of the 32 bit words
1184 1185 1186 1187 1188 1189 1190 1191
        if sel == -2:
            buf= self.read_block((4*(nrep+1)+2),     # num,
                                   (0,1)[quiet<1],     # show_rslt,
                                   1) # Wait for operation to complete
        else:
            buf= self.read_pattern((4*(nrep+1)+2),     # num,
                                   (0,1)[quiet<1],     # show_rslt,
                                   1) # Wait for operation to complete
1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222
        buf= buf[4:] # discard first 4*32-bit words
        if quiet <1:
            hbuf=[]
            for dd in buf:
                hbuf.append(hex(dd))
            print(hbuf)
            # with "good" data each word in buf should be 0xff00ff00
        for d in buf:
            if d !=0xffffffff:
                break
        else: # Maybe it is not needed with correct cmda_odelay ?
            if quiet<3:
                print ("Got a block of bad data during read pattern") 
            return None
        data=[0]*32 # for each bit - even, then for all - odd
        for w in range (4 * nrep):
            lane=w%2
            for wb in range(32):
                g=(wb/8)%2
                b=wb%8+lane*8+16*g
                if (buf[w+2] & (1<<wb) != 0):
                    data[b]+=1
        scale=1.0/(4*nrep)
        for i in range(32):
            data[i]*=scale
        if quiet < 2:
            for i in range(32):
                print("%.2f"%data[i],end=" ")
            print()
        return data

1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236
    def manual_refresh(self,
                     wait_complete=1): # Wait for operation to complete
        """
        Run refresh cycle 
        <wait_complete> wait read pattern operation to complete (0 - may initiate multiple PS PIO operations)
        """

        self.schedule_ps_pio ( # schedule software-control memory operation (may need to check FIFO status first)
                        vrlg.REFRESH_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, 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)
1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255


    def init_ddr3(self,
                  refresh=1,
                  wait_complete=True,
                  quiet=1):

        """
        Enable address/command pins, remove SDRST, enable CKE,
        Setup PS PIO
        Set DDR3 MR0..MR3 registers
        Optionally enable refresh
        @param refresh - enable refresh
        @param wait_complete  Do not request a new transaction from the scheduler until previous memory transaction is finished
        @param quiet reduce output
        """
        self.restart_ddr3(wait_complete,quiet)
        self.x393_axi_tasks.enable_refresh(refresh)

1256
    
1257 1258 1259 1260 1261 1262 1263
    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
1264 1265
        @param wait_complete  Do not request a new transaction from the scheduler until previous memory transaction is finished
        @param quiet reduce output
1266 1267 1268 1269
        """
# enable output for address/commands to DDR chip    
        self.x393_axi_tasks.enable_cmda(1)
        self.x393_axi_tasks.activate_sdrst(1) # reset DDR3
1270
        sleep(0.001)
1271 1272
# remove reset from DDR3 chip    
        self.x393_axi_tasks.activate_sdrst(0) # was enabled at system reset
1273
        sleep(0.001) # actually 500 usec required
1274 1275
        self.x393_axi_tasks.enable_cke(1);
        
1276
        self.x393_axi_tasks.enable_memcntrl_channels(0x1)      # only channel 0 and 1 are enabled
1277
        self.x393_axi_tasks.configure_channel_priority(0,0)    # lowest priority channel 0
1278
#        self.x393_axi_tasks.configure_channel_priority(1,0)    # lowest priority channel 1
1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290
        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 
1291 1292 1293 1294



    def task_set_up(self,
1295
                    dqs_pattern=None,
1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308
                    quiet = 1):
        """
        Initial setup of the memory controller, including:
            disable (and reset) memory controller
            enable memory controller
            setup status generation in all modules
            tristate patterns
            DQS/DQM patterns
            all sequences
            channel 0 buffer data
            I/O delays
            clock phase
            write buffer latency
1309
        @param dqs_pattern None - use Verilog parameter, other values 0xaa or 0x55 - DQS output value per 1/2 SDCLK period
1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320
        Returns 1 if phase was set, 0 if it failed         
        """
#reset memory controller
        self.x393_axi_tasks.enable_memcntrl(0)
#enable memory controller
        self.x393_axi_tasks.enable_memcntrl(1)
#program status for all used modules to refresh at any bit change        
        self.x393_axi_tasks.program_status_all(3, 0)
# set dq /dqs tristate on/off patterns
        self.x393_mcntrl_timing.axi_set_tristate_patterns()
# set patterns for DM (always 0) and DQS - always the same (may try different for write lev.)
1321 1322 1323
        self.x393_mcntrl_timing.axi_set_dqs_dqm_patterns(dqs_patt=dqs_pattern, # use default
                                                         dqm_patt=None, # use default
                                                         quiet=1)
1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342
# prepare all sequences
        self.set_all_sequences(quiet)
# prepare write buffer    
        self.x393_mcntrl_buffers.write_block_buf_chn(0,0,256,quiet); # fill block memory (channel, page, number)
# set all 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()
# set clock phase relative to DDR clk
#phase already set in axi_set_delays
#        print("Debugging: sleeping for 1 second")
#        sleep(1)
#        phaseOK=self.x393_mcntrl_timing.axi_set_phase(vrlg.DLY_PHASE,wait_phase_en=True); # wait for phase set
#        if not phaseOK:
#            print("Failed to set clock phase")
#            return 0
# read and print status (optional)
        self.x393_mcntrl_timing.axi_set_wbuf_delay(vrlg.WBUF_DLY_DFLT)
        self.x393_axi_tasks.read_all_status()
        return 1