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 .
@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"
from x393_mem import X393Mem
import x393_axi_control_status
from x393_pio_sequences import X393PIOSequences
from x393_mcntrl_timing import X393McntrlTiming
from x393_mcntrl_buffers import X393McntrlBuffers
from verilog_utils import concat,convert_w32_to_mem16 #, getParWidth
import vrlg
import x393_mcntrl
class X393McntrlTests(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
verbose=1
def __init__(self, debug_mode=1,dry_mode=True):
self.DEBUG_MODE= debug_mode
self.DRY_MODE= dry_mode
self.x393_mem= X393Mem(debug_mode,dry_mode)
self.x393_axi_tasks=x393_axi_control_status.X393AxiControlStatus(debug_mode,dry_mode)
self.x393_pio_sequences= X393PIOSequences(debug_mode,dry_mode)
self.x393_mcntrl_timing= X393McntrlTiming(debug_mode,dry_mode)
self.x393_mcntrl_buffers= X393McntrlBuffers(debug_mode,dry_mode)
# self.x393_mcntrl_adjust= X393McntrlAdjust(debug_mode,dry_mode)
try:
self.verbose=vrlg.VERBOSE
except:
pass
'''
def func_encode_mode_tiled(self, # function [6:0]
byte32, # input byte32; # 32-byte columns (0 - 16-byte columns)
keep_open, # input keep_open; # for 8 or less rows - do not close page between accesses
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 7-bit encoded data for tiled mode memory R/W
use 32-byte wide columns (0 - use 16-byte ones)
, do not close page between accesses (for 8 or less rows only)
, 2-bit number of extra pages that need to stay (not to be overwritten) in the buffer
This argument can be used for read access with horizontal overlapping tiles
, write to memory mode (0 - read from memory)
, enable requests from this channel ( 0 will let current to finish, but not raise want/need)
): immediately reset all the internal circuitry
"""
return concat ((
((0,1)[byte32], 1), # byte32,
((0,1)[keep_open],1), # keep_open,
(extra_pages, 2), # extra_pages,
((0,1)[write_mem],1), # write_mem,
((0,1)[enable], 1), #enable,
((1,0)[chn_reset],1)))[0]# ~chn_reset};
def func_encode_mode_scanline(self, # function [4:0]
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
, 2-bit number of extra pages that need to stay (not to be overwritten) in the buffer
This argument can be used for read access with horizontal overlapping tiles
, write to memory mode (0 - read from memory)
, enable requests from this channel ( 0 will let current to finish, but not raise want/need)
): immediately reset all the internal circuitry
"""
return concat ((
(extra_pages, 2), # extra_pages,
((0,1)[write_mem],1), # write_mem,
((0,1)[enable], 1), #enable,
((1,0)[chn_reset],1)))[0] # ~chn_reset};
'''
def test_write_levelling(self,
dqs_odly= None,
wbuf_dly = None,
wait_complete=1, # Wait for operation to complete
quiet=0):
"""
Test write levelling mode
DQS output delay for write levelling mode. If it is not None,
the default DQS output delay will be restored in the end
Write buffer latency (currently 9) If it is not None,
the default wbuf delay will be restored in the end
wait write levelling operation to complete (0 - may initiate multiple PS PIO operations)
reduce output
returns a pair of ratios for getting "1" for 2 lanes and problem marker (should be 0)
"""
self.x393_pio_sequences.set_write_lev(16) # write leveling, 16 times (full buffer - 128)
if not dqs_odly is None:
self.x393_mcntrl_timing.axi_set_dqs_odelay(dqs_odly)
# Set write buffer (from DDR3) WE signal delay for write leveling mode
if not wbuf_dly is None:
self.x393_mcntrl_timing.axi_set_wbuf_delay(wbuf_dly)
rslt= self.x393_pio_sequences.write_levelling(
wait_complete,
16, # number of 8-bursts
quiet)
#restore values to defaults (only if changed)
if not dqs_odly is None:
self.x393_mcntrl_timing.axi_set_dqs_odelay()
# Set write buffer (from DDR3) WE signal delay for write leveling mode
if not wbuf_dly is None:
self.x393_mcntrl_timing.axi_set_wbuf_delay()
# if quiet <2:
# print ("WLEV lanes ratios: %f %f, non 0x00/0x01 bytes: %f"%(rslt[0],rslt[1],rslt[2]))
return rslt
def test_read_pattern(self,
dq_idelay=None,
dqs_idelay=None,
wait_complete=1): # Wait for operation to complete
"""
Test read pattern mode
set DQ input delays if provided ([] - skip, single number - both lanes, 2 element list - per/lane)
set DQS input delays if provided ([] - skip, single number - both lanes, 2 element list - per/lane)
wait read pattern operation to complete (0 - may initiate multiple PS PIO operations)
returns list of the read data
"""
if (not dq_idelay is None) and (dq_idelay != []):
self.x393_mcntrl_timing.axi_set_dq_idelay(dq_idelay)
if (not dqs_idelay is None) and (dqs_idelay != []):
self.x393_mcntrl_timing.axi_set_dqs_idelay(dqs_idelay)
return self.x393_pio_sequences.read_pattern(
32, # num
1, # show_rslt,
wait_complete) # # Wait for operation to complete
def test_write_block(self,
dq_odelay=None,
dqs_odelay=None,
wait_complete=1): # Wait for operation to complete
"""
Test write block in PS PIO mode
set DQ output delays if provided ([] - skip, single number - both lanes, 2 element list - per/lane)
set DQS output delays if provided ([] - skip, single number - both lanes, 2 element list - per/lane)
wait write block operation to complete (0 - may initiate multiple PS PIO operations)
"""
if (not dq_odelay is None) and (dq_odelay != []):
self.x393_mcntrl_timing.axi_set_dq_odelay(dq_odelay)
if (not dqs_odelay is None) and (dqs_odelay != []):
self.x393_mcntrl_timing.axi_set_dqs_odelay(dqs_odelay)
return self.x393_pio_sequences.write_block(0,wait_complete) # Wait for operation to complete
def test_read_block(self,
dq_idelay=None,
dqs_idelay=None,
wait_complete=1): # Wait for operation to complete
"""
Test read block in PS PIO mode
set DQ input delays if provided ([] - skip, single number - both lanes, 2 element list - per/lane)
set DQS input delays if provided ([] - skip, single number - both lanes, 2 element list - per/lane)
wait read block operation to complete (0 - may initiate multiple PS PIO operations)
returns list of the read data
"""
if (not dq_idelay is None) and (dq_idelay != []):
self.x393_mcntrl_timing.axi_set_dq_idelay(dq_idelay)
if (not dqs_idelay is None) and (dqs_idelay != []):
self.x393_mcntrl_timing.axi_set_dqs_idelay(dqs_idelay)
rd_buf = self.x393_pio_sequences.read_block(
256, # num,
0, # show_rslt,
wait_complete) # Wait for operation to complete
sum_rd_buf=0
for d in rd_buf:
sum_rd_buf+=d
print("read buffer: (0x%x):"%sum_rd_buf)
for i in range(len(rd_buf)):
if (i & 0xf) == 0:
print("\n%03x:"%i,end=" ")
print("%08x"%rd_buf[i],end=" ")
print("\n")
return rd_buf
def test_read_block16(self,
dq_idelay=None,
dqs_idelay=None,
wait_complete=1): # Wait for operation to complete
"""
Test read block in PS PIO mode, convert data to match DDR3 16-bit output words
set DQ input delays if provided ([] - skip, single number - both lanes, 2 element list - per/lane)
set DQS input delays if provided ([] - skip, single number - both lanes, 2 element list - per/lane)
wait read block operation to complete (0 - may initiate multiple PS PIO operations)
returns list of the read data
"""
if (not dq_idelay is None) and (dq_idelay != []):
self.x393_mcntrl_timing.axi_set_dq_idelay(dq_idelay)
if (not dqs_idelay is None) and (dqs_idelay != []):
self.x393_mcntrl_timing.axi_set_dqs_idelay(dqs_idelay)
rd_buf = self.x393_pio_sequences.read_block(
256, # num,
0, # show_rslt,
wait_complete) # Wait for operation to complete
read16=convert_w32_to_mem16(rd_buf) # 512x16 bit, same as DDR3 DQ over time
sum_read16=0
for d in read16:
sum_read16+=d
print("read16 (0x%x):"%sum_read16)
for i in range(len(read16)):
if (i & 0x1f) == 0:
print("\n%03x:"%i,end=" ")
print("%04x"%read16[i],end=" ")
print("\n")
return read16
def test_scanline_write(self, #
channel, # input [3:0] channel;
extra_pages, # input [1:0] extra_pages;
wait_done, # input wait_done;
window_width, # input [15:0] window_width;
window_height, # input [15:0] window_height;
window_left, # input [15:0] window_left;
window_top): # input [15:0] window_top;
"""
Test scanline write (frame size/row increment is set in parameters)
channel number to use. Valid values: 1, 3
2-bit number of extra pages that need to stay (not to be overwritten) in the buffer
for operation finished
13-bit window width in 8-bursts (16 bytes)
16 bit window height
, 13-bit window left margin in 8-bursts (16 bytes)
16-bit window top margin
"""
# integer startx,starty; # temporary - because of the vdt bug with integer ports
# pages_per_row= (window_width>>NUM_XFER_BITS)+((window_width[NUM_XFER_BITS-1:0]==0)?0:1);
pages_per_row= (window_width>>vrlg.NUM_XFER_BITS)+(1,0)[(window_width & ((1<>NUM_XFER_BITS)+((window_width[NUM_XFER_BITS-1:0]==0)?0:1);
print("====== test_scanline_write: channel=%d, extra_pages=%d, wait_done=%d"%
(channel, extra_pages, wait_done))
'''
if channel == 1:
start_addr= vrlg.MCNTRL_SCANLINE_CHN1_ADDR
status_address= vrlg.MCNTRL_TEST01_STATUS_REG_CHN1_ADDR
status_control_address= vrlg.MCNTRL_TEST01_ADDR + vrlg.MCNTRL_TEST01_CHN1_STATUS_CNTRL
test_mode_address= vrlg.MCNTRL_TEST01_ADDR + vrlg.MCNTRL_TEST01_CHN1_MODE
'''
if channel == 3:
start_addr= vrlg.MCNTRL_SCANLINE_CHN3_ADDR
status_address= vrlg.MCNTRL_TEST01_STATUS_REG_CHN3_ADDR
status_control_address= vrlg.MCNTRL_TEST01_ADDR + vrlg.MCNTRL_TEST01_CHN3_STATUS_CNTRL
test_mode_address= vrlg.MCNTRL_TEST01_ADDR + vrlg.MCNTRL_TEST01_CHN3_MODE
else:
print("**** ERROR: Invalid channel, only 3 is valid")
start_addr= vrlg.MCNTRL_SCANLINE_CHN1_ADDR
status_address= vrlg.MCNTRL_TEST01_STATUS_REG_CHN3_ADDR
status_control_address= vrlg.MCNTRL_TEST01_ADDR + vrlg.MCNTRL_TEST01_CHN3_STATUS_CNTRL
test_mode_address= vrlg.MCNTRL_TEST01_ADDR + vrlg.MCNTRL_TEST01_CHN3_MODE
'''
mode= self.func_encode_mode_scanline(
extra_pages,
1, # write_mem,
1, # enable
0) # chn_reset
'''
mode= x393_mcntrl.func_encode_mode_scan_tiled(
disable_need = False,
repetitive= True,
single = False,
reset_frame = False,
extra_pages = extra_pages,
write_mem = True,
enable = True,
chn_reset = False)
self.x393_axi_tasks.write_control_register(start_addr + vrlg.MCNTRL_SCANLINE_MODE, 0); # reset channel, including page address
self.x393_axi_tasks.write_control_register(start_addr + vrlg.MCNTRL_SCANLINE_STARTADDR, vrlg.FRAME_START_ADDRESS); # RA=80, CA=0, BA=0 22-bit frame start address (3 CA LSBs==0. BA==0)
self.x393_axi_tasks.write_control_register(start_addr + vrlg.MCNTRL_SCANLINE_FRAME_FULL_WIDTH, vrlg.FRAME_FULL_WIDTH);
self.x393_axi_tasks.write_control_register(start_addr + vrlg.MCNTRL_SCANLINE_WINDOW_WH, (window_height<<16) | window_width); #WINDOW_WIDTH + (WINDOW_HEIGHT<<16));
self.x393_axi_tasks.write_control_register(start_addr + vrlg.MCNTRL_SCANLINE_WINDOW_X0Y0, (window_top<<16) | window_left); #WINDOW_X0+ (WINDOW_Y0<<16));
self.x393_axi_tasks.write_control_register(start_addr + vrlg.MCNTRL_SCANLINE_WINDOW_STARTXY, vrlg.SCANLINE_STARTX+(vrlg.SCANLINE_STARTY<<16));
self.x393_axi_tasks.write_control_register(start_addr + vrlg.MCNTRL_SCANLINE_MODE, mode);
self.x393_axi_tasks.configure_channel_priority(channel,0); # lowest priority channel 3
# enable_memcntrl_channels(16'h000b); # channels 0,1,3 are enabled
self.x393_axi_tasks.enable_memcntrl_en_dis(channel,1);
self.x393_axi_tasks.write_control_register(test_mode_address, vrlg.TEST01_START_FRAME);
for ii in range(0,vrlg.TEST_INITIAL_BURST): # for (ii=0;ii 1:
if (ii % pages_per_row) < (pages_per_row-1):
xfer_size= 1 << vrlg.NUM_XFER_BITS
else:
xfer_size= window_width % (1<= vrlg.TEST_INITIAL_BURST): # begin # wait page ready and fill page after first 4 are filled
self.x393_axi_tasks.wait_status_condition (
status_address, # MCNTRL_TEST01_STATUS_REG_CHN3_ADDR,
status_control_address, # MCNTRL_TEST01_ADDR + MCNTRL_TEST01_CHN3_STATUS_CNTRL,
vrlg.DEFAULT_STATUS_MODE,
(ii-vrlg.TEST_INITIAL_BURST)<<16, # 4-bit page number
0xf << 16, #'hf << 16, # mask for the 4-bit page number
1, # not equal to
(0,1)[ii == vrlg.TEST_INITIAL_BURST]) # synchronize sequence number - only first time, next just wait fro auto update
if pages_per_row > 1:
if (ii % pages_per_row) < (pages_per_row-1):
xfer_size= 1 << vrlg.NUM_XFER_BITS
else:
xfer_size= window_width % (1<>NUM_XFER_BITS)+((window_width[NUM_XFER_BITS-1:0]==0)?0:1);
pages_per_row= (window_width>>vrlg.NUM_XFER_BITS)+(1,0)[(window_width & ((1<>NUM_XFER_BITS)+((window_width[NUM_XFER_BITS-1:0]==0)?0:1);
print("====== test_scanline_read: channel=%d, extra_pages=%d, show_data=%d"%
(channel, extra_pages, show_data))
'''
if channel == 1:
start_addr= vrlg.MCNTRL_SCANLINE_CHN1_ADDR
status_address= vrlg.MCNTRL_TEST01_STATUS_REG_CHN1_ADDR
status_control_address= vrlg.MCNTRL_TEST01_ADDR + vrlg.MCNTRL_TEST01_CHN1_STATUS_CNTRL
test_mode_address= vrlg.MCNTRL_TEST01_ADDR + vrlg.MCNTRL_TEST01_CHN1_MODE
'''
if channel == 3:
start_addr= vrlg.MCNTRL_SCANLINE_CHN3_ADDR
status_address= vrlg.MCNTRL_TEST01_STATUS_REG_CHN3_ADDR
status_control_address= vrlg.MCNTRL_TEST01_ADDR + vrlg.MCNTRL_TEST01_CHN3_STATUS_CNTRL
test_mode_address= vrlg.MCNTRL_TEST01_ADDR + vrlg.MCNTRL_TEST01_CHN3_MODE
else:
print("**** ERROR: Invalid channel, only 3 is valid")
start_addr= vrlg.MCNTRL_SCANLINE_CHN3_ADDR
status_address= vrlg.MCNTRL_TEST01_STATUS_REG_CHN3_ADDR
status_control_address= vrlg.MCNTRL_TEST01_ADDR + vrlg.MCNTRL_TEST01_CHN3_STATUS_CNTRL
test_mode_address= vrlg.MCNTRL_TEST01_ADDR + vrlg.MCNTRL_TEST01_CHN3_MODE
'''
mode= self.func_encode_mode_scanline(
extra_pages,
0, # write_mem,
1, # enable
0) # chn_reset
'''
mode= x393_mcntrl.func_encode_mode_scan_tiled(
disable_need = False,
repetitive= True,
single = False,
reset_frame = False,
extra_pages = extra_pages,
write_mem = False,
enable = True,
chn_reset = False)
# program to the
self.x393_axi_tasks.write_control_register(start_addr + vrlg.MCNTRL_SCANLINE_MODE, 0); # reset channel, including page address
self.x393_axi_tasks.write_control_register(start_addr + vrlg.MCNTRL_SCANLINE_STARTADDR, vrlg.FRAME_START_ADDRESS); # RA=80, CA=0, BA=0 22-bit frame start address (3 CA LSBs==0. BA==0)
self.x393_axi_tasks.write_control_register(start_addr + vrlg.MCNTRL_SCANLINE_FRAME_FULL_WIDTH, vrlg.FRAME_FULL_WIDTH);
self.x393_axi_tasks.write_control_register(start_addr + vrlg.MCNTRL_SCANLINE_WINDOW_WH, (window_height << 16) | window_width); #WINDOW_WIDTH + (WINDOW_HEIGHT<<16));
self.x393_axi_tasks.write_control_register(start_addr + vrlg.MCNTRL_SCANLINE_WINDOW_X0Y0, (window_top << 16) | window_left); #WINDOW_X0+ (WINDOW_Y0<<16));
self.x393_axi_tasks.write_control_register(start_addr + vrlg.MCNTRL_SCANLINE_WINDOW_STARTXY, vrlg.SCANLINE_STARTX+(vrlg.SCANLINE_STARTY<<16));
self.x393_axi_tasks.write_control_register(start_addr + vrlg.MCNTRL_SCANLINE_MODE, mode);# set mode register: {extra_pages[1:0],enable,!reset}
self.x393_axi_tasks.configure_channel_priority(channel,0); # lowest priority channel 3
self.x393_axi_tasks.enable_memcntrl_en_dis(channel,1);
self.x393_axi_tasks.write_control_register(test_mode_address, vrlg.TEST01_START_FRAME);
for ii in range(window_height * pages_per_row): # for (ii=0;ii<(window_height * pages_per_row);ii = ii+1) begin
if pages_per_row > 1:
if (ii % pages_per_row) < (pages_per_row-1):
xfer_size= 1 << vrlg.NUM_XFER_BITS
else:
xfer_size= window_width % (1< channel number to use. Valid values: 2, 4
use 32-byte wide columns (0 - use 16-byte ones)
, do not close page between accesses (for 8 or less rows only)
2-bit number of extra pages that need to stay (not to be overwritten) in the buffer
wait for operation finished
13-bit window width in 8-bursts (16 bytes)
16 bit window height
, 13-bit window left margin in 8-bursts (16 bytes)
16-bit window top margin
6-bit tile width in 8-bursts (16 bytes) (0 -> 64)
6-bit tile_height (0->64)
6-bit tile vertical step (0->64) to control tole vertical overlap
"""
# tiles_per_row= (window_width/tile_width)+ ((window_width % tile_width==0)?0:1);
tiles_per_row= (window_width/tile_width)+ (0,1)[(window_width % tile_width)==0]
tile_rows_per_window= ((window_height-1)/tile_vstep) + 1
tile_size= tile_width*tile_height;
channel= (0,1)[channel]
keep_open= (0,1)[keep_open]
wait_done= (0,1)[wait_done]
print("====== test_tiled_write: channel=%d, byte32=%d, keep_open=%d, extra_pages=%d, wait_done=%d"%
(channel, byte32, keep_open, extra_pages, wait_done))
if channel == 2:
start_addr= vrlg.MCNTRL_TILED_CHN2_ADDR
status_address= vrlg.MCNTRL_TEST01_STATUS_REG_CHN2_ADDR
status_control_address= vrlg.MCNTRL_TEST01_ADDR + vrlg.MCNTRL_TEST01_CHN2_STATUS_CNTRL
test_mode_address= vrlg.MCNTRL_TEST01_ADDR + vrlg.MCNTRL_TEST01_CHN2_MODE
elif channel == 4:
start_addr= vrlg.MCNTRL_TILED_CHN4_ADDR;
status_address= vrlg.MCNTRL_TEST01_STATUS_REG_CHN4_ADDR;
status_control_address= vrlg.MCNTRL_TEST01_ADDR + vrlg.MCNTRL_TEST01_CHN4_STATUS_CNTRL;
test_mode_address= vrlg.MCNTRL_TEST01_ADDR + vrlg.MCNTRL_TEST01_CHN4_MODE;
else:
print("**** ERROR: Invalid channel, only 2 and 4 are valid");
start_addr= vrlg.MCNTRL_TILED_CHN2_ADDR;
status_address= vrlg.MCNTRL_TEST01_STATUS_REG_CHN2_ADDR;
status_control_address= vrlg.MCNTRL_TEST01_ADDR + vrlg.MCNTRL_TEST01_CHN2_STATUS_CNTRL;
test_mode_address= vrlg.MCNTRL_TEST01_ADDR + vrlg.MCNTRL_TEST01_CHN2_MODE;
'''
mode= self.func_encode_mode_tiled(
byte32,
keep_open,
extra_pages,
1, # write_mem,
1, # enable
0) # chn_reset
'''
mode= x393_mcntrl.func_encode_mode_scan_tiled(
disable_need = False,
repetitive= True,
single = False,
reset_frame = False,
byte32 = byte32,
keep_open = keep_open,
extra_pages = extra_pages,
write_mem = True,
enable = True,
chn_reset = False)
self.x393_axi_tasks.write_control_register(start_addr + vrlg.MCNTRL_TILED_MODE, 0); # reset channel, including page address
self.x393_axi_tasks.write_control_register(start_addr + vrlg.MCNTRL_TILED_STARTADDR,
vrlg.FRAME_START_ADDRESS) # RA=80, CA=0, BA=0 22-bit frame start address (3 CA LSBs==0. BA==0)
self.x393_axi_tasks.write_control_register(start_addr + vrlg.MCNTRL_TILED_FRAME_FULL_WIDTH,
vrlg.FRAME_FULL_WIDTH)
self.x393_axi_tasks.write_control_register(start_addr + vrlg.MCNTRL_TILED_WINDOW_WH,
concat(((window_height,16),
(window_width, 16)))[0]) # {window_height,window_width});
self.x393_axi_tasks.write_control_register(start_addr + vrlg.MCNTRL_TILED_WINDOW_X0Y0,
concat(((window_top, 16),
(window_left, 16)))[0]) # {window_top,window_left});
self.x393_axi_tasks.write_control_register(start_addr + vrlg.MCNTRL_TILED_WINDOW_STARTXY,
concat(((vrlg.TILED_STARTY, 16),
(vrlg.TILED_STARTX, 16)))[0]) # TILED_STARTX+(TILED_STARTY<<16));
self.x393_axi_tasks.write_control_register(start_addr + vrlg.MCNTRL_TILED_TILE_WHS,
concat(((tile_vstep, 8),
(tile_height, 8),
(tile_width, 8)))[0]) # {8'b0,tile_vstep,tile_height,tile_width});#tile_width+(tile_height<<8)+(tile_vstep<<16));
self.x393_axi_tasks.write_control_register(start_addr + vrlg.MCNTRL_TILED_MODE, mode);# set mode register: {extra_pages[1:0],enable,!reset}
self.x393_axi_tasks.configure_channel_priority(channel,0) # lowest priority channel 3
self.x393_axi_tasks.enable_memcntrl_en_dis(channel,1);
self.x393_axi_tasks.write_control_register(test_mode_address, vrlg.TEST01_START_FRAME);
for ii in range(vrlg.TEST_INITIAL_BURST): # for (ii=0;ii= vrlg.TEST_INITIAL_BURST: # ) begin # wait page ready and fill page after first 4 are filled
self.x393_axi_tasks.wait_status_condition (
status_address, # MCNTRL_TEST01_STATUS_REG_CHN5_ADDR,
status_control_address, # MCNTRL_TEST01_ADDR + MCNTRL_TEST01_CHN5_STATUS_CNTRL,
vrlg.DEFAULT_STATUS_MODE,
(ii-vrlg.TEST_INITIAL_BURST)<<16, # 4-bit page number
0xf << 16, # 'hf << 16, # mask for the 4-bit page number
1, # not equal to
(0,1)[ii == vrlg.TEST_INITIAL_BURST]); # synchronize sequence number - only first time, next just wait fro auto update
print("########### test_tiled_write block %d: channel=%d"%(ii, channel))
startx = window_left + ((ii % tiles_per_row) * tile_width);
starty = window_top + (ii / tile_rows_per_window);
self.x393_mcntrl_buffers.write_block_scanline_chn( # TODO: Make a different tile buffer data, matching the order
channel, # channel
(ii & 3),
tile_size,
startx, # window_left + ((ii % tiles_per_row) * tile_width),
starty) # window_top + (ii / tile_rows_per_window)); # SCANLINE_CUR_Y);\
self.x393_axi_tasks.write_control_register(test_mode_address, vrlg.TEST01_NEXT_PAGE);
if wait_done:
self.x393_axi_tasks.wait_status_condition( # may also be read directly from the same bit of mctrl_linear_rw (address=5) status
status_address, # MCNTRL_TEST01_STATUS_REG_CHN3_ADDR,
status_control_address, # MCNTRL_TEST01_ADDR + MCNTRL_TEST01_CHN3_STATUS_CNTRL,
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
0) # no need to synchronize sequence number
# enable_memcntrl_en_dis(channel,0); # disable channel
def test_tiled_read(self, #\
channel, # input [3:0] channel;
byte32, # input byte32;
keep_open, # input keep_open;
extra_pages, # input [1:0] extra_pages;
show_data, # input show_data;
window_width, # input [15:0] window_width;
window_height, # input [15:0] window_height;
window_left, # input [15:0] window_left;
window_top, # input [15:0] window_top;
tile_width, # input [ 7:0] tile_width;
tile_height, # input [ 7:0] tile_height;
tile_vstep): # input [ 7:0] tile_vstep;
"""
Test tiled mode write (frame size/row increment is set in parameters)
channel number to use. Valid values: 2, 4
use 32-byte wide columns (0 - use 16-byte ones)
, do not close page between accesses (for 8 or less rows only)
2-bit number of extra pages that need to stay (not to be overwritten) in the buffer
print read data
13-bit window width in 8-bursts (16 bytes)
16 bit window height
, 13-bit window left margin in 8-bursts (16 bytes)
16-bit window top margin
6-bit tile width in 8-bursts (16 bytes) (0 -> 64)
6-bit tile_height (0->64)
6-bit tile vertical step (0->64) to control tole vertical overlap
Returns read data as a list
"""
result=[] # will be a 2-d array
# tiles_per_row= (window_width/tile_width)+ ((window_width % tile_width==0)?0:1);
tiles_per_row= (window_width/tile_width)+ (0,1)[(window_width % tile_width)==0]
tile_rows_per_window= ((window_height-1)/tile_vstep) + 1
tile_size= tile_width*tile_height;
channel= (0,1)[channel]
keep_open= (0,1)[keep_open]
show_data= (0,1)[show_data]
print("====== test_tiled_read: channel=%d, byte32=%d, keep_open=%d, extra_pages=%d, show_data=%d"%
(channel, byte32, keep_open, extra_pages, show_data))
if channel == 2:
start_addr= vrlg.MCNTRL_TILED_CHN2_ADDR;
status_address= vrlg.MCNTRL_TEST01_STATUS_REG_CHN2_ADDR;
status_control_address= vrlg.MCNTRL_TEST01_ADDR + vrlg.MCNTRL_TEST01_CHN2_STATUS_CNTRL;
test_mode_address= vrlg.MCNTRL_TEST01_ADDR + vrlg.MCNTRL_TEST01_CHN2_MODE;
elif channel == 4:
start_addr= vrlg.MCNTRL_TILED_CHN4_ADDR;
status_address= vrlg.MCNTRL_TEST01_STATUS_REG_CHN4_ADDR;
status_control_address= vrlg.MCNTRL_TEST01_ADDR + vrlg.MCNTRL_TEST01_CHN4_STATUS_CNTRL;
test_mode_address= vrlg.MCNTRL_TEST01_ADDR + vrlg.MCNTRL_TEST01_CHN4_MODE;
else:
print("**** ERROR: Invalid channel, only 2 and 4 are valid");
start_addr= vrlg.MCNTRL_TILED_CHN2_ADDR;
status_address= vrlg.MCNTRL_TEST01_STATUS_REG_CHN2_ADDR;
status_control_address= vrlg.MCNTRL_TEST01_ADDR + vrlg.MCNTRL_TEST01_CHN2_STATUS_CNTRL;
test_mode_address= vrlg.MCNTRL_TEST01_ADDR + vrlg.MCNTRL_TEST01_CHN2_MODE;
'''
mode= self.func_encode_mode_tiled(
byte32,
keep_open,
extra_pages,
0, # write_mem,
1, # enable
0) # chn_reset
'''
mode= x393_mcntrl.func_encode_mode_scan_tiled(
disable_need = False,
repetitive= True,
single = False,
reset_frame = False,
byte32 = byte32,
keep_open = keep_open,
extra_pages = extra_pages,
write_mem = False,
enable = True,
chn_reset = False)
self.x393_axi_tasks.write_control_register(start_addr + vrlg.MCNTRL_TILED_MODE, 0); # reset channel, including page address
self.x393_axi_tasks.write_control_register(start_addr + vrlg.MCNTRL_TILED_STARTADDR,
vrlg.FRAME_START_ADDRESS) # RA=80, CA=0, BA=0 22-bit frame start address (3 CA LSBs==0. BA==0)
self.x393_axi_tasks.write_control_register(start_addr + vrlg.MCNTRL_TILED_FRAME_FULL_WIDTH,
vrlg.FRAME_FULL_WIDTH)
self.x393_axi_tasks.write_control_register(start_addr + vrlg.MCNTRL_TILED_WINDOW_WH,
concat(((window_height,16),
(window_width, 16)))[0]) # {window_height,window_width});
self.x393_axi_tasks.write_control_register(start_addr + vrlg.MCNTRL_TILED_WINDOW_X0Y0,
concat(((window_top, 16),
(window_left, 16)))[0]) # {window_top,window_left});
self.x393_axi_tasks.write_control_register(start_addr + vrlg.MCNTRL_TILED_WINDOW_STARTXY,
concat(((vrlg.TILED_STARTY, 16),
(vrlg.TILED_STARTX, 16)))[0]) # TILED_STARTX+(TILED_STARTY<<16));
self.x393_axi_tasks.write_control_register(start_addr + vrlg.MCNTRL_TILED_TILE_WHS,
concat(((tile_vstep, 8),
(tile_height, 8),
(tile_width, 8)))[0]) # {8'b0,tile_vstep,tile_height,tile_width});#tile_width+(tile_height<<8)+(tile_vstep<<16));
self.x393_axi_tasks.write_control_register(start_addr + vrlg.MCNTRL_TILED_MODE, mode);# set mode register: {extra_pages[1:0],enable,!reset}
self.x393_axi_tasks.configure_channel_priority(channel,0) # lowest priority channel 3
self.x393_axi_tasks.enable_memcntrl_en_dis(channel,1);
self.x393_axi_tasks.write_control_register(test_mode_address, vrlg.TEST01_START_FRAME);
for ii in range(tiles_per_row * tile_rows_per_window): # (ii=0;ii<(tiles_per_row * tile_rows_per_window);ii = ii+1) begin
self.x393_axi_tasks.wait_status_condition (
status_address, # MCNTRL_TEST01_STATUS_REG_CHN4_ADDR,
status_control_address, # MCNTRL_TEST01_ADDR + MCNTRL_TEST01_CHN4_STATUS_CNTRL,
vrlg.DEFAULT_STATUS_MODE,
ii << 16, # -TEST_INITIAL_BURST)<<16, # 4-bit page number
0xf<< 16, #'hf << 16, # mask for the 4-bit page number
1, # not equal to
(0,1)[ii == 0]) # synchronize sequence number - only first time, next just wait fro auto update
if (show_data):
print("########### test_tiled_read block %d: channel=%d"%(ii, channel))
result.append(self.x393_mcntrl_buffers.read_block_buf_chn (channel,
(ii & 3),
tile_size <<2,
# 1, # chn=0, page=3, number of 32-bit words=256, show_rslt
show_data))
self.x393_axi_tasks.write_control_register(test_mode_address, vrlg.TEST01_NEXT_PAGE);
# enable_memcntrl_en_dis(channel,0); # disable channel
return result