x393_mcntrl_membridge.py 19.6 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 34 35 36 37 38
from __future__ import print_function
'''
# Copyright (C) 2015, Elphel.inc.
# Class to measure and adjust I/O delays  
# 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/>.
Created on May 2, 2015

@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 vrlg
#import x393_utils
import x393_mem
import x393_axi_control_status
import x393_pio_sequences
import x393_mcntrl_timing
import x393_mcntrl_buffers 
39
#import verilog_utils 
40
import x393_mcntrl
41 42
#MEM_PATH='/sys/devices/elphel393-mem.2/'
MEM_PATH='/sys/devices/soc0/elphel393-mem@0/'
Andrey Filippov's avatar
Andrey Filippov committed
43
BUFFER_ADDRESS_NAME='buffer_address'
44 45 46
BUFFER_PAGES_NAME='buffer_pages'
BUFFER_ADDRESS=None
BUFFER_LEN=None
47 48 49 50

#BUFFER_ADDRESS=0x27900000
#BUFFER_LEN=    0x6400000

51 52
PAGE_SIZE=4096
AFI_BASE_ADDR= 0xf8008000
53

54 55 56 57 58 59 60 61 62 63
'''
root@elphel393:/sys/devices/elphel393-mem.2# cat buffer_address 
0x27900000
root@elphel393:/sys/devices/elphel393-mem.2# cat buffer_pages
25600
BUFFER_ADDRESS= 663748608
BUFFER_LEN= 104857600
BUFFER_ADDRESS=0x27900000
BUFFER_LEN=0x6400000

64
'''
65 66 67 68 69 70 71 72
'''
def func_encode_mode_scanline(extra_pages,  # input [1:0] extra_pages; # number of extra pages that need to stay (not to be overwritten) in the buffer
                                            # can be used for overlapping tile read access
                              write_mem,    # input       write_mem;   # write to memory mode (0 - read from memory)
                              enable,       # input       enable;      # enable requests from this channel ( 0 will let current to finish, but not raise want/need)
                              chn_reset):   # input       chn_reset;       # immediately reset all the internal circuitry
    """
    Combines arguments to create a 5-bit encoded data for scanline mode memory R/W
73
    @param extra_pages  2-bit number of extra pages that need to stay (not to be overwritten) in the buffer
74
                    This argument can be used for  read access with horizontal overlapping tiles
75 76 77
    @param write_mem,    write to memory mode (0 - read from memory)
    @param enable,       enable requests from this channel ( 0 will let current to finish, but not raise want/need)
    @param chn_reset):   immediately reset all the internal circuitry
78 79
    
    """
80
    return verilog_utils.concat (((extra_pages,     2), # extra_pages,
81 82
                                 ((0,1)[write_mem],1), # write_mem,
                                 ((0,1)[enable],   1), #enable,
83
                                 ((1,0)[chn_reset],1)))[0] # ~chn_reset};
84
'''
85 86 87 88 89 90 91 92 93 94 95 96
class X393McntrlMembridge(object):
    DRY_MODE= True # True
    DEBUG_MODE=1
    x393_mem=None
    x393_axi_tasks=None #x393X393AxiControlStatus
    x393_pio_sequences=None
    x393_mcntrl_timing=None
    x393_mcntrl_buffers=None
    x393_utils=None
    verbose=1
    adjustment_state={}
    def __init__(self, debug_mode=1,dry_mode=True): #, saveFileName=None):
97
        global BUFFER_ADDRESS, BUFFER_LEN
98 99 100 101 102 103 104
        self.DEBUG_MODE=  debug_mode
        self.DRY_MODE=    dry_mode
        self.x393_mem=            x393_mem.X393Mem(debug_mode,dry_mode)
        self.x393_axi_tasks=      x393_axi_control_status.X393AxiControlStatus(debug_mode,dry_mode)
        self.x393_pio_sequences=  x393_pio_sequences.X393PIOSequences(debug_mode,dry_mode)
        self.x393_mcntrl_timing=  x393_mcntrl_timing.X393McntrlTiming(debug_mode,dry_mode)
        self.x393_mcntrl_buffers= x393_mcntrl_buffers.X393McntrlBuffers(debug_mode,dry_mode)
105
        
106 107 108 109 110 111
#        self.x393_utils=          x393_utils.X393Utils(debug_mode,dry_mode, saveFileName) # should not overwrite save file path
        try:
            self.verbose=vrlg.VERBOSE
        except:
            pass
        if dry_mode:
112 113
            BUFFER_ADDRESS=0x25500000
            BUFFER_LEN=    0x19000000
114 115 116
            print ("Running in simulated mode, using hard-coded addresses:")
        else:
            try:
Andrey Filippov's avatar
Andrey Filippov committed
117
                with open(MEM_PATH+BUFFER_ADDRESS_NAME) as sysfile:
118 119 120 121
                    BUFFER_ADDRESS=int(sysfile.read(),0)
                with open(MEM_PATH+BUFFER_PAGES_NAME) as sysfile:
                    BUFFER_LEN=PAGE_SIZE*int(sysfile.read(),0)
            except:
122
                print("Failed to get reserved physical memory range")
123 124 125 126 127
                print('BUFFER_ADDRESS=',BUFFER_ADDRESS)    
                print('BUFFER_LEN=',BUFFER_LEN)    
                return
        print('BUFFER_ADDRESS=0x%x'%(BUFFER_ADDRESS))    
        print('BUFFER_LEN=0x%x'%(BUFFER_LEN))
128
        
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
    def afi_write_reg(self,
                     port_num, # input   [1:0] port_num;
                     rel_baddr, # input integer rel_baddr; # relative byte address
                     data, # input  [31:0] data
                     quiet=1): #input  verbose;
        '''
        Write data to AXI_HP (AFI) register
        @param port - AXI_HP port number (0..3)
        @param rel_baddr relative register byte address (0, 4, 8, 0xc, ...)
        @param data data to write to the AFI_nn register
        @param quiet - reduce output (>=1 - silent)
        '''
        self.x393_mem.write_mem(AFI_BASE_ADDR+ (port_num << 12) + (rel_baddr & 0xfffffffc),
                                data & 0xffffffff,
                                quiet)
    def afi_read_reg(self,
145 146 147
                     port_num,       # input   [1:0] port_num;
                     rel_baddr=None, # input integer rel_baddr; # relative byte address
                     quiet=1):       #input  verbose;
148 149 150 151 152 153 154
        '''
        Read data from the AXI_HP (AFI) register
        @param port - AXI_HP port number (0..3)
        @param rel_baddr relative register byte address (0, 4, 8, 0xc, ...)
        @param quiet - reduce output (>=1 - silent)
        @return register data
        '''
155 156 157 158 159 160 161
        
        if rel_baddr is None:
            rslt=[]
            for baddr in (0,4,8,0xc,0x10,0x14,0x18,0x1c,0x20,0x24):
                rslt.append(self.afi_read_reg(port_num,baddr,quiet-1))
            return rslt    
                
162 163 164 165 166 167 168
        return self.x393_mem.read_mem(AFI_BASE_ADDR+ (port_num << 12) + (rel_baddr & 0xfffffffc),
                                quiet)

    def afi_setup (self,
                   port_num,
                   quiet=1):
        '''
169
        Write default parameters to AFI port registers
170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
        @param port_num - AXI_HP port number (0..3)
        @param quiet - reduce output (>=1 - silent)
        '''
        self.afi_write_reg(port_num, 0x0,      0) # AFI_RDCHAN_CTRL
        self.afi_write_reg(port_num, 0x04,   0x7) # AFI_RDCHAN_ISSUINGCAP
        self.afi_write_reg(port_num, 0x08,     0) # AFI_RDQOS
        #self.afi_write_reg(port_num,0x0c,     0) # AFI_RDDATAFIFO_LEVEL
        #self.afi_write_reg(port_num,0x10,     0) # AFI_RDDEBUG
        self.afi_write_reg(port_num, 0x14, 0xf00) # AFI_WRCHAN_CTRL
        self.afi_write_reg(port_num, 0x18,   0x7) # AFI_WRCHAN_ISSUINGCAP
        self.afi_write_reg(port_num, 0x1c,     0) # AFI_WRQOS
        #self.afi_write_reg(port_num,0x20,     0) # AFI_WRDATAFIFO_LEVEL
        #self.afi_write_reg(port_num,0x24,     0) # AFI_WRDEBUG

    def membridge_setup (self,
                         len64,                         # input [28:0] len64;    # number of 64-bit words to transfer
                         width64,                       # input [28:0] width64;  # frame width in 64-bit words
187
                         start64,                       # input [28:0] start64;  # relative start address of the transfer (set to 0 when writing lo_addr64)
188 189
                         lo_addr64 =       None,        # input [28:0] lo_addr64; # low address of the system memory range, in 64-bit words 
                         size64 =          None,        # input [28:0] size64;    # size of the system memory range in 64-bit words
190
#                         cache = 0x3,
191 192 193 194 195 196 197 198 199 200
                         quiet=1):
        '''
        Set up membridge parameters for data transfer
        @param len64   number of 64-bit words to transfer
        @param width64 frame width in 64-bit words
        @param start64 relative start address of the transfer (normally 0)
        @param lo_addr64 low address of the system memory range, in 64-bit words 
        @param size64  size of the system memory range in 64-bit words
        @quiet - reduce output (>=1 - silent)
        '''
201 202 203 204 205
        if lo_addr64 is None:
            lo_addr64 =         BUFFER_ADDRESS//8        # input [28:0] lo_addr64;        # low address of the system memory range, in 64-bit words 
        if size64 is None:
            size64 =            BUFFER_LEN//8            # input [28:0] size64;           # size of the system memory range in 64-bit words
        
206
        if quiet <2:
207
            print("membridge_setup(0x%08x,0x%08x,0x%08x,0x%08x,0x%08x,%d)"%(len64, width64, start64, lo_addr64, size64, quiet))
208 209 210 211 212
        self.x393_axi_tasks.write_control_register(vrlg.MEMBRIDGE_ADDR + vrlg.MEMBRIDGE_LO_ADDR64,  lo_addr64);    
        self.x393_axi_tasks.write_control_register(vrlg.MEMBRIDGE_ADDR + vrlg.MEMBRIDGE_SIZE64,     size64);    
        self.x393_axi_tasks.write_control_register(vrlg.MEMBRIDGE_ADDR + vrlg.MEMBRIDGE_START64,    start64);    
        self.x393_axi_tasks.write_control_register(vrlg.MEMBRIDGE_ADDR + vrlg.MEMBRIDGE_LEN64,      len64);    
        self.x393_axi_tasks.write_control_register(vrlg.MEMBRIDGE_ADDR + vrlg.MEMBRIDGE_WIDTH64,    width64);    
213
#        self.x393_axi_tasks.write_control_register(vrlg.MEMBRIDGE_ADDR + vrlg.MEMBRIDGE_MODE,       cache);    
214 215 216 217 218 219 220 221 222

    def membridge_start(self,
                        cont=False,
                        quiet=1):
        '''
        Set up membridge parameters for data transfer
        @param cont - continue with the current system memory pointer, False - start with lo_addr64+start64
        @quiet reduce output (>=1 - silent)
        '''
223 224
        self.x393_axi_tasks.write_control_register(vrlg.MEMBRIDGE_ADDR + vrlg.MEMBRIDGE_CTRL,  (0x3,0x7)[cont]);    
#        write_control_register(MEMBRIDGE_ADDR + MEMBRIDGE_CTRL,         {29'b0,continue,2'b11});    
225 226 227 228 229 230 231 232 233

    def membridge_en(self,
                     en=True,
                     quiet=1):
        '''
        Enable/disable AXI transfers, when it is running. When stopped - reset "Done"
        @param en True - enable, False - disable AXI transfers (reset "Done" if AFI is idle
        @quiet reduce output (>=1 - silent)
        '''
234 235
        self.x393_axi_tasks.write_control_register(vrlg.MEMBRIDGE_ADDR + vrlg.MEMBRIDGE_CTRL,  (0,1)[en]);    
#       write_control_register(MEMBRIDGE_ADDR + MEMBRIDGE_CTRL,         {31'b0,en});
236 237

    def membridge_rw (self,
238 239 240 241 242 243 244 245 246 247 248 249
                      write_ddr3,                                   # input        write_ddr3;
#                      extra_pages,                                 # input  [1:0] extra_pages;
                      frame_start_addr =  None,                     # input [21:0] frame_start_addr;
                      window_full_width = None,                     # input [15:0] window_full_width;# 13 bit - in 8*16=128 bit bursts
                      window_width =      None,                     # input [15:0] window_width;     # 13 bit - in 8*16=128 bit bursts
                      window_height =     None,                     # input [15:0] window_height;    # 16 bit (only 14 are used here)
                      window_left =       None,                     # input [15:0] window_left;
                      window_top =        None,                     # input [15:0] window_top;
                      start64 =           0,                        # input [28:0] start64;          # relative start address of the transfer (set to 0 when writing lo_addr64)
                      lo_addr64 =         None,                     # input [28:0] lo_addr64;        # low address of the system memory range, in 64-bit words 
                      size64 =            None,                     # input [28:0] size64;           # size of the system memory range in 64-bit words
                      cont =              False,                    # input        continue;         # 0 start from start64, 1 - continue from where it was
250
#                      cache =             0x3,
251
                      wait_ready =        False,
252 253 254 255 256 257 258 259 260 261 262 263 264 265
                      quiet=1):
        '''
        Set up and run data transfer between the system and videobuffer memory
        @param write_ddr3 True: from system memory to ddr3, False - from ddr3 to system memory
        @param frame_start_addr [21:0] Frame start address in video buffer  RA=80, CA=0, BA=0 22-bit frame start address (3 CA LSBs==0. BA==0)
        @param window_full_width  padded frame width in 8-word (16 byte) bursts - increment to the next line (after bank), currently 13 bits
        @param window_width window width in 16-byte bursts to be transferred, currently 13 bits (0 - maximal width 0f 2<<13)
        @param window_height window height to be transferred, 14 bits
        @param window_left window to be transferred left margin (relative to frame) in 16-byte bursts (13 bits)
        @param window_top window to be transferred top margin (relative to frame) 16-bit
        @param start64 start of transfer address in system memory, relative to the start of region (in 8-bytes)
        @param lo_addr64 start of the system memory buffer, in 8-bytes (byte_address >>3), 29 bits 
        @param size64 size of the transfer buffer in the system memory, in 8-bytes. Transfers will roll over to lo_addr64. 29 bits.
        @param cont True: continue from  the same address in the system memory, where the previous transfer stopped. False - start from lo_addr64+start64
266
        @param wait_ready poll status to see if the command finished
267 268
        @param quiet Reduce output
        '''
269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285
        if frame_start_addr is None:
            frame_start_addr =  vrlg.FRAME_START_ADDRESS # input [21:0] frame_start_addr;
        if window_full_width is None:
            window_full_width = vrlg.FRAME_FULL_WIDTH    # input [15:0] window_full_width;# 13 bit - in 8*16=128 bit bursts
        if window_width is None:
            window_width =      vrlg.WINDOW_WIDTH        # input [15:0] window_width;     # 13 bit - in 8*16=128 bit bursts
        if window_height is None:
            window_height =     vrlg.WINDOW_HEIGHT       # input [15:0] window_height;    # 16 bit (only 14 are used here)
        if window_left is None:
            window_left =       vrlg.WINDOW_X0           # input [15:0] window_left;
        if window_top is None:
            window_top =        vrlg.WINDOW_Y0           # input [15:0] window_top;
        if lo_addr64 is None:
            lo_addr64 =         BUFFER_ADDRESS//8        # input [28:0] lo_addr64;        # low address of the system memory range, in 64-bit words 
        if size64 is None:
            size64 =            BUFFER_LEN//8            # input [28:0] size64;           # size of the system memory range in 64-bit words
        
286 287 288 289 290 291 292 293 294 295
        window_height &= 0x3fff
        if window_height == 0:
            window_height = 0x4000
        window_width &= 0x1fff
        if window_width == 0:
            window_width = 0x2000
            
        if quiet <2:
            print("====== test_afi_rw: write=%s, frame_start=0x%x, window_full_width=%d, window_width=%d, window_height=%d, window_left=%d, window_top=%d"%(
                                      str(write_ddr3),  frame_start_addr, window_full_width,   window_width, window_height, window_left, window_top));
296
            print("len64=0x%x,  width64=0x%x, start64=0x%x, lo_addr64=0x%x, size64=0x%x"%(
297 298
                  (window_width << 1)*window_height,
                  (window_width << 1),
299
                  start64, lo_addr64, size64))
300
        '''    
301 302 303 304 305
        mode=   func_encode_mode_scanline(
                    0, # extra_pages,
                    write_ddr3, # write_mem,
                    1, # enable
                    0)  # chn_reset
306 307
        '''
        mode=   x393_mcntrl.func_encode_mode_scan_tiled(
308
                                   skip_too_late = False,
309 310 311
                                   disable_need = False,
                                   repetitive=    True,
                                   single =       False,
312
                                   reset_frame =  True, # Is needed to propagate start addressFalse,
313 314 315
                                   extra_pages =  0,
                                   write_mem =    write_ddr3,
                                   enable =       True,
316 317
                                   chn_reset =    False,
                                   abort_late =   False)
318

319 320 321 322 323 324 325 326
#        self.x393_axi_tasks.write_control_register(vrlg.MEMBRIDGE_ADDR + vrlg.MEMBRIDGE_WIDTH64,    width64);    
#        self.x393_axi_tasks.write_control_register(vrlg.MCNTRL_SCANLINE_CHN1_ADDR + vrlg.MCNTRL_SCANLINE_MODE,             0); # reset channel, including page address
        self.x393_axi_tasks.write_control_register(vrlg.MCNTRL_SCANLINE_CHN1_ADDR + vrlg.MCNTRL_SCANLINE_STARTADDR,        frame_start_addr) # RA=80, CA=0, BA=0 22-bit frame start address (3 CA LSBs==0. BA==0) 
        self.x393_axi_tasks.write_control_register(vrlg.MCNTRL_SCANLINE_CHN1_ADDR + vrlg.MCNTRL_SCANLINE_FRAME_FULL_WIDTH, window_full_width);
        self.x393_axi_tasks.write_control_register(vrlg.MCNTRL_SCANLINE_CHN1_ADDR + vrlg.MCNTRL_SCANLINE_WINDOW_WH,        (window_height << 16) | window_width) # WINDOW_WIDTH + (WINDOW_HEIGHT<<16));
        self.x393_axi_tasks.write_control_register(vrlg.MCNTRL_SCANLINE_CHN1_ADDR + vrlg.MCNTRL_SCANLINE_WINDOW_X0Y0,      (window_top << 16) | window_left)     # WINDOW_X0+ (WINDOW_Y0<<16));
        self.x393_axi_tasks.write_control_register(vrlg.MCNTRL_SCANLINE_CHN1_ADDR + vrlg.MCNTRL_SCANLINE_WINDOW_STARTXY,   0)
        self.x393_axi_tasks.write_control_register(vrlg.MCNTRL_SCANLINE_CHN1_ADDR + vrlg.MCNTRL_SCANLINE_MODE,             mode) 
327 328
        self.x393_axi_tasks.configure_channel_priority(1,0);    # lowest priority channel 1
        self.x393_axi_tasks.enable_memcntrl_en_dis(1,1);
329
#        write_control_register(test_mode_address,            TEST01_START_FRAME);
330 331 332 333 334 335
        self.afi_setup(0)
        self.membridge_setup(
            (window_width << 1)*window_height, # ((window_width[12:0]==0)? 15'h4000 : {1'b0,window_width[12:0],1'b0})*window_height[13:0], #len64,
            (window_width << 1),               # (window_width[12:0]==0)? 29'h4000 : {15'b0,window_width[12:0],1'b0}, # width64,
            start64,
            lo_addr64,
336
            size64,
337
#            cache,
338
            quiet)
339 340
        self.membridge_start (cont)         
# just wait done (default timeout = 10 sec)
341 342 343
        if wait_ready:
            self.x393_axi_tasks.wait_status_condition ( # may also be read directly from the same bit of mctrl_linear_rw (address=5) status
                vrlg.MEMBRIDGE_STATUS_REG, # MCNTRL_TEST01_STATUS_REG_CHN3_ADDR,
344
                vrlg.MEMBRIDGE_ADDR +vrlg.MEMBRIDGE_STATUS_CNTRL, # MCNTRL_TEST01_ADDR + MCNTRL_TEST01_CHN3_STATUS_CNTRL,
345 346 347 348
                vrlg.DEFAULT_STATUS_MODE,
                2 << vrlg.STATUS_2LSB_SHFT, # bit 24 - busy, bit 25 - frame done
                2 << vrlg.STATUS_2LSB_SHFT,  # mask for the 4-bit page number
                0, # equal to
349
                1); # synchronize sequence number
350