Commit 8df14818 authored by Andrey Filippov's avatar Andrey Filippov

more hardware tests

parent 49288bf2
......@@ -33,13 +33,13 @@ task wait_status_condition;
begin
WAITING_STATUS = 1;
for (match=0; !match; match = invert_match ^ (((registered_rdata ^ {6'h0,pattern}) & {6'h0,mask})==0)) begin
read_and_wait_status(status_address);
read_status(status_address);
if (wait_seq) begin
seq_num = (registered_rdata[STATUS_SEQ_SHFT+:6] ^ 6'h20)&'h30;
write_contol_register(status_control_address, {24'b0,status_mode,seq_num});
read_and_wait_status(status_address);
read_status(status_address);
while (((registered_rdata[STATUS_SEQ_SHFT+:6] ^ seq_num) & 6'h30)!=0) begin // match just 2 MSBs
read_and_wait_status(status_address);
read_status(status_address);
end
end
end
......@@ -58,7 +58,7 @@ task wait_status_condition_auto; // assumes status is already updating
begin
WAITING_STATUS = 1;
for (match=0; !match; match = invert_match ^ (((registered_rdata ^ {6'h0,pattern}) & {6'h0,mask})==0)) begin
read_and_wait_status(status_address);
read_status(status_address);
end
WAITING_STATUS = 0;
end
......@@ -68,9 +68,9 @@ endtask
task wait_phase_shifter_ready;
begin
WAITING_STATUS = 1;
read_and_wait_status(MCONTR_PHY_STATUS_REG_ADDR);
read_status(MCONTR_PHY_STATUS_REG_ADDR);
while (((registered_rdata & STATUS_PSHIFTER_RDY_MASK) == 0) || (((registered_rdata ^ {24'h0,target_phase}) & 'hff) != 0)) begin
read_and_wait_status(MCONTR_PHY_STATUS_REG_ADDR); // exits after negedge CLK
read_status(MCONTR_PHY_STATUS_REG_ADDR); // exits after negedge CLK
end
WAITING_STATUS = 0;
end
......@@ -78,21 +78,21 @@ endtask
task read_all_status;
begin
read_and_wait_status (MCONTR_PHY_STATUS_REG_ADDR);
read_and_wait_status (MCONTR_TOP_STATUS_REG_ADDR);
read_and_wait_status (MCNTRL_PS_STATUS_REG_ADDR);
read_and_wait_status (MCNTRL_SCANLINE_STATUS_REG_CHN1_ADDR);
read_and_wait_status (MCNTRL_SCANLINE_STATUS_REG_CHN3_ADDR);
read_and_wait_status (MCNTRL_TILED_STATUS_REG_CHN2_ADDR);
read_and_wait_status (MCNTRL_TILED_STATUS_REG_CHN4_ADDR);
read_and_wait_status (MCNTRL_TEST01_STATUS_REG_CHN1_ADDR);
read_and_wait_status (MCNTRL_TEST01_STATUS_REG_CHN2_ADDR);
read_and_wait_status (MCNTRL_TEST01_STATUS_REG_CHN3_ADDR);
read_and_wait_status (MCNTRL_TEST01_STATUS_REG_CHN4_ADDR);
read_status (MCONTR_PHY_STATUS_REG_ADDR);
read_status (MCONTR_TOP_STATUS_REG_ADDR);
read_status (MCNTRL_PS_STATUS_REG_ADDR);
read_status (MCNTRL_SCANLINE_STATUS_REG_CHN1_ADDR);
read_status (MCNTRL_SCANLINE_STATUS_REG_CHN3_ADDR);
read_status (MCNTRL_TILED_STATUS_REG_CHN2_ADDR);
read_status (MCNTRL_TILED_STATUS_REG_CHN4_ADDR);
read_status (MCNTRL_TEST01_STATUS_REG_CHN1_ADDR);
read_status (MCNTRL_TEST01_STATUS_REG_CHN2_ADDR);
read_status (MCNTRL_TEST01_STATUS_REG_CHN3_ADDR);
read_status (MCNTRL_TEST01_STATUS_REG_CHN4_ADDR);
end
endtask
task read_and_wait_status;
task read_status;
input [STATUS_DEPTH-1:0] address;
begin
read_and_wait_w(STATUS_ADDR + address ); // Will set: registered_rdata <= rdata;
......
......@@ -377,7 +377,13 @@ USAGE
print
for name,val in sorted(callableTasks.items()):
if re.match(helpFilter,name):
#enable_memcntrl enable_memcntr .__class__.__name__
print('=== %s ==='%name)
print('defined in %s.%s, %s: %d)'%(str(callableTasks[name]['inst'].__class__.__module__),
callableTasks[name]['inst'].__class__.__name__,
callableTasks[name]['func'].func_code.co_filename,
callableTasks[name]['func'].func_code.co_firstlineno
))
sFuncArgs=getFuncArgsString(name)
docs=callableTasks[name]['docs']
if docs:
......
......@@ -40,12 +40,16 @@ def hx(obj):
Simulate Verilog concatenation. Input list tuple of items, each being a pair of (value, width)
'''
def concat(items):
# print(items)
val=0
width=0
for vw in reversed(items):
v=vw[0]
if vw[1]==1:
v=(0,1)[v] # So True/False will also work, not juet o/1
if vw[1]==1: # So True/False will also work, not just 0/1
if v:
v=1
else:
v=0
val |= (v & ((1 << vw[1])-1))<<width
width += vw[1]
return (val,width)
......
......@@ -34,7 +34,7 @@ from import_verilog_parameters import VerilogParameters
from x393_mem import X393Mem
#from verilog_utils import hx,concat, bits
from verilog_utils import hx
from time import time
class X393AxiControlStatus(object):
DRY_MODE= True # True
DEBUG_MODE=1
......@@ -72,13 +72,12 @@ class X393AxiControlStatus(object):
<data> - 32-bit data to write
"""
self.x393_mem.axi_write_single_w(self.CONTROL_ADDR+reg_addr, data)
def read_and_wait_status(self, address):
def read_status(self, address): # was read_and_wait_status
"""
Read word from the status register (up to 26 bits payload and 6-bit sequence number)
<addr> - status register address (currently 0..255)
"""
return self.x393_mem.axi_read_addr_w(self.STATUS_ADDR + address )
def wait_status_condition(self,
status_address, # input [STATUS_DEPTH-1:0] status_address;
status_control_address, # input [29:0] status_control_address;
......@@ -86,7 +85,8 @@ class X393AxiControlStatus(object):
pattern, # input [25:0] pattern; // bits as in read registers
mask, # input [25:0] mask; // which bits to compare
invert_match, # input invert_match; // 0 - wait until match to pattern (all bits), 1 - wait until no match (any of bits differ)
wait_seq): # input wait_seq; // Wait for the correct sequence number, False assume correct
wait_seq, # input wait_seq; // Wait for the correct sequence number, False assume correct
timeout=10.0): # maximal timeout (0 - no timeout)
"""
Poll specified status register until some condition is matched
<status_address> - status register address (currently 0..255)
......@@ -100,20 +100,37 @@ class X393AxiControlStatus(object):
<mask> - 26-bit mask to enable pattern matching (0-s - ignore)
<invert_match> - invert match (wait until matching condition becomes false)
<wait_seq>- wait for the correct sequence number, if False - assume always correct
<timeout> maximal time to wait for condition
Return 1 if success, 0 - if timeout
"""
match=False
endTime=None
if timeout>0:
endTime=time()+timeout
while not match:
data=self.read_and_wait_status(status_address)
data=self.read_status(status_address)
if wait_seq:
seq_num = ((data >> self.STATUS_SEQ_SHFT) ^ 0x20) & 0x30
data=self.read_and_wait_status(status_address)
self.write_contol_register(status_control_address, ((status_mode & 3) <<6) | (seq_num & 0x3f))
data=self.read_status(status_address)
while (((data >> self.STATUS_SEQ_SHFT) ^ seq_num) & 0x30) !=0:
data=self.read_and_wait_status(status_address)
data=self.read_status(status_address)
if self.DRY_MODE: break
if timeout and (time()>endTime):
print("TIMEOUT in wait_status_condition(status_address=0x%x,status_control_address=0x%x,pattern=0x%x,mask=0x%x,timeout=%f)"%
(status_address,status_control_address,pattern,mask,timeout))
print ("last read status data is 0x%x, written seq number is 0x%x"%(data,seq_num))
return 0
match = (((data ^ pattern) & mask & 0x3ffffff)==0)
if invert_match:
match = not match
if self.DRY_MODE: break
if timeout and (time()>endTime):
print("TIMEOUT1 in wait_status_condition(status_address=0x%x,status_control_address=0x%x,pattern=0x%x,mask=0x%x,timeout=%f)"%
(status_address,status_control_address,pattern,mask,timeout))
print ("last read status data is 0x%x"%(data))
return 0
return 1
def read_all_status(self):
"""
......@@ -123,17 +140,17 @@ class X393AxiControlStatus(object):
# for name in self.__dict__:
# print (name+": "+str(name=='MCONTR_PHY_STATUS_REG_ADDR'))
# print (self.__dict__['MCONTR_PHY_STATUS_REG_ADDR'])
print ("MCONTR_PHY_STATUS_REG_ADDR: %s"%(hx(self.read_and_wait_status(self.MCONTR_PHY_STATUS_REG_ADDR))))
print ("MCONTR_TOP_STATUS_REG_ADDR: %s"%(hx(self.read_and_wait_status(self.MCONTR_TOP_STATUS_REG_ADDR))))
print ("MCNTRL_PS_STATUS_REG_ADDR: %s"%(hx(self.read_and_wait_status(self.MCNTRL_PS_STATUS_REG_ADDR))))
print ("MCNTRL_SCANLINE_STATUS_REG_CHN1_ADDR:%s"%(hx(self.read_and_wait_status(self.MCNTRL_SCANLINE_STATUS_REG_CHN1_ADDR))))
print ("MCNTRL_SCANLINE_STATUS_REG_CHN3_ADDR:%s"%(hx(self.read_and_wait_status(self.MCNTRL_SCANLINE_STATUS_REG_CHN3_ADDR))))
print ("MCNTRL_TILED_STATUS_REG_CHN2_ADDR: %s"%(hx(self.read_and_wait_status(self.MCNTRL_TILED_STATUS_REG_CHN2_ADDR))))
print ("MCNTRL_TILED_STATUS_REG_CHN4_ADDR: %s"%(hx(self.read_and_wait_status(self.MCNTRL_TILED_STATUS_REG_CHN4_ADDR))))
print ("MCNTRL_TEST01_STATUS_REG_CHN1_ADDR: %s"%(hx(self.read_and_wait_status(self.MCNTRL_TEST01_STATUS_REG_CHN1_ADDR))))
print ("MCNTRL_TEST01_STATUS_REG_CHN2_ADDR: %s"%(hx(self.read_and_wait_status(self.MCNTRL_TEST01_STATUS_REG_CHN2_ADDR))))
print ("MCNTRL_TEST01_STATUS_REG_CHN3_ADDR: %s"%(hx(self.read_and_wait_status(self.MCNTRL_TEST01_STATUS_REG_CHN3_ADDR))))
print ("MCNTRL_TEST01_STATUS_REG_CHN4_ADDR: %s"%(hx(self.read_and_wait_status(self.MCNTRL_TEST01_STATUS_REG_CHN4_ADDR))))
print ("MCONTR_PHY_STATUS_REG_ADDR: %s"%(hx(self.read_status(self.MCONTR_PHY_STATUS_REG_ADDR))))
print ("MCONTR_TOP_STATUS_REG_ADDR: %s"%(hx(self.read_status(self.MCONTR_TOP_STATUS_REG_ADDR))))
print ("MCNTRL_PS_STATUS_REG_ADDR: %s"%(hx(self.read_status(self.MCNTRL_PS_STATUS_REG_ADDR))))
print ("MCNTRL_SCANLINE_STATUS_REG_CHN1_ADDR:%s"%(hx(self.read_status(self.MCNTRL_SCANLINE_STATUS_REG_CHN1_ADDR))))
print ("MCNTRL_SCANLINE_STATUS_REG_CHN3_ADDR:%s"%(hx(self.read_status(self.MCNTRL_SCANLINE_STATUS_REG_CHN3_ADDR))))
print ("MCNTRL_TILED_STATUS_REG_CHN2_ADDR: %s"%(hx(self.read_status(self.MCNTRL_TILED_STATUS_REG_CHN2_ADDR))))
print ("MCNTRL_TILED_STATUS_REG_CHN4_ADDR: %s"%(hx(self.read_status(self.MCNTRL_TILED_STATUS_REG_CHN4_ADDR))))
print ("MCNTRL_TEST01_STATUS_REG_CHN1_ADDR: %s"%(hx(self.read_status(self.MCNTRL_TEST01_STATUS_REG_CHN1_ADDR))))
print ("MCNTRL_TEST01_STATUS_REG_CHN2_ADDR: %s"%(hx(self.read_status(self.MCNTRL_TEST01_STATUS_REG_CHN2_ADDR))))
print ("MCNTRL_TEST01_STATUS_REG_CHN3_ADDR: %s"%(hx(self.read_status(self.MCNTRL_TEST01_STATUS_REG_CHN3_ADDR))))
print ("MCNTRL_TEST01_STATUS_REG_CHN4_ADDR: %s"%(hx(self.read_status(self.MCNTRL_TEST01_STATUS_REG_CHN4_ADDR))))
def program_status(self,
base_addr, # input [29:0] base_addr;
......
......@@ -116,22 +116,31 @@ class X393McntrlTests(object):
set_per_pin_delays=0):
"""
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
status generation
write buffer latency
<set_per_pin_delays> - 1 - set individual (per-pin) I/O delays, 0 - use common for the whole class
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.)
self.x393_mcntrl_timing.axi_set_dqs_dqm_patterns()
# prepare all sequences
self.set_all_sequences;
self.set_all_sequences()
# prepare write buffer
self.x393_mcntrl_buffers.write_block_buf_chn(0,0,256); # fill block memory (channel, page, number)
# set all delays
......@@ -149,11 +158,14 @@ class X393McntrlTests(object):
# set clock phase relative to DDR clk
# print("Debugging: sleeping for 1 second")
# sleep(1)
self.x393_mcntrl_timing.axi_set_phase(self.DLY_PHASE);
# self.x393_axi_tasks.read_all_status()
#program status for all used modules to refresh at any bit change
self.x393_axi_tasks.program_status_all(3, 0)
phaseOK=self.x393_mcntrl_timing.axi_set_phase(self.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(self.WBUF_DLY_DFLT)
self.x393_axi_tasks.read_all_status()
return 1
def set_all_sequences(self):
"""
......@@ -182,6 +194,50 @@ class X393McntrlTests(object):
0x1234, # 15'h1234, # row address
0x100 # 10'h100 # column address
)
def init_ddr3(self):
"""
Enable address/command pins, remove SDRST, enable CKE,
Setup PS PIO
Set DDR3 MR0..MR3 registers
"""
"""
// enable output for address/commands to DDR chip
enable_cmda(1);
repeat (16) @(posedge CLK) ;
// remove reset from DDR chip
activate_sdrst(0); // was enabled at system reset
#5000; // actually 500 usec required
repeat (16) @(posedge CLK) ;
enable_cke(1);
repeat (16) @(posedge CLK) ;
// enable_memcntrl(1); // enable memory controller
enable_memcntrl_channels(16'h0003); // only channel 0 and 1 are enabled
configure_channel_priority(0,0); // lowest priority channel 0
configure_channel_priority(1,0); // lowest priority channel 1
enable_reset_ps_pio(1,0); // enable, no reset
// set MR registers in DDR3 memory, run DCI calibration (long)
wait_ps_pio_ready(DEFAULT_STATUS_MODE, 1); // wait FIFO not half full
schedule_ps_pio ( // schedule software-control memory operation (may need to check FIFO status first)
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
`PS_PIO_WAIT_COMPLETE );// wait_complete; // Do not request a newe transaction from the scheduler until previous memory transaction is finished
`ifdef WAIT_MRS
wait_ps_pio_done(DEFAULT_STATUS_MODE, 1);
`else
repeat (32) @(posedge CLK) ; // what delay is needed to be sure? Add to PS_PIO?
// first refreshes will be fast (accummulated while waiting)
`endif
enable_refresh(1);
axi_set_dqs_odelay('h78); //??? dafaults - wrong?
"""
def test_write_levelling(self,
wait_complete, # Wait for operation to complete
......
......@@ -51,6 +51,51 @@ class X393McntrlTiming(object):
self.x393_mem=X393Mem(debug_mode,dry_mode)
self.x393_axi_tasks=X393AxiControlStatus(debug_mode,dry_mode)
self.__dict__.update(VerilogParameters.__dict__["_VerilogParameters__shared_state"]) # Add verilog parameters to the class namespace
def axi_set_phase(self,
phase, # input [PHASE_WIDTH-1:0] phase;
wait_phase_en=True,
wait_seq=False):
"""
Set clock phase
<phase> 8-bit clock phase value
<wait_phase_en> compare phase shift to programmed (will not work if the program was restarted)
<wait_seq> read and re-send status request to make sure status reflects new data (just for testing, too fast for Python)
Returns 1 if success, 0 if timeout (or no wait was performed)
"""
if self.DEBUG_MODE > 1:
print("SET CLOCK PHASE=0x%x"%phase)
self.x393_axi_tasks.write_contol_register(self.LD_DLY_PHASE, phase & ((1<<self.PHASE_WIDTH)-1)) # {{(32-PHASE_WIDTH){1'b0}},phase}); // control regiter address
self.x393_axi_tasks.write_contol_register(self.DLY_SET,0)
self.target_phase = phase
if wait_phase_en:
return self.wait_phase(True, wait_seq)
return 0
def wait_phase(self,
check_phase_value=True,
wait_seq=False):
"""
Wait for the phase shifter
<check_phase_value> compare phase shift to programmed (will not work if the program was restarted)
<wait_seq> read and re-send status request to make sure status reflects new data (just for testing, too fast for Python)
Returns 1 if success, 0 if timeout
"""
patt = 0x3000000 | self.target_phase
mask = 0x3000100
if check_phase_value:
mask |= 0xff
return self.x393_axi_tasks.wait_status_condition(
self.MCONTR_PHY_STATUS_REG_ADDR, # status_address,
self.MCONTR_PHY_16BIT_ADDR + self.MCONTR_PHY_STATUS_CNTRL, # status_control_address,
3, # status_mode,
patt, # pattern,
mask, # mask
0, # invert_match
wait_seq, # wait_seq;
1.0) # maximal timeout (0 - no timeout)
def get_target_phase(self):
"""
Returns previously set clock phase value
......@@ -210,25 +255,13 @@ class X393McntrlTiming(object):
for i in range(0,number): # (i=0;i<number;i=i+1) begin
self.x393_axi_tasks.write_contol_register(reg_addr + i, delay) # {24'b0,delay}); // control register address
def axi_set_phase(self,
phase): # input [PHASE_WIDTH-1:0] phase;
"""
Set clock phase
<phase> 8-bit clock phase value
"""
if self.DEBUG_MODE > 1:
print("SET CLOCK PHASE=0x%x"%phase)
self.x393_axi_tasks.write_contol_register(self.LD_DLY_PHASE, phase & ((1<<self.PHASE_WIDTH)-1)) # {{(32-PHASE_WIDTH){1'b0}},phase}); // control regiter address
self.x393_axi_tasks.write_contol_register(self.DLY_SET,0)
self.target_phase = phase
def wait_phase_shifter_ready(self):
"""
Wait until clock phase shifter is ready
"""
data=self.x393_axi_tasks.read_and_wait_status(self.MCONTR_PHY_STATUS_REG_ADDR)
data=self.x393_axi_tasks.read_status(self.MCONTR_PHY_STATUS_REG_ADDR)
while (((data & self.STATUS_PSHIFTER_RDY_MASK) == 0) or (((data ^ self.target_phase) & 0xff) != 0)):
data=self.x393_axi_tasks.read_and_wait_status(self.MCONTR_PHY_STATUS_REG_ADDR)
data=self.x393_axi_tasks.read_status(self.MCONTR_PHY_STATUS_REG_ADDR)
if self.DRY_MODE: break
def axi_set_wbuf_delay(self,
......
......@@ -107,7 +107,8 @@ class X393PIOSequences(object):
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
sync_seq, # input sync_seq; // synchronize sequences
timeout=2.0): # maximal timeout in seconds
"""
Wait PS PIO module has no pending/running memory transaction
<mode> status mode (0..3) - see 'help program_status'
......@@ -120,7 +121,8 @@ class X393PIOSequences(object):
0,
3 << self.STATUS_2LSB_SHFT,
0,
sync_seq)
sync_seq,
timeout)
'''
x393_mcontr_encode_cmd
'''
......@@ -355,7 +357,7 @@ class X393PIOSequences(object):
(al,2), # al[1:0], # MR1.4_3
(rtt,1), # rtt[0], # MR1.2
(ods,1), # ods[0], # MR1.1
(dll)))[0] #dll}; # MR1.0
(dll,1)))[0] #dll}; # MR1.0
def func_ddr3_mr2(self, # ; function [ADDRESS_NUMBER+2:0]
rtt_wr, # input [1:0] rtt_wr; # Dynamic ODT :
......@@ -415,7 +417,7 @@ class X393PIOSequences(object):
"""
return concat((
(3,3), # 3'h3,
(0,self.ADDRESS_NUMBER), # {ADDRESS_NUMBER-3{1'b0}},
(0,self.ADDRESS_NUMBER-3), # {ADDRESS_NUMBER-3{1'b0}},
(mpr, 1), # mpr, # MR3.2
(mpr_rf,2)))[0] # mpr_rf[1:0]}; # MR3.1_0
......@@ -617,7 +619,7 @@ class X393PIOSequences(object):
self.x393_mem.axi_write_single_w(cmd_addr, data)
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
data=self.func_encode_skip( 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)# tMOD
self.x393_mem.axi_write_single_w(cmd_addr, data)
cmd_addr += 1
# first read
......@@ -820,10 +822,10 @@ class X393PIOSequences(object):
0) # 2'h0); # [1:0] mpr_rf; # MPR read function: 2'b00: predefined pattern 0101...
cmd_addr = self.MCONTR_CMD_WR_ADDR + self.INITIALIZE_OFFSET;
if self.DEBUG_MODE > 1:
print("mr0=0x%x", mr0);
print("mr1=0x%x", mr1);
print("mr2=0x%x", mr2);
print("mr3=0x%x", mr3);
print("mr0=0x%05x"%mr0);
print("mr1=0x%05x"%mr1);
print("mr2=0x%05x"%mr2);
print("mr3=0x%05x"%mr3);
# 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)
self.x393_mem.axi_write_single_w(cmd_addr, data)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment