From 9b43bdd6250001816735fcf9802dccb06551a11c Mon Sep 17 00:00:00 2001 From: Andrey Filippov Date: Tue, 14 Apr 2015 01:23:59 -0600 Subject: [PATCH] Cleaning up the code, adding provisions for multiple solutions for the same phase - this will be the case at higher clock frequencies --- py393/get_test_dq_dqs_data.py | 193 ++- py393/vrlg.py | 1 + py393/x393_lma.py | 250 +++- py393/x393_mcntrl_adjust.py | 2516 +++++++++++++++++++++++++-------- py393/x393_mcntrl_timing.py | 11 +- 5 files changed, 2301 insertions(+), 670 deletions(-) diff --git a/py393/get_test_dq_dqs_data.py b/py393/get_test_dq_dqs_data.py index eb9e108..8320fe7 100644 --- a/py393/get_test_dq_dqs_data.py +++ b/py393/get_test_dq_dqs_data.py @@ -892,6 +892,59 @@ def get_adjust_cmda_odelay(): 'cmda_odly_a':-1.40105743313 } + +def get_wlev_dqs_delays(variant=0): + if variant ==0: # large step + return [[(130, None), (125, None)], [(133, 0.09375), (129, -0.75)], [(130, 0.5625), (128, -0.0625)], [(125, None), (125, 0.5)], [(129, -0.28125), (120, None)], + [(126, 0.375), (124, 0.3125)], [(125, 0.875), (121, 0.4375)], [(124, -0.8125), (115, None)], [(123, 0.375), (119, -0.96875)], [(120, 0.125), (119, 0.25)], + [(115, None), (115, 0.0)], [(119, 0.21875), (114, -0.96875)], [(115, -0.1875), (114, -0.5625)], [(115, 0.9375), (113, -0.03125)], [(114, -0.875), (105, None)], + [(112, 0.5625), (109, -0.84375)], [(110, 0.875), (107, 0.0)], [(109, -0.96875), (105, 0.8125)], [(107, 0.0), (104, -0.96875)], [(105, 0.625), (103, -0.5)], + [(100, None), (100, -0.3125)], [(102, -0.15625), (95, None)], [(100, 0.625), (99, 0.0625)], [(95, None), (96, 0.25)], [(99, -0.1875), (90, None)], + [(96, 0.5), (94, -0.90625)], [(95, 0.84375), (92, -0.0625)], [(90, None), (90, -0.125)], [(93, 0.375), (85, None)], [(90, 0.5), (89, -0.5)], + [(85, None), (86, 0.09375)], [(88, -0.3125), (80, None)], [(85, 0.5), (84, -0.78125)], [(80, None), (81, -0.09375)], [(84, -0.875), (80, 0.53125)], + [(80, 0.78125), (79, -0.1875)], [(75, None), (78, -0.1875)], [(75, None), (75, 0.0)], [(77, -0.46875), (70, None)], [(75, 0.75), (74, -0.28125)], + [(70, None), (70, -0.53125)], [(74, -0.6875), (70, 0.9375)], [(73, -0.25), (65, None)], [(70, 0.5), (69, -0.8125)], [(65, None), (68, 0.21875)], + [(69, -0.625), (65, 0.90625)], [(65, 0.0625), (60, None)], [(60, None), (61, 0.09375)], [(60, None), (60, 0.5)], [(55, None), (57, -0.5)], + [(55, None), (55, -0.25)], [(59, 0.28125), (50, None)], [(55, 0.125), (50, None)], [(50, None), (51, -0.28125)], [(50, None), (50, 0.84375)], + [(53, 0.25), (45, None)], [(45, None), (46, 0.0)], [(45, None), (45, 0.3125)], [(47, 0.1875), (40, None)], [(45, 0.78125), (44, -0.1875)], + [(40, None), (40, -0.1875)], [(44, 0.21875), (35, None)], [(41, 0.53125), (35, None)], [(35, None), (36, 0.375)], [(35, None), (35, 0.46875)], + [(38, 0.53125), (30, None)], [(35, 0.65625), (34, -0.96875)], [(30, None), (33, 0.03125)], [(30, None), (30, 0.4375)], [(33, 0.5), (25, None)], + [(25, None), (29, 0.125)], [(25, None), (26, 0.3125)], [(28, 0.5), (20, None)], [(25, 0.5625), (20, None)], [(20, None), (22, 0.03125)], + [(23, 0.5), (15, None)], [(20, 0.5), (15, None)], [(15, None), (17, 0.03125)], [(19, 0.5), (15, 0.0625)], [(16, 0.5), (10, None)], + [(10, None), (14, -0.96875)], [(10, None), (11, 0.03125)], [(13, 0.0625), (10, 0.5625)], [(11, 0.5), (5, None)], [(5, None), (7, -0.21875)], + [(9, -0.375), (5, 0.0)], [(6, 0.5), (0, None)], [(0, None), (2, -0.9375)], None, None, None, None, None, None, None, None, None, None, None, None, + [(150, None), (150, 0.5625)], [(153, -0.9375), (145, None)], [(151, 0.40625), (148, 0.03125)], [(145, None), (145, 0.15625)], [(145, None), (140, None)], + [(145, 0.9375), (140, 0.28125)], [(140, None), (135, None)], [(143, 0.25), (139, -0.4375)], [(140, 0.75), (136, 0.25)], [(135, None), (135, 0.9375)], + [(139, 0.75), (130, None)], [(136, 0.4375), (134, 0.53125)]] + elif variant == 1: #small step + return [[(134, -0.9375), (129, None)], [(133, 0.25), (129, -0.71875)], [(130, 0.46875), (128, 0.0)], [(129, None), (125, 0.6875)], [(129, 0.0), (124, None)], + [(125, -0.03125), (124, 0.125)], [(125, 0.84375), (121, 0.09375)], [(124, -0.53125), (119, None)], [(123, 0.3125), (119, None)], [(120, 0.46875), (119, 0.15625)], + [(119, None), (115, 0.0625)], [(119, 0.46875), (114, None)], [(115, 0.4375), (114, -0.4375)], [(115, 0.84375), (112, 0.1875)], [(114, -0.75), (109, None)], + [(112, 0.5), (109, -0.90625)], [(110, 0.84375), (107, 0.34375)], [(109, None), (105, 0.90625)], [(107, 0.28125), (104, None)], [(105, 0.65625), (103, -0.46875)], + [(104, None), (100, 0.0)], [(102, 0.5), (99, -0.96875)], [(100, 0.65625), (99, 0.09375)], [(99, None), (95, -0.65625)], [(99, 0.375), (94, None)], + [(96, 0.5), (94, -0.96875)], [(95, 0.6875), (93, -0.46875)], [(94, None), (90, -0.25)], [(92, 0.21875), (89, None)], [(90, 0.53125), (89, -0.78125)], + [(89, None), (86, 0.03125)], [(88, 0.09375), (84, None)], [(85, 0.53125), (84, -0.90625)], [(84, None), (81, -0.15625)], [(84, -0.875), (80, 0.40625)], + [(80, 0.8125), (79, -0.8125)], [(79, None), (78, 0.0625)], [(79, -0.875), (75, 0.28125)], [(77, -0.03125), (74, None)], [(75, 0.8125), (74, 0.125)], + [(74, None), (71, 0.34375)], [(74, -0.65625), (69, None)], [(73, 0.5), (69, None)], [(70, 0.21875), (69, None)], [(69, None), (67, 0.375)], + [(69, 0.15625), (65, 0.96875)], [(65, 0.0625), (64, -0.875)], [(64, None), (61, -0.0625)], [(64, None), (60, 0.46875)], [(59, None), (59, 0.5)], + [(59, None), (55, -0.0625)], [(59, 0.21875), (54, None)], [(55, 0.3125), (54, -0.9375)], [(54, None), (51, 0.125)], [(54, None), (49, None)], + [(53, 0.5), (49, None)], [(49, None), (46, -0.09375)], [(49, None), (45, 0.34375)], [(47, 0.1875), (44, None)], [(45, 0.84375), (44, -0.09375)], + [(44, None), (40, -0.375)], [(44, 0.375), (39, None)], [(41, 0.5), (39, None)], [(39, None), (36, 0.40625)], [(39, None), (35, 0.0)], [(37, 0.0), (34, None)], + [(35, 0.53125), (34, None)], [(34, None), (33, 0.0)], [(34, None), (30, 0.28125)], [(33, 0.5), (29, None)], [(30, 0.96875), (29, 0.03125)], + [(29, None), (26, 0.125)], [(28, 0.5), (24, None)], [(25, 0.71875), (24, None)], [(24, None), (22, 0.03125)], [(23, 0.53125), (20, 0.96875)], + [(20, 0.40625), (19, None)], [(19, None), (17, 0.0)], [(19, 0.125), (15, 0.15625)], [(16, 0.5), (14, None)], [(14, None), (14, -0.84375)], + [(14, None), (11, -0.09375)], [(13, 0.03125), (10, 0.78125)], [(11, 0.53125), (9, None)], [(9, None), (8, -0.28125)], [(9, -0.46875), (5, 0.03125)], + [(6, 0.5), (4, None)], [(4, None), (4, 0.125)], None, None, None, None, None, None, None, None, None, None, None, None, [(154, None), (150, 0.21875)], + [(154, -0.875), (149, None)], [(150, -0.6875), (148, -0.15625)], [(149, None), (145, 0.46875)], [(149, None), (144, None)], [(145, 0.96875), (140, 0.40625)], + [(144, None), (139, None)], [(142, -0.375), (139, -0.6875)], [(140, 0.5), (135, -0.3125)], [(139, None), (134, None)], [(139, 0.0), (134, None)], + [(135, -0.5), (134, 0.375)]] + +def get_wlev_dqs_steps(variant=0): + if variant == 0: + return 1 + elif variant ==1: + return 0 + def get_wlev_data(): return { 'wlev_dqs_odly_b':[52.119267926792674, 49.885802580258002], @@ -1399,6 +1452,7 @@ def get_addr_meas(): [124, 131, 128, 127, 129, 129, 129, 124, 129, 134, 129, 129, 124, 129, 129, 124, 130, 127]] , ] def get_addr_odly(): + print("**** OBSOLETE *****") return { 'dlys': [[46, 49, 48, 47, 48, 49, 48, 45, 49, 50, 48, 48, 45, 48, 48, 46, 49, 48, 50, 49, 49, 48], [45, 48, 46, 45, 46, 48, 45, 44, 47, 49, 45, 46, 44, 46, 45, 45, 48, 46, 49, 48, 48, 46], [44, 45, 44, 44, 44, 46, 44, 43, 45, 48, 44, 44, 43, 44, 44, 44, 46, 44, 48, 46, 45, 45], [43, 44, 44, 43, 44, 44, 44, 41, 44, 45, 44, 44, 41, 44, 44, 43, 44, 44, 45, 44, 44, 44], @@ -1508,4 +1562,141 @@ def get_cmda_parameters(): 'tA': [2014.335618035371, 2022.0831903592677, 2025.482966498, 2000.1256204889644, 2017.3513081600333, 2054.856921634421, 1998.5668161398096, 1991.5152458814302, 2013.552541418718, 2035.4497883071335, 2012.5914774537146, 2013.8664966165068, 1995.7738477106127, 2021.1313354266506, 2005.8702139359314, 2014.6518090648067, 2025.5963222621444, 2025.7326063296766, 2030.5864502298764, 2024.5266464332833, 2039.6076080635871, 2018.250230021426]} - \ No newline at end of file +def get_cmda_odelay(): + return { +'dlys': [{0: [46, 49, 48, 47, 48, 49, 48, 45, 48, 50, 48, 48, 45, 48, 48, 46, 49, 48, 50, 49, 49, 48]}, + {0: [45, 48, 46, 45, 46, 48, 46, 44, 47, 49, 45, 46, 44, 46, 46, 45, 48, 46, 49, 48, 48, 46]}, + {0: [44, 45, 44, 44, 44, 45, 44, 43, 45, 48, 44, 45, 43, 44, 44, 44, 46, 44, 48, 45, 45, 45]}, + {0: [43, 44, 44, 43, 44, 44, 44, 41, 44, 45, 43, 44, 41, 44, 44, 43, 44, 44, 45, 44, 44, 44]}, + {0: [40, 44, 43, 40, 43, 44, 43, 39, 43, 44, 42, 43, 39, 43, 43, 40, 44, 43, 44, 44, 43, 43]}, + {0: [39, 43, 40, 39, 40, 43, 40, 39, 40, 43, 40, 40, 39, 40, 40, 39, 43, 40, 44, 42, 42, 40]}, + {0: [39, 40, 39, 39, 39, 40, 39, 38, 39, 42, 39, 39, 38, 39, 39, 39, 40, 39, 42, 40, 40, 39]}, + {0: [37, 39, 38, 37, 38, 39, 38, 35, 38, 40, 38, 38, 35, 38, 38, 38, 39, 38, 40, 39, 39, 38]}, + {0: [35, 38, 37, 35, 37, 38, 36, 34, 37, 39, 36, 37, 34, 37, 36, 35, 38, 37, 39, 38, 38, 37]}, + {0: [34, 36, 35, 34, 35, 37, 35, 33, 35, 38, 34, 35, 33, 35, 34, 34, 36, 35, 38, 35, 35, 35]}, + {0: [33, 34, 34, 33, 34, 35, 34, 32, 34, 35, 34, 34, 32, 34, 34, 33, 34, 34, 35, 34, 34, 34]}, + {0: [32, 34, 33, 31, 33, 34, 33, 30, 33, 34, 33, 33, 30, 33, 33, 32, 34, 33, 34, 34, 34, 33]}, + {0: [30, 33, 31, 30, 30, 33, 30, 29, 30, 33, 30, 31, 29, 31, 30, 30, 33, 30, 33, 32, 33, 30]}, + {0: [29, 30, 29, 29, 29, 30, 29, 28, 29, 32, 29, 29, 28, 29, 29, 29, 30, 29, 32, 30, 30, 29]}, + {0: [28, 29, 29, 28, 29, 29, 28, 26, 29, 30, 28, 29, 26, 29, 28, 28, 29, 29, 30, 29, 29, 29]}, + {0: [25, 28, 28, 25, 27, 29, 27, 24, 27, 29, 27, 28, 25, 28, 27, 26, 28, 28, 29, 28, 28, 28]}, + {0: [24, 26, 25, 24, 25, 28, 25, 24, 25, 28, 25, 25, 24, 25, 25, 24, 26, 25, 28, 26, 26, 25]}, + {0: [24, 25, 24, 23, 24, 25, 24, 23, 24, 25, 24, 24, 23, 24, 24, 24, 25, 24, 25, 24, 25, 24]}, + {0: [23, 24, 23, 22, 23, 24, 23, 20, 23, 24, 23, 23, 20, 23, 23, 23, 24, 23, 24, 24, 24, 23]}, + {0: [20, 23, 22, 20, 21, 23, 20, 19, 21, 23, 20, 21, 19, 22, 20, 20, 23, 22, 23, 23, 23, 21]}, + {0: [19, 20, 20, 19, 19, 22, 19, 18, 19, 22, 19, 20, 19, 20, 19, 19, 20, 20, 22, 20, 20, 20]}, + {0: [18, 19, 19, 18, 19, 20, 18, 17, 19, 20, 18, 19, 17, 19, 19, 18, 19, 19, 20, 19, 19, 19]}, + {0: [17, 18, 18, 16, 18, 19, 17, 15, 18, 19, 17, 18, 15, 18, 17, 17, 18, 18, 19, 18, 19, 18]}, + {0: [15, 17, 16, 14, 15, 18, 15, 14, 15, 18, 15, 15, 14, 15, 15, 15, 17, 15, 18, 16, 17, 15]}, + {0: [14, 15, 14, 14, 14, 16, 14, 13, 14, 15, 14, 14, 13, 14, 14, 14, 15, 14, 15, 14, 15, 14]}, + {0: [13, 14, 14, 13, 13, 14, 13, 11, 13, 14, 13, 13, 11, 14, 13, 13, 14, 14, 14, 14, 14, 13]}, + {0: [11, 13, 13, 10, 12, 14, 10, 9, 11, 13, 11, 12, 10, 12, 11, 11, 13, 12, 13, 13, 13, 12]}, + {0: [9, 10, 10, 9, 10, 13, 9, 9, 9, 12, 9, 10, 9, 10, 9, 10, 10, 10, 11, 10, 11, 10]}, + {0: [9, 9, 9, 8, 9, 10, 9, 8, 9, 10, 9, 9, 8, 9, 9, 9, 9, 9, 10, 9, 10, 9], -1: [159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159]}, + {0: [8, 8, 8, 7, 8, 9, 7, 5, 8, 9, 8, 8, 5, 8, 8, 8, 9, 8, 9, 8, 9, 8], -1: [159, 159, 159, 159, 159, 159, 159, 158, 159, 159, 159, 159, 158, 159, 159, 159, 159, 159, 159, 159, 159, 159]}, + {0: [5, 7, 7, 5, 5, 8, 5, 4, 5, 8, 5, 6, 4, 6, 5, 5, 7, 6, 8, 6, 8, 6], -1: [158, 159, 159, 159, 159, 159, 159, 157, 159, 159, 159, 159, 156, 159, 159, 158, 159, 159, 159, 159, 159, 159]}, + {0: [4, 5, 5, 4, 4, 7, 4, 3, 4, 5, 4, 4, 4, 5, 4, 4, 5, 5, 5, 5, 5, 4], -1: [155, 159, 159, 158, 159, 159, 159, 155, 159, 159, 159, 159, 154, 159, 159, 155, 159, 159, 159, 159, 159, 159]}, + {0: [3, 4, 4, 3, 4, 5, 3, 2, 3, 4, 3, 4, 3, 4, 3, 4, 4, 4, 4, 4, 4, 4], -1: [154, 159, 158, 157, 159, 158, 159, 154, 159, 159, 159, 159, 154, 158, 159, 154, 159, 158, 159, 159, 158, 159]}, + {0: [2, 3, 3, 1, 3, 4, 1, 0, 1, 4, 2, 3, 0, 3, 1, 2, 3, 3, 3, 3, 4, 3], -1: [153, 159, 155, 155, 158, 155, 159, 153, 159, 159, 157, 158, 153, 157, 158, 153, 159, 155, 159, 159, 157, 158]}, + {0: [0, 0, 0, 0, 0, 3, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0], -1: [152, 159, 154, 154, 155, 154, 158, 151, 159, 159, 155, 156, 150, 155, 157, 152, 159, 154, 159, 159, 155, 155]}, + {0: [0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], -1: [150, 158, 153, 153, 154, 154, 155, 149, 157, 159, 154, 154, 149, 154, 155, 150, 158, 153, 159, 158, 154, 154]}, + {0: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], -1: [149, 155, 152, 150, 153, 152, 154, 149, 155, 158, 153, 154, 148, 153, 154, 149, 155, 152, 159, 155, 153, 153]}, + {0: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], -1: [148, 154, 150, 149, 151, 150, 154, 148, 154, 156, 151, 153, 147, 150, 153, 148, 154, 150, 159, 154, 151, 152]}, + {0: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], -1: [146, 154, 149, 149, 150, 149, 152, 145, 153, 154, 149, 150, 145, 149, 150, 146, 154, 149, 158, 154, 149, 150]}, + {0: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], -1: [145, 152, 148, 147, 149, 148, 150, 144, 151, 154, 149, 149, 144, 149, 149, 145, 152, 148, 155, 152, 149, 149]}, + {0: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], -1: [144, 150, 146, 145, 148, 146, 149, 143, 149, 153, 148, 148, 143, 148, 149, 144, 150, 146, 154, 150, 148, 148]}, + {0: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], -1: [143, 149, 144, 144, 145, 145, 148, 142, 149, 150, 145, 146, 141, 145, 147, 143, 149, 144, 153, 149, 145, 145]}, + {-1: [140, 148, 144, 143, 144, 144, 146, 140, 148, 149, 144, 145, 140, 144, 145, 140, 148, 144, 151, 148, 144, 144]}, + {-1: [139, 146, 143, 141, 143, 143, 144, 139, 145, 148, 143, 144, 139, 143, 144, 139, 145, 143, 149, 146, 143, 144]}, + {-1: [139, 144, 140, 140, 142, 140, 144, 138, 144, 146, 142, 143, 138, 141, 143, 139, 144, 140, 149, 144, 142, 143]}, + {-1: [137, 144, 139, 139, 140, 139, 143, 136, 143, 145, 140, 140, 135, 140, 141, 137, 144, 139, 148, 144, 140, 140]}, + {-1: [135, 143, 138, 138, 139, 139, 140, 134, 141, 144, 139, 139, 134, 139, 139, 135, 143, 138, 145, 143, 139, 139]}, + {-1: [134, 140, 137, 135, 138, 138, 139, 134, 139, 143, 138, 138, 134, 138, 139, 134, 140, 137, 144, 140, 138, 138]}, + {-1: [133, 139, 135, 134, 136, 135, 138, 133, 139, 140, 135, 137, 132, 135, 138, 133, 139, 135, 143, 139, 136, 136]}, + {-1: [132, 138, 134, 133, 134, 134, 136, 130, 138, 139, 134, 135, 130, 134, 135, 132, 138, 134, 141, 138, 134, 135]}, + {-1: [130, 136, 133, 132, 134, 133, 135, 129, 135, 138, 134, 134, 129, 134, 134, 130, 136, 133, 139, 136, 134, 134]}, + {-1: [129, 134, 131, 130, 133, 132, 134, 128, 134, 137, 133, 133, 128, 132, 133, 129, 134, 131, 139, 134, 133, 133]}, + {-1: [128, 134, 129, 129, 130, 130, 133, 127, 133, 135, 130, 131, 126, 130, 131, 128, 134, 129, 138, 134, 130, 130]}, + {-1: [125, 133, 129, 128, 129, 129, 130, 125, 131, 134, 129, 129, 125, 129, 130, 125, 133, 129, 135, 133, 129, 129]}, + {-1: [124, 130, 128, 126, 128, 128, 129, 124, 130, 133, 128, 129, 124, 128, 129, 124, 130, 128, 134, 130, 128, 128]}, + {-1: [124, 129, 125, 124, 127, 125, 128, 123, 129, 130, 126, 128, 123, 126, 128, 124, 129, 125, 133, 129, 127, 127]}, + {-1: [123, 128, 124, 124, 125, 124, 127, 121, 128, 129, 125, 125, 120, 124, 125, 123, 128, 124, 131, 128, 125, 125]}, + {-1: [120, 126, 123, 123, 124, 124, 125, 119, 125, 128, 124, 124, 119, 124, 124, 120, 126, 123, 129, 126, 124, 124]}, + {-1: [119, 125, 122, 120, 123, 123, 124, 119, 124, 127, 123, 123, 119, 123, 123, 119, 125, 122, 129, 125, 123, 123]}, + {-1: [118, 124, 120, 119, 120, 120, 123, 118, 123, 125, 120, 121, 118, 120, 122, 118, 124, 120, 127, 124, 120, 121]}, + {-1: [117, 123, 119, 118, 119, 119, 120, 115, 122, 124, 119, 120, 115, 119, 120, 117, 123, 119, 125, 123, 119, 119]}, + {-1: [115, 120, 118, 117, 119, 118, 119, 114, 120, 123, 118, 119, 114, 118, 119, 115, 120, 118, 124, 120, 119, 119]}, + {-1: [114, 119, 115, 115, 117, 117, 118, 113, 119, 120, 117, 118, 113, 117, 118, 114, 119, 115, 123, 119, 118, 118]}, + {-1: [113, 118, 114, 114, 115, 115, 117, 112, 118, 119, 115, 115, 112, 115, 115, 113, 118, 114, 120, 118, 115, 115]}, + {-1: [111, 117, 114, 113, 114, 114, 115, 110, 115, 118, 114, 114, 110, 114, 114, 111, 117, 114, 119, 117, 114, 114]}, + {-1: [109, 115, 113, 111, 113, 113, 114, 109, 114, 117, 113, 113, 109, 113, 114, 109, 115, 113, 119, 115, 113, 113]}, + {-1: [109, 114, 110, 109, 111, 111, 113, 108, 113, 115, 110, 112, 108, 110, 112, 109, 114, 110, 117, 114, 112, 111]}, + {-1: [108, 113, 109, 109, 109, 109, 110, 106, 112, 114, 109, 110, 106, 109, 110, 108, 113, 109, 115, 113, 110, 110]}, + {-1: [105, 110, 108, 108, 109, 109, 109, 105, 110, 113, 109, 109, 104, 109, 109, 105, 110, 108, 114, 110, 109, 109]}, + {-1: [104, 109, 107, 105, 108, 108, 109, 104, 109, 110, 108, 108, 104, 108, 108, 104, 109, 107, 113, 109, 108, 108]}, + {-1: [103, 108, 105, 104, 105, 105, 107, 103, 108, 109, 105, 106, 103, 105, 106, 103, 108, 105, 110, 108, 105, 105]}, + {-1: [102, 107, 104, 103, 104, 104, 105, 100, 105, 109, 104, 104, 100, 104, 104, 102, 107, 104, 109, 107, 104, 104]}, + {-1: [100, 105, 103, 102, 103, 103, 104, 99, 104, 107, 103, 104, 99, 103, 104, 100, 105, 103, 108, 105, 104, 104]}, + {-1: [99, 104, 100, 100, 102, 102, 103, 99, 104, 105, 101, 103, 98, 101, 103, 99, 104, 100, 107, 104, 102, 102]}, + {-1: [98, 103, 99, 99, 100, 100, 101, 97, 102, 104, 100, 100, 97, 100, 100, 98, 103, 99, 105, 103, 100, 100]}, + {-1: [96, 100, 99, 98, 99, 99, 99, 95, 100, 103, 99, 99, 95, 99, 99, 96, 100, 99, 104, 100, 99, 99]}, + {-1: [95, 99, 98, 95, 98, 98, 99, 94, 99, 100, 98, 98, 94, 98, 98, 95, 99, 97, 103, 99, 98, 98]}, + {-1: [94, 99, 95, 94, 95, 96, 98, 93, 98, 99, 95, 96, 93, 95, 97, 94, 99, 95, 100, 99, 96, 96]}, + {-1: [93, 97, 94, 94, 94, 94, 95, 91, 95, 99, 94, 95, 91, 94, 95, 93, 97, 94, 99, 97, 95, 94]}, + {-1: [90, 95, 93, 92, 94, 94, 94, 90, 94, 97, 93, 94, 89, 94, 94, 90, 95, 93, 98, 95, 94, 94]}, + {-1: [89, 94, 91, 90, 93, 93, 93, 89, 94, 95, 92, 93, 89, 92, 93, 89, 94, 91, 97, 94, 93, 93]}, + {-1: [89, 93, 90, 89, 90, 90, 91, 88, 92, 94, 90, 90, 88, 90, 90, 89, 93, 90, 95, 93, 90, 90]}, + {-1: [87, 91, 89, 88, 89, 89, 89, 85, 90, 93, 89, 89, 85, 89, 89, 88, 91, 89, 94, 91, 89, 89]}, + {-1: [85, 89, 88, 86, 88, 88, 89, 84, 89, 90, 88, 88, 84, 88, 88, 85, 89, 88, 93, 89, 89, 88]}, + {-1: [84, 89, 85, 85, 86, 87, 88, 84, 88, 89, 86, 87, 83, 86, 87, 84, 89, 85, 90, 89, 87, 87]}, + {-1: [83, 88, 84, 84, 85, 85, 85, 82, 86, 89, 84, 85, 82, 84, 85, 83, 88, 84, 89, 88, 85, 85]}, + {-1: [82, 85, 84, 83, 84, 84, 84, 80, 84, 87, 84, 84, 80, 84, 84, 82, 85, 84, 88, 85, 84, 84]}, + {-1: [80, 84, 82, 80, 83, 83, 83, 79, 84, 85, 83, 83, 79, 83, 83, 80, 84, 82, 86, 84, 83, 83]}, + {-1: [79, 83, 80, 79, 80, 81, 82, 78, 83, 84, 80, 81, 78, 80, 80, 79, 83, 80, 85, 83, 81, 80]}, + {-1: [78, 81, 79, 78, 79, 79, 80, 76, 80, 83, 79, 79, 76, 79, 79, 78, 81, 79, 84, 81, 80, 79]}, + {-1: [75, 79, 78, 77, 78, 79, 79, 75, 79, 81, 78, 79, 75, 78, 79, 76, 79, 78, 83, 79, 79, 79]}, + {-1: [74, 79, 76, 75, 77, 78, 78, 74, 78, 79, 76, 78, 74, 77, 78, 74, 79, 76, 80, 79, 78, 77]}, + {-1: [74, 78, 75, 74, 75, 75, 75, 73, 76, 79, 75, 75, 73, 75, 75, 74, 78, 75, 79, 78, 75, 75]}, + {-1: [73, 75, 74, 73, 74, 74, 74, 70, 74, 78, 74, 74, 70, 74, 74, 73, 75, 74, 78, 75, 74, 74]}, + {-1: [70, 74, 73, 71, 73, 73, 73, 69, 74, 75, 73, 73, 69, 73, 73, 70, 74, 73, 76, 74, 73, 73]}, + {-1: [69, 73, 70, 69, 71, 72, 72, 69, 73, 74, 70, 71, 69, 71, 71, 69, 73, 70, 74, 73, 72, 71]}, + {-1: [68, 72, 69, 69, 69, 70, 70, 68, 70, 73, 69, 70, 68, 69, 69, 68, 72, 69, 74, 71, 70, 69]}, + {-1: [67, 70, 69, 68, 69, 69, 69, 65, 69, 71, 68, 69, 65, 69, 69, 67, 70, 68, 73, 70, 69, 69]}, + {-1: [65, 69, 67, 65, 68, 68, 68, 64, 68, 69, 67, 68, 64, 68, 68, 65, 69, 67, 70, 69, 68, 68]}, + {-1: [64, 68, 65, 64, 65, 66, 65, 63, 66, 69, 65, 65, 63, 65, 65, 64, 68, 65, 69, 68, 66, 65]}, + {-1: [63, 65, 64, 63, 64, 65, 64, 62, 65, 68, 64, 64, 62, 64, 64, 63, 65, 64, 68, 65, 64, 64]}, + {-1: [61, 64, 63, 62, 63, 64, 64, 60, 64, 65, 63, 63, 60, 63, 63, 61, 64, 63, 66, 64, 64, 63]}, + {-1: [59, 63, 61, 60, 61, 63, 62, 59, 63, 64, 61, 62, 59, 62, 62, 59, 63, 61, 64, 63, 63, 62]}, + {-1: [59, 62, 60, 59, 60, 60, 60, 58, 60, 63, 59, 60, 58, 60, 60, 59, 62, 59, 64, 62, 60, 60]}, + {-1: [58, 60, 59, 58, 59, 59, 59, 55, 59, 61, 59, 59, 55, 59, 59, 58, 60, 59, 63, 60, 59, 59]}, + {-1: [55, 59, 58, 56, 58, 59, 58, 54, 58, 59, 58, 58, 54, 58, 58, 55, 59, 58, 60, 59, 58, 58]}, + {-1: [54, 58, 55, 54, 55, 57, 55, 54, 57, 59, 55, 56, 54, 55, 55, 54, 58, 55, 59, 58, 57, 55]}, + {-1: [53, 55, 54, 54, 54, 55, 54, 53, 55, 58, 54, 54, 53, 54, 54, 54, 55, 54, 58, 55, 55, 54]}, + {-1: [52, 54, 53, 53, 54, 54, 54, 50, 54, 55, 53, 54, 50, 54, 53, 52, 54, 53, 56, 54, 54, 54]}, + {-1: [50, 54, 52, 50, 52, 53, 53, 49, 53, 54, 51, 53, 49, 52, 52, 50, 54, 52, 54, 53, 53, 52]}, + {-1: [49, 52, 50, 49, 50, 51, 50, 48, 50, 53, 50, 50, 48, 50, 50, 49, 52, 50, 54, 52, 51, 50]}, + {-1: [48, 50, 49, 48, 49, 50, 49, 47, 49, 51, 49, 49, 47, 49, 49, 48, 50, 49, 52, 50, 49, 49]}] , +'err': [{0: 13.81671034754726}, {0: 13.771469038723755}, {0: 14.340527380809972}, {0: 14.164584645161225}, {0: 14.179870115556541}, {0: 13.432773521664858}, + {0: 13.3566833724952}, {0: 14.390664706793272}, {0: 9.709949257904468}, {0: 14.378331292519688}, {0: 13.581005590479135}, {0: 12.284361804967448}, + {0: 13.744883867172295}, {0: 13.069265521537245}, {0: 12.948095405025088}, {0: 14.02335676260822}, {0: 12.788901745548783}, {0: 14.356338229244015}, + {0: 12.479472180202405}, {0: 13.05966158965421}, {0: 14.447252771454869}, {0: 14.616176623323012}, {0: 13.284252179533341}, {0: 13.320428707512901}, + {0: 13.828083387638953}, {0: 13.961453041428879}, {0: 14.434483095270862}, {0: 14.155562014516082}, {0: 13.621773270398254, -1: 193.69710272527527}, + {0: 14.135410406801002, -1: 171.37567415384638}, {0: 11.944276842146932, -1: 149.05424558241793}, {0: 14.670265752668596, -1: 126.73281701098949}, + {0: 14.235541468098885, -1: 104.41138843956105}, {0: 14.675487230752724, -1: 82.08995986813261}, {0: 29.055624070515652, -1: 59.76853129670371}, + {0: 51.37705264194409, -1: 37.44710272527527}, {0: 73.69848121337276, -1: 15.125674153846376}, {0: 96.01990978480143, -1: 12.325458563410393}, + {0: 118.34133835622987, -1: 14.236786310874777}, {0: 140.6627669276583, -1: 14.207693683545585}, {0: 162.98419549908698, -1: 13.65984427239664}, + {0: 185.30562407051565, -1: 13.560536133667483}, {-1: 14.297620103659483}, {-1: 13.829412301415232}, {-1: 13.710533168281472}, {-1: 13.286347636302253}, + {-1: 12.821762281056635}, {-1: 14.004133136291784}, {-1: 9.404038490873972}, {-1: 14.596070048842194}, {-1: 14.546608275830295}, {-1: 13.403412231999482}, + {-1: 12.216694920653026}, {-1: 13.382714580810898}, {-1: 13.948656237887462}, {-1: 13.560160527110838}, {-1: 14.296751164508805}, {-1: 13.862925497698143}, + {-1: 13.63882881579002}, {-1: 11.889989628702551}, {-1: 13.219880835126332}, {-1: 13.970514707628354}, {-1: 14.09870815509612}, {-1: 11.864068831077475}, + {-1: 13.590024300898676}, {-1: 13.75198732304716}, {-1: 12.797367218788622}, {-1: 13.42483346885092}, {-1: 14.382045933133213}, {-1: 13.199714247831253}, + {-1: 14.375940766531585}, {-1: 14.219509535919315}, {-1: 14.55629922099888}, {-1: 14.488771143817758}, {-1: 13.845159186347246}, {-1: 12.792416076802965}, + {-1: 13.931039565706214}, {-1: 13.444451538081921}, {-1: 13.249330703433316}, {-1: 14.24759723939951}, {-1: 12.788236240655351}, {-1: 13.516253899478215}, + {-1: 13.693473701950552}, {-1: 14.232298130985328}, {-1: 14.83706677922919}, {-1: 14.079110967730685}, {-1: 14.136257289816967}, {-1: 11.651025550468603}, + {-1: 13.429311988168593}, {-1: 14.569819221850139}, {-1: 14.363411528439883}, {-1: 11.942874143262088}, {-1: 14.445342077758596}, {-1: 12.934262137098358}, + {-1: 14.543709933431273}, {-1: 13.440294617312247}, {-1: 13.65979569157389}, {-1: 14.14668606893565}, {-1: 12.577856540548964}, {-1: 10.30006550464168}, + {-1: 14.055893653045587}, {-1: 14.073969932251202}, {-1: 14.428825281091122}, {-1: 14.187880101861538}, {-1: 12.25117775834633}, {-1: 13.974271255088752}, + {-1: 11.378383135418517}, {-1: 14.504429101537426}, {-1: 14.472180131938785}, {-1: 14.274908290143685}, {-1: 12.941975230024127}, {-1: 12.806753039948944}] +} + + \ No newline at end of file diff --git a/py393/vrlg.py b/py393/vrlg.py index dda1f45..8e2c2e6 100644 --- a/py393/vrlg.py +++ b/py393/vrlg.py @@ -29,6 +29,7 @@ __maintainer__ = "Andrey Filippov" __email__ = "andrey@elphel.com" __status__ = "Development" DEFAULTS={} +dqs_dqm_patt=None def init_vars(d): global DEFAULTS if d: diff --git a/py393/x393_lma.py b/py393/x393_lma.py index 28e8959..19e9b72 100644 --- a/py393/x393_lma.py +++ b/py393/x393_lma.py @@ -1625,17 +1625,44 @@ class X393LMA(object): s=if-ir+of-or d=ir-if+of-or """ - def lma_fit_dqsi_phase(self, + def lma_fit_dqs_phase(self, lane, # byte lane bin_size_ps, clk_period, - dqsi_dqi_parameters, + dqs_dq_parameters, + tSDQS, # use if dqs_dq_parameters are not available data_set, compare_prim_steps, scale_w, - numPhaseSteps, + numPhaseSteps, + maxDlyErr=200.0, # ps - trying multiple overlapping branches + fallingPhase=False, # output mode - delays decrease when phase increases + shiftFracPeriod=0.5, # measured data is marginal, shift optimal by half period quiet=1): -# print("++++++lma_fit_dqsi_phase(), quiet=",quiet) + """ + Calculate linear approximation for DQS-in or DQS-out vs. phase, crossing periods + @param lane byte lane to use (0,1 or 'all') + @param bin_size_ps histogram bin size in ps + @param clk_period clock period, in ps + @param dqs_dq_parameters dq{i,0} vs dqs[i,o} parameters or Null if not yet available (after write levelling) + used to get initial delay scale and fine delay correction + @param tSDQS delay in ps for one finedelay step - used only if dqs_dq_parameters are not available + @param data_set data set number for hard-coded debug data or -1 to use actual just measured results + @param compare_prim_steps if True input data was calibrated with primary delay steps, False - if with fine delay + That means that delay data is on average is either 2.5 or 0.5 lower than unbiased average + @param scale_w weight for samples that have "binary" data with full uncertainty of +/-2.5 or +/-0.5 steps + @param numPhaseSteps Total number of delay steps (currently 5*32 = 160) + @param maxDlyErr Made for testing multiple overlapping branches, maximal error in ps to keep the result branch + @param fallingPhase input data is decreasing with phase increasing (command/addresses, data output), False - increasing + as for DQS in /DQ in + @param shiftFracPeriod When measured data is marginal, not optimal, result needs to be shifted by this fraction of the period + Currently it should be 0.5 for input, 0.0 - for output + @param quiet=1): + """ + +# print("++++++lma_fit_dqs_phase(), quiet=",quiet) + phase_sign=(1,-1)[fallingPhase] + phase_add=(0,numPhaseSteps)[fallingPhase] def show_input_data(filtered): print(('unfiltered','filtered')[filtered]) for phase,d in enumerate(data_set): @@ -1648,7 +1675,7 @@ class X393LMA(object): dly+=halfStep # print ("%f %f"%(dly, dly-phase*phase_step/dbg_tSDQS[lane]), end=" ") # print ("%f %f"%(dly*dbg_tSDQS[lane]/phase_step, dly*dbg_tSDQS[lane]/phase_step-phase), end=" ") - print ("%f %f"%(dly*dbg_tSDQS[lane], dly*dbg_tSDQS[lane]-phase*phase_step), end=" ") + print ("%f %f"%(dly*dbg_tSDQS[lane], dly*dbg_tSDQS[lane]+(phase_add-phase)*phase_step), end=" ") else: print ("? ?", end=" ") print() @@ -1660,7 +1687,7 @@ class X393LMA(object): dly = dl[0] if dl[1] is None: dly+=halfStep - diff_ps=dly*tSDQS-phase*phase_step + diff_ps=dly*tSDQS+(phase_add-phase)*phase_step binArr[int((diff_ps-minVal)/bin_size_ps)]+=1 if quiet < 3: for i,h in enumerate(binArr): @@ -1683,27 +1710,45 @@ class X393LMA(object): return minVal+bin_size_ps*(SX+0.5) # ps if not isinstance(lane,(int, long)): # ignore content, process both lanes - rslt_names=("dqsi_optimal_ps","dqsi_phase") + rslt_names=("dqs_optimal_ps","dqs_phase","dqs_phase_multi","dqs_phase_err","dqs_min_max_periods") rslt= {} for name in rslt_names: rslt[name] = [] for lane in range(2): - rslt_lane=self.lma_fit_dqsi_phase(lane, # byte lane - bin_size_ps, - clk_period, - dqsi_dqi_parameters, - data_set, - compare_prim_steps, - scale_w, - numPhaseSteps, - quiet) + rslt_lane=self.lma_fit_dqs_phase(lane= lane, # byte lane + bin_size_ps= bin_size_ps, + clk_period= clk_period, + dqs_dq_parameters= dqs_dq_parameters, + tSDQS= tSDQS, + data_set= data_set, + compare_prim_steps= compare_prim_steps, + scale_w= scale_w, + numPhaseSteps= numPhaseSteps, + maxDlyErr= maxDlyErr, + fallingPhase= fallingPhase, + shiftFracPeriod= shiftFracPeriod, + quiet= quiet) + for name in rslt_names: rslt[name].append(rslt_lane[name]) if quiet<3: - print ('dqsi_optimal_ps=%s'%(str(rslt['dqsi_optimal_ps']))) - print ('dqsi_phase=[') - for lane in rslt['dqsi_phase']: + print ('dqs_optimal_ps=%s'%(str(rslt['dqs_optimal_ps']))) + print ('dqs_phase=[') + for lane in rslt['dqs_phase']: + print(" [",end=" ") + for i,d in enumerate(lane): + last= i == (len(lane)-1) + print("%s"%(str(d)), end=" ") + if not last: + print(",",end=" ") + if ((i+1) % 16) ==0: + print("\n ",end="") + else: + print('],') + print(']') + print ('dqs_phase_multi=[') + for lane in rslt['dqs_phase_multi']: print(" [",end=" ") for i,d in enumerate(lane): last= i == (len(lane)-1) @@ -1715,24 +1760,54 @@ class X393LMA(object): else: print('],') print(']') -# print(rslt) + print ('dqs_phase_err=[') + for lane in rslt['dqs_phase_err']: + print(" [",end=" ") + for i,d in enumerate(lane): + last= i == (len(lane)-1) + print("%s"%(str(d)), end=" ") + if not last: + print(",",end=" ") + if ((i+1) % 16) ==0: + print("\n ",end="") + else: + print('],') + print(']') + +# print(rslt) + return rslt - phase_step= clk_period/ numPhaseSteps - tSDQS=dqsi_dqi_parameters[lane]['tSDQS'] # ~16.081739769147354 - dbg_tSDQS=(dqsi_dqi_parameters[0]['tSDQS'],dqsi_dqi_parameters[1]['tSDQS']) + phase_step= phase_sign*clk_period/ numPhaseSteps + try: + tSDQS=dqs_dq_parameters[lane]['tSDQS'] # ~16.081739769147354 + except: + if quiet < 2: + print("dqs_dq_parameters are not available, using datasheet value for tSDQS=%f ps"%(tSDQS)) + + try: + dbg_tSDQS=(dqs_dq_parameters[0]['tSDQS'],dqs_dq_parameters[1]['tSDQS']) + except: + dbg_tSDQS=(tSDQS,tSDQS) + halfStep=0.5*(1,compare_prim_steps)[compare_prim_steps] + #phase_step/tSDQS -# print("lma_fit_dqsi_phase(): quiet=",quiet) +# print("lma_fit_dqs_phase(): quiet=",quiet) if quiet < 2: print (phase_step,dbg_tSDQS) for filtered in range(2): show_input_data(filtered) - # all preliminary teset above - maxVal= DLY_STEPS*tSDQS - minVal= -clk_period + # all preliminary tests above + #phase_add + if fallingPhase: + maxVal= clk_period + minVal= -DLY_STEPS*abs(tSDQS) + else: + maxVal= DLY_STEPS*abs(tSDQS) + minVal= -clk_period num_bins=int((maxVal-minVal)/bin_size_ps)+1 binArr=[0]*num_bins if quiet < 2: @@ -1751,13 +1826,16 @@ class X393LMA(object): dly = dl[0] if dl[1] is None: dly+=halfStep - periods[phase]=int(round((dly*tSDQS-phase*phase_step)/clk_period)) + periods[phase]=int(round((dly*tSDQS+(phase_add-phase)*phase_step)/clk_period)) ############################# w=[0.0]*len(data_set) if quiet < 2: for i,p in enumerate(periods): print ("%d %s"%(i,str(p))) - tFDQS=dqsi_dqi_parameters[lane]['tFDQS'] # [-21.824409224001187, -10.830180678770162, 1.5698858542328959, 11.267851084349177] - tFDQS.append(-tFDQS[0]-tFDQS[1]-tFDQS[2]-tFDQS[3]) + try: + tFDQS=dqs_dq_parameters[lane]['tFDQS'] # [-21.824409224001187, -10.830180678770162, 1.5698858542328959, 11.267851084349177] + tFDQS.append(-tFDQS[0]-tFDQS[1]-tFDQS[2]-tFDQS[3]) + except: + tFDQS=[0.0]*FINE_STEPS SY=0.0 S0=0.0 for phase,d in enumerate(data_set): @@ -1769,8 +1847,8 @@ class X393LMA(object): if dl[1] is None: dly+=halfStep w[phase]=scale_w - d=dly*tSDQS-periods[phase]*clk_period-tFDQS[dl[0] % FINE_STEPS] - y=d-phase*phase_step + d=dly*tSDQS-periods[phase]*clk_period-tFDQS[dl[0] % FINE_STEPS] ############################ + y=d+(phase_add-phase)*phase_step S0+=w[phase] SY+=w[phase]*y if S0 > 0.0: @@ -1786,7 +1864,7 @@ class X393LMA(object): dly = dl[0] if dl[1] is None: dly+=halfStep - d=dly*tSDQS-periods[phase]*clk_period-tFDQS[dl[0] % FINE_STEPS] + d=dly*tSDQS-periods[phase]*clk_period-tFDQS[dl[0] % FINE_STEPS] ############################ print ("%f %f"%(d, w[i]), end=" ") if not dl[1] is None: print(d,end=" ") @@ -1794,30 +1872,90 @@ class X393LMA(object): print("?",end=" ") else: print ("? ?", end=" ") - print("%f"%(SY+phase*phase_step),end=" ") + print("%f"%(SY-(phase_add-phase)*phase_step),end=" ") print() - # Now shift SY by clk_period/2.0, for each phase find the closest DQSI match (None if does not exist) - dqsi_range=tSDQS*DLY_STEPS# full range of the DQSI delay for this lane -# dqsi_middle_in_ps = SY-clk_period*round(SY/clk_period)-0.5 -# dqsi_middle_in_ps = (SY-clk_period/2)-clk_period*round((SY-clk_period/2)/clk_period) -# dqsi_middle_in_ps = (SY-clk_period/2)-clk_period*round(SY/clk_period -0.5) - dqsi_middle_in_ps = SY-clk_period*(round(SY/clk_period -0.5)+0.5) - dqsi_phase=[None]*numPhaseSteps + # Now shift SY by half clk_period for each phase find the closest DQSI match (None if does not exist) + # Shift should only be for DQSI (middle between the errors), for WLEV - no shift + #shiftFracPeriod + dqsi_range=abs(tSDQS)*DLY_STEPS# full range of the DQSI delay for this lane +# dqsi_middle_in_ps = SY-clk_period*(round(SY/clk_period -0.5)+0.5) + dqsi_middle_in_ps = SY-clk_period*(round(SY/clk_period -shiftFracPeriod)+shiftFracPeriod) + if quiet < 3: + print("SY=",SY) + print("dqsi_middle_in_ps=",dqsi_middle_in_ps) + print("phase_add=",phase_add) + print("phase_step=",phase_step) + print("shiftFracPeriod=",shiftFracPeriod) + print("clk_period*shiftFracPeriod=",(clk_period*shiftFracPeriod)) + dqs_phase=[None]*numPhaseSteps for phase in range(numPhaseSteps): - dly_ps=phase_step*phase+dqsi_middle_in_ps + dly_ps=-phase_step*(phase_add-phase)+dqsi_middle_in_ps dly_ps-=clk_period*round(dly_ps/clk_period - 0.5) # positive, dqsi_range: continue # no valid dqs_idelay for this phase - idly = int (round(dly_ps/tSDQS)) + idly = int (round(dly_ps/tSDQS)) ###############? low= max(0,idly-FINE_STEPS) high=min(DLY_STEPS-1,idly+FINE_STEPS) idly=low for i in range(low,high+1): - if abs(i*tSDQS-tFDQS[i % FINE_STEPS]-dly_ps) < abs(idly*tSDQS-tFDQS[idly % FINE_STEPS]-dly_ps): + if abs(i*tSDQS-tFDQS[i % FINE_STEPS]-dly_ps) < abs(idly*tSDQS-tFDQS[idly % FINE_STEPS]-dly_ps): ############################ idly=i - dqsi_phase[phase]=idly + dqs_phase[phase]=idly + if quiet < 3: + for phase,d in enumerate(data_set): + print ("%d"%(phase),end=" ") + if (not d is None) and (not d[lane] is None) and (not d[lane][0] is None): + dly = d[lane][0] + if d[lane][1] is None: + dly+=halfStep + print ("%f"%(dly), end=" ") + else: + print ("?", end=" ") + if not dqs_phase[phase] is None: + print("%f"%(dqs_phase[phase]),end=" ") + else: + print ("?", end=" ") + print() + # maxDlyErr (ps) + dqsi_phase_multi=[None]*numPhaseSteps + dqsi_phase_err= [None]*numPhaseSteps + min_max_periods=None + for phase in range(numPhaseSteps): + dly_ps=phase_step*(phase-phase_add)+dqsi_middle_in_ps + periods=int(round((dly_ps+ +maxDlyErr)/clk_period - 0.5)) + dly_ps-=clk_period*periods # positive, = DLY_STEPS: + high=DLY_STEPS - 1 + low= DLY_STEPS - FINE_STEPS + idly=low + for i in range(low,high+1): + if abs(i*tSDQS-tFDQS[i % FINE_STEPS]-dly_ps) < abs(idly*tSDQS-tFDQS[idly % FINE_STEPS]-dly_ps): ################### + idly=i + dqsi_phase_multi[phase][periods]=idly + dqsi_phase_err[phase][periods]=idly*tSDQS-tFDQS[idly % FINE_STEPS]-dly_ps ###################### + periods-=1 + dly_ps+=clk_period + if quiet < 3: + print ("maxDlyErr=",maxDlyErr) + print ("min_max_periods=",min_max_periods) + print ("dqsi_phase_multi=",dqsi_phase_multi) + print ("dqsi_phase_err=",dqsi_phase_err) for phase,d in enumerate(data_set): print ("%d"%(phase),end=" ") if (not d is None) and (not d[lane] is None) and (not d[lane][0] is None): @@ -1827,13 +1965,27 @@ class X393LMA(object): print ("%f"%(dly), end=" ") else: print ("?", end=" ") - if not dqsi_phase[phase] is None: - print("%f"%(dqsi_phase[phase]),end=" ") + if not dqsi_phase_multi[phase] is None: + for periods in range (min_max_periods[0],min_max_periods[1]+1): + try: + print("%f"%(dqsi_phase_multi[phase][periods]),end=" ") + except: + print ("?", end=" ") + for periods in range (min_max_periods[0],min_max_periods[1]+1): + try: + print("%.1f"%(dqsi_phase_err[phase][periods]),end=" ") + except: + print ("?", end=" ") else: print ("?", end=" ") print() - return {"dqsi_optimal_ps":dqsi_middle_in_ps, - "dqsi_phase":dqsi_phase} + + return {"dqs_optimal_ps":dqsi_middle_in_ps, + "dqs_phase":dqs_phase, + "dqs_phase_multi":dqsi_phase_multi, + "dqs_phase_err":dqsi_phase_err, + "dqs_min_max_periods":min_max_periods + } diff --git a/py393/x393_mcntrl_adjust.py b/py393/x393_mcntrl_adjust.py index ef5bd19..5cdcb4d 100644 --- a/py393/x393_mcntrl_adjust.py +++ b/py393/x393_mcntrl_adjust.py @@ -49,8 +49,12 @@ import vrlg NUM_DLY_STEPS =NUM_FINE_STEPS * 32 # =160 DQI_KEY='dqi' DQO_KEY='dqo' +DQSI_KEY='dqsi' +DQSO_KEY='dqso' +CMDA_KEY='cmda' ODD_KEY='odd' - +SIG_LIST=[CMDA_KEY,DQSI_KEY,DQI_KEY,DQSO_KEY,DQO_KEY] +DFLT_DLY_FILT=['Best','Early'] # default non-None filter setting to select a single "best" delay/delay set class X393McntrlAdjust(object): DRY_MODE= True # True @@ -118,209 +122,744 @@ class X393McntrlAdjust(object): print("%08x"%rd_blk[i],end=" ") print("\n") return True - return False - - def set_phase_with_refresh(self, # check result for not None - phase, - quiet=1): + return False + + def _get_dqs_dly_err(self, + phase, + delays, + errors): + ''' + extract dqsi/dqso data for a single phase as a dictionary with keys - signed integer period branches, + values - list of 2 lane delays + Returns either this dictionary or a tuple of this one and corresponding worst errors. Or None! + ''' + periods=None # needed just for PyDev? + for linedata in delays: + try: + periods &= set(linedata[phase].keys()) + except: + try: + periods = set(linedata[phase].keys()) + except: + pass + if not periods: + return None # no branch has all lines + phaseData={} + #Errors may be common for the whole 8-bit lane + if not errors is None: + phaseErrs={} + if len(delays)==8*len(errors): + errors=[errors[i//8] for i in range(len(delays))] + for branch in periods: + phaseData[branch]=[] + if not errors is None: + phaseErrs[branch]=0.0 + for lineData,lineErr in zip(delays,errors): + try: + phaseData[branch].append(lineData[phase][branch]) + except: + phaseData[branch].append(None) + try: + phaseErrs[branch]=max(phaseErrs[branch],abs(lineErr[phase][branch])) + except: + pass + + else: + for lineData in delays: + phaseData[branch].append(lineData[phase][branch]) + if errors is None: + return phaseData + else: + return (phaseData,phaseErrs) + ''' + def combine_dq_dqs(self, + outMode=None, + quiet=1): """ - Set specified phase and matching cmda_odelay while temporarily turning off refresh - @param phase phase to set, signed short - @param quiet reduce output - @return cmda_odelay linear value or None if there is no valid cmda output delay for this phase + @param outmode False - dqi/dqsi, True - dgo/dqso, None - both """ - if not "cmda_bspe" in self.adjustment_state: - raise Exception ("No cmda_odelay data is available. 'adjust_cmda_odelay 0 1 0.1 3' command should run first.") - dly_steps=self.x393_mcntrl_timing.get_dly_steps() - numPhaseSteps= int(dly_steps['SDCLK_PERIOD']/dly_steps['PHASE_STEP']+0.5) - cmda_odly_data=self.adjustment_state['cmda_bspe'][phase % numPhaseSteps] - if (not cmda_odly_data): # phase is invalid for CMDA - return None - cmda_odly_lin=cmda_odly_data['ldly'] - self.x393_axi_tasks.enable_refresh(0) - self.x393_mcntrl_timing.axi_set_phase(phase,quiet=quiet) - self.x393_mcntrl_timing.axi_set_cmda_odelay(combine_delay(cmda_odly_lin),quiet=quiet) - self.x393_axi_tasks.enable_refresh(1) - return cmda_odly_lin - - def set_phase_delays(self, - phase= None, - inp_period='A', - out_period='A', - refresh=True, - delays_phase=None, # if None - use global - quiet=1): + if outMode is None: + self.combine_dq_dqs(False) + self.combine_dq_dqs(True) + elif outMode: + delays, errors= self._combine_dq_dqs(dqs_data=self.adjustment_state['dqso_phase_multi'], + dq_enl_data=self.adjustment_state["dqo_dqso"], + dq_enl_err = self.adjustment_state["maxErrDqso"], + quiet=quiet) + self.adjustment_state['dqo_phase_multi'] = delays + self.adjustment_state["dqo_phase_err"] = errors + elif outMode: + delays, errors= self._combine_dq_dqs(dqs_data=self.adjustment_state['dqsi_phase_multi'], + dq_enl_data=self.adjustment_state["dqi_dqsi"], + dq_enl_err = self.adjustment_state["maxErrDqsi"], + quiet=quiet) + self.adjustment_state['dqi_phase_multi'] = delays + self.adjustment_state["dqi_phase_err"] = errors + else: + self.combine_dq_dqs(False) + self.combine_dq_dqs(True) + ''' + + def _combine_dq_dqs(self, + dqs_data, + dq_enl_data, + dq_enl_err, +# target="dqsi", + quiet=1): """ - Set clock phase and all I/O delays optimal for this phase - @param phase value to set (if None - set 'optimal' if it is defined) - @param inp_period - period branch for DQ inputs: E, N, L or A - @param out_period - period branch for DQ outputs: E, N, L or A - @param refresh - turn refresh OFF before and ON after changing the delays and phase - @param quiet - reduce output - @return True on success, False on invalid phase + Create possibly overlapping branches of delay/error data vs phase for dqi or dqo + @param dqs_data self.adjustment_state['dqs?_phase_multi'] (dqs errors are not used here) + @param dq_enl_data self.adjustment_state["dq?_dqs?"] delay[ENL-branch][dqs_dly][bit] ('None' may be at any level) + @param dq_enl_err self.adjustment_state["maxErrDqs?"] errorPS[ENL-branch][dqs_dly][bit] ('None' may be at any level) +# @param target - one of "dqsi" or "dqso" + @param quiet reduce output + @return dqi/dqo object compatible with the input of get_delays_for_phase(): + (data[line][phase]{(p_dqs,p_dq):delay, ...}, err[lane][phase]{(p_dqs,p_dq):delay, ...} + Errors are per-lane, not per line! """ - if phase is None: - try: - phase= self.adjustment_state['optimal_phase']['optimal_phase'] + # +# if quiet <2: +# print("dq_enl_data=",dq_enl_data) +# print("\ndqs_data=",dqs_data) +# print("\ndqs_data[0]=",dqs_data[0]) +# print("\nlen(dqs_data[0])=",len(dqs_data[0])) + + enl_dict={'early':-1,'nominal':0,'late':1} +# for enl_branch in + numPhaseSteps= len(dqs_data[0]) + for v in dq_enl_data.values(): + try: # branch data + for p in v: # phase data + try: + numLines=len(p) + break + except: + pass + break except: - raise Exception("Phase value is not provided and global;optimal phase is not defined") - - num_addr=vrlg.ADDRESS_NUMBER - num_banks=3 + pass +# numLanes=numLines//8 +# for enl_branch in dq_enl_data: + + if quiet <2: +# print ("numLines=",numLines," numLanes=",numLanes," numPhaseSteps=",numPhaseSteps) + print ("numLines=",numLines," numPhaseSteps=",numPhaseSteps) + data=[[] for _ in range(numLines)] # each element is a new instance of a list + errs=[[] for _ in range(numLines//8)] # each element is a new instance of a list + for phase in range(numPhaseSteps): + + line_data=[{} for _ in range(numLines)] # each element is a new instance of a dict + line_errs=[{} for _ in range(numLines//8)] # each element is a new instance of a dict + phaseData=self._get_dqs_dly_err(phase, + dqs_data, + None) + if quiet <2: + print ("===== phase=%d phaseData=%s"%(phase,str(phaseData))) + if not phaseData is None: + periods_dqs=phaseData.keys() + periods_dqs.sort() + + for period_dqs in periods_dqs: # iterate through all dqs periods + dly_dqs=phaseData[period_dqs] # pair of lane delays + for enl_branch in dq_enl_data: + if not enl_branch is None: + period_dq=enl_dict[enl_branch] + period_key=(period_dqs,period_dq) + if quiet <2: + print ("period_dqs=%d enl_branch=%s period_key=%s, dly_dqs=%s"%(period_dqs,enl_branch,str(period_key),str(dly_dqs))) + try: + print ("dq_enl_data['%s][%d]=%s"%(enl_branch,dly_dqs[0], str(dq_enl_data[enl_branch][dly_dqs[0]]))) + except: + print ("dq_enl_data['%s]=%s"%(enl_branch, str(dq_enl_data[enl_branch]))) + try: + print ("dq_enl_data['%s][%d]=%s"%(enl_branch,dly_dqs[1], str(dq_enl_data[enl_branch][dly_dqs[0]]))) + except: + pass + for line in range(numLines): + try: + line_data[line][period_key]=dq_enl_data[enl_branch][dly_dqs[line//8]][line] + except: + pass + for lane in range(numLines//8): + try: + line_errs[lane][period_key]=dq_enl_err [enl_branch][dly_dqs[lane]][lane] + except: + pass + if quiet <2: + print ("line_data=",line_data) + print ("line_errs=",line_errs) + + + for line,d in zip(data,line_data): + if d: # not empty dictionary + line.append(d) + else: + line.append(None) + for line,d in zip(errs,line_errs): + if d: + line.append(d) + else: + line.append(None) + if quiet <3: + print ("\ndq_dqs_combined_data=",data) + print ("\ndq_dqs_combined_errs=",errs) + print('len(data)=',len(data),'len(data[0])=',len(data[0])) + print('len(errs)=',len(errs),'len(errs[0])=',len(errs[0])) + print("") + for phase in range(len(data[0])): + print ("%d"%(phase), end=" ") + for line in range(len(data)): + print("%s"%(str(data[line][phase])), end=" ") + for lane in range(len(errs)): + print("%s"%(str(errs[lane][phase])), end=" ") + print() + return (data,errs) + - rslt_names=("early","nominal","late") - enl_in=None - enl_out=None - enl_in_used=None - enl_out_used=None - try: - inp=str(inp_period)[0].upper() - except: - print ("Invalid parameter =%s"%(str(inp_period))) - return False + def get_delays_for_phase(self, + phase = None, + list_branches=False, + target=DQSI_KEY, + b_filter=None, # will default to earliest (lowest delay) branch, same as 'e', + cost=None, # if None - will default to NUM_FINE_STEPS, if 0 - will keep it + quiet = 1): + """ + Get list of "optimal" per-bit delays for DQSI,dqso and cmda + always use the same branch + @param phase phase value, if None - return a list for all phases + @parame list_branches - return (ordered) list of available branches, not delays. If it is a string starting with E, + return worst errors in ps instead of the data + @param target - one of "dqsi","dqso", "dqi", "dqo" or "cmda" + @param b_filter - filter to limit clock-period 'branches', item or a list/tuple of items, + consisting of any (or combination) of: + a)word starting with 'E','B','L' (E - branch with smallest delay, + L - largest delay, B (lowest error) - no EBL defaults to "early" + If both Best and Late/Early are present, extra period adds cost*clk_period/NUM_DLY_STEPS + a1) word starting with 'A' (A) - return results even if some lines are None + b) float number - maximal allowed error in ps and + c) one or several specific branches (signed integers) + If b_filter is None, earliest (lowest delay) branch will be used + @param cost TODO: check with multiple overlapping low-error branches. This parameter allows to select between + multiple "good" (low-error) branches that will become availble when clock period will be lower than + delay range. When selecting lowest error it adds cost for lower/higher delays, such that delay of the + full clock period will add/subtract cost/NUM_DLY_STEPS of the period to effective error. With default + cost==5 it will "punish" with 1/32 period for using "wrong" period branch + @param quiet reduce output + @return - a list of delays for a specific phase or None (if none available/match f_filter) or + a list of lists of delays/None-s for all phases (if phase is not specified) or + a list of period branches (signed integers) for a specific phase/None if list_branches is True or + a list of lists/None-s for all phases if phase is None and list_branches is True + """ + + """ + #TODO: REMOVE next temporary lines + self.load_hardcoded_data() + self.proc_addr_odelay(True, 200.0, 4) + self.proc_dqsi_phase ('All', 50, 0, 0.0, 200, 3) + self.proc_dqso_phase ('All', 50, 0, 0.0, 200, 3) + """ + if cost is None: + cost=NUM_FINE_STEPS + return_error=False try: - outp=str(out_period)[0].upper() + if list_branches.upper()[0]=='E': + return_error=True + list_branches=False except: - print ("Invalid parameter =%s"%(str(out_period))) - return False + pass + + if quiet < 2: + print ("processing get_delays_for_phase(phase=%s,list_branches=%s,target='%s',b_filter=%s)"%(str(phase), + str(list_branches), + str(target), + str(b_filter))) + #parse b-filter + if not isinstance (b_filter, (list,tuple)): + b_filter=[b_filter] + periods_set=set() + highDelay=False + lowDelay=False + minError=False + maxErrPS=0.0 + allGood=True + for item in b_filter: + if not item is None: + if isinstance(item,float): + maxErrPS=item + elif isinstance(item,(int,long,tuple)): + periods_set.add(item) + elif isinstance(item,str) and (len(item)>0) and (item.upper()[0] in "EBLA"): + if item.upper()[0] == "L": + highDelay=True + elif item.upper()[0] == "B": + minError=True + elif item.upper()[0] == "E": + lowDelay=True + elif item.upper()[0] == "A": + allGood=False + else: + raise Exception("Unrecognized filter option %s - first letter should be one of 'EBLA'"%(item)) + else: + raise Exception("Unrecognized filter item %s - can be string (starting with E,L,B,A) float (max error in ps) or signed integer - number of clock periods"%(item)) + delay_cost=0 + clk_period=1000.0*self.x393_mcntrl_timing.get_dly_steps()['SDCLK_PERIOD'] # 2500.0, # clk_period, + #Will add to error(ps) -delay_cost(steps) * delay_cost + if lowDelay: + delay_cost=clk_period*cost/(NUM_DLY_STEPS**2) + elif highDelay: + delay_cost=-clk_period*cost/(NUM_DLY_STEPS**2) - if inp == 'A': - enl_in=rslt_names + if target.upper() == 'DQI': + delays=self.adjustment_state['dqi_phase_multi'] + errors=self.adjustment_state['dqi_phase_err'] + common_branches=False + elif target.upper() == 'DQO': + delays=self.adjustment_state['dqo_phase_multi'] + errors=self.adjustment_state['dqo_phase_err'] + common_branches=False + elif target.upper() == 'DQSI': + delays=self.adjustment_state['dqsi_phase_multi'] + errors=self.adjustment_state['dqsi_phase_err'] + common_branches=False + elif target.upper() == 'DQSO': + delays=self.adjustment_state['dqso_phase_multi'] + errors=self.adjustment_state['dqso_phase_err'] + common_branches=False + elif target.upper() == 'CMDA': + delays=self.adjustment_state['addr_odelay']['dlys'] + errors=self.adjustment_state['addr_odelay']['err'] +# print("delays=",delays) +# print("errors=",errors) +# print("2:self.adjustment_state['addr_odelay']=",self.adjustment_state['addr_odelay']) + + common_branches=True else: - for k in rslt_names: - if inp == k[0].upper(): - enl_in=(k,) - break - else: - print ("Unrecognized parameter =%s"%(str(inp_period))) - return False - - if outp == 'A': - enl_out=rslt_names + raise Exception("Unrecognized mode option, valid are: 'DQSI','DQSO' and CMDA'") + if common_branches: + numPhaseSteps= len(delays) else: - for k in rslt_names: - if outp == k[0].upper(): - enl_out=(k,) - break + numPhaseSteps= len(delays[0]) + def single_phase(phase): + if common_branches: + phaseData=delays[phase] + phaseErrs=errors[phase] + if quiet <1: + print("phaseData=",phaseData) +# print("phaseErrs=",phaseErrs) else: - print ("Unrecognized parameter =%s"%(str(out_period))) - return False - - - dly_steps=self.x393_mcntrl_timing.get_dly_steps() - numPhaseSteps= int(dly_steps['SDCLK_PERIOD']/dly_steps['PHASE_STEP']+0.5) - phase= phase % numPhaseSteps # valid for negative also, numPhaseSteps should be <=128 (now it is 112) - if delays_phase == None: - try: - delays_phase=self.adjustment_state['delays_phase'] - except: - print("Delays for phases (self.adjustment_state['delays_phase']) are not set, running 'get_delays_vs_phase' command ") try: - delays_phase=self.get_delays_vs_phase(filter_dqo=2, - filter_dqi=2, - filter_dqso=2, - filter_dqsi=2, - filter_cmda=2, - filter_read=0, - filter_write=0, - filter_rsel=None, - filter_wsel=None, - keep_all=False, - set_table=True, - quiet=quiet+2) - self.adjustment_state['delays_phase']=delays_phase - except: - print ("Failed to execute 'get_delays_vs_phase' command") - return False - elif quiet < 2: - print ("using provided delays_phase") - try: - delays=delays_phase[phase] - except: - print("No valid delay data for phase %d is available"%(phase)) - return False - if quiet<1: - print ("delays=",delays) - - try: - cmda_odly=delays['cmda'] - except: - print("No valid CMDA output delay data for phase %d is available, it is required"%(phase)) - return False - - try: - dqs_idelays=delays['dqsi'] - except: - dqs_idelays=None - if quiet < 2: - print ("No valid DQS input delay data for phase %d is available, it will not be set"%(phase)) - - try: - dqs_odelays=delays['dqso'] - except: - dqs_odelays=None - if quiet < 2: - print ("No valid DQS output delay data for phase %d is available, it will not be set"%(phase)) + phaseData,phaseErrs=self._get_dqs_dly_err(phase, + delays, + errors) + except: # _get_dqs_dly_err ==> None + if quiet <1: + print("phaseData=None") + + return None + if quiet <1: + print("phaseData=",phaseData) - for k in enl_in: - try: - dq_idelays=delays['dqi'][k] - enl_in_used=k - break - except: - pass + if phaseData is None: + return None + periods=phaseData.keys() + + periods.sort() # can compare tuples (1-st is "more important") + if maxErrPS: + for indx,branch in enumerate(periods): + if phaseErrs[branch] > maxErrPS: + periods.pop(indx) + if allGood: + for indx,branch in enumerate(periods): + if None in phaseData[branch]: + periods.pop(indx) + + for indx,branch in enumerate(periods): # if all elements are None + if all(v is None for v in phaseData[branch]): + periods.pop(indx) + + + # useBranch + # filter results + if periods_set: + periods=[p for p in periods if p in periods_set] + if not periods: + return None + if (len(periods) > 1) and minError: + if delay_cost == 0: + """ + merr=min(phaseErrs[b] for b in periods) + for branch in periods: # , e in phaseErrs.items(): + if phaseErrs[branch] == merr: + periods=[branch] + break + """ + #just list errors for the periods list + eff_errs=[phaseErrs[b] for b in periods] + else: + #calculate "effective errors" by adding scaled (with +/-) average delay for branches + eff_errs=[phaseErrs[b]+(delay_cost*sum(d for d in phaseData[b] if not d is None)/sum(1 for d in phaseData[b] if not d is None)) for b in periods] + periods=[periods[eff_errs.index(min(eff_errs))]] + #Filter by low/high delays without minError mode + if len(periods)>1: + dl0_per=[phaseData[p][0] for p in periods] # only delay for line 0, but with same branch requirement this should be the same for all lines + if highDelay or lowDelay or not list_branches or return_error: # in list_branches mode - filter by low/high only if requested, for delays use low if not highDelay + periods=[periods[dl0_per.index((min,max)[highDelay](dl0_per))]] + if list_branches: # move to the almost very end, so filters apply + return periods + elif return_error: + return phaseErrs[periods[0]] + else: + return phaseData[periods[0]] + + #main method body + if not phase is None: + rslt= single_phase(phase) + if quiet < 3: + print ("%d %s"%(phase,str(rslt))) else: - dq_idelays=None - if quiet < 2: - print ("No valid DQ input delay data for phase %d (period(s)=%s) is available, it will not be set"%(phase,str(enl_in))) - - for k in enl_out: + rslt=[] + for phase in range(numPhaseSteps): + rslt.append(single_phase(phase)) + if quiet < 3: + for phase, v in enumerate(rslt): + print ("%d %s"%(phase,str(v))) + return rslt + + def set_delays(self, + phase, + filter_cmda=None, # may be special case: 'S + filter_dqsi=None, + filter_dqi= None, + filter_dqso=None, + filter_dqo= None, + cost=None, + refresh=True, + forgive_missing=False, + quiet=3): + """ + Set phase and all relevant delays (ones with non None filters) + @param phase value to calculate delays for or None to use globally set optimal_phase + @param filter_cmda filter clock period branches for command and addresses. See documentation for + get_delays_for_phase() - b_filter + @param filter_dqsi filter for DQS output delays + @param filter_dqi filter for DQS output delays + @param filter_dqso filter for DQS output delays + @param filter_dqo filter for DQS output delays, + @param refresh - turn refresh OFF before and ON after changing the delays and phase + @param forgive_missing do not raise exceptions on missing data - just skip that delay group + @param quiet Reduce output + @return used delays dictionary on success, None on failure + raises Exception() if any delays with non-None filters miss required data + """ + if phase is None: try: - dq_odelays=delays['dqo'][k] - enl_out_used=k - break + phase= self.adjustment_state['optimal_phase'] except: - pass - else: - dq_odelays=None - if quiet < 2: - print ("No valid DQ output delay data for phase %d (period(s)=%s) is available, it will not be set"%(phase,str(enl_out))) - + raise Exception("Phase value is not provided and global;optimal phase is not defined") + num_addr=vrlg.ADDRESS_NUMBER + num_banks=3 + dly_steps=self.x393_mcntrl_timing.get_dly_steps() + numPhaseSteps= int(dly_steps['SDCLK_PERIOD']/dly_steps['PHASE_STEP']+0.5) + phase= phase % numPhaseSteps # valid for negative also, numPhaseSteps should be <=128 (now it is 112) + + delays=self.get_all_delays(phase=phase, + filter_cmda= filter_cmda, # may be special case: 'S + filter_dqsi= filter_dqsi, + filter_dqi= filter_dqi, + filter_dqso= filter_dqso, + filter_dqo= filter_dqo, + cost= cost, + forgive_missing= forgive_missing, + quiet= quiet) + if delays is None: #May also be an empty dictionary? + return None + filters=dict(zip(SIG_LIST,[filter_cmda,filter_dqsi,filter_dqi,filter_dqso,filter_dqo])) if quiet < 2: print ("Going to set:") print ("phase=",phase) - print ('cmda_odly=',cmda_odly) - print ('dqs_idelays=',dqs_idelays) - print ('dqs_odelays=',dqs_odelays) - print ('dq_idelays=',dq_idelays,' (',enl_in_used,')') - print ('dq_odelays=',dq_odelays,' (',enl_out_used,')') + name_len=max(len(k) for k in SIG_LIST if filters[k] is not None) + frmt="%%%ds = %%s"%(name_len+3) + for k in SIG_LIST: + if not filters[k] is None: + print(frmt%(k+" = "+" "*(name_len-len(k)), str(delays[k]))) print ('Memory refresh will %sbe controlled'%(('NOT ','')[refresh])) + if refresh: self.x393_axi_tasks.enable_refresh(0) self.x393_mcntrl_timing.axi_set_phase(phase,quiet=quiet) - if isinstance(cmda_odly,(list,tuple)): - self.x393_mcntrl_timing.axi_set_address_odelay(combine_delay(cmda_odly[:num_addr]),quiet=quiet) - self.x393_mcntrl_timing.axi_set_bank_odelay (combine_delay(cmda_odly[num_addr:num_addr+num_banks]),quiet=quiet) - cmd_dly_data=cmda_odly[num_addr+num_banks:] - while len(cmd_dly_data) < 5: - cmd_dly_data.append(cmd_dly_data[-1]) # repeat last element (average address/command delay) - self.x393_mcntrl_timing.axi_set_cmd_odelay (combine_delay(cmd_dly_data),quiet=quiet) # for now - same delay TODO: upgrade! -# self.x393_mcntrl_timing.axi_set_cmda_odelay(combine_delay(cmda_odly),quiet=quiet) - else: - self.x393_mcntrl_timing.axi_set_cmda_odelay(combine_delay(cmda_odly),quiet=quiet) + if CMDA_KEY in delays: + if isinstance(delays[CMDA_KEY],(list,tuple)): + self.x393_mcntrl_timing.axi_set_address_odelay(combine_delay(delays[CMDA_KEY][:num_addr]),quiet=quiet) + self.x393_mcntrl_timing.axi_set_bank_odelay (combine_delay(delays[CMDA_KEY][num_addr:num_addr+num_banks]),quiet=quiet) + cmd_dly_data=delays[CMDA_KEY][num_addr+num_banks:] + while len(cmd_dly_data) < 5: + cmd_dly_data.append(cmd_dly_data[-1]) # repeat last element (average address/command delay) + self.x393_mcntrl_timing.axi_set_cmd_odelay (combine_delay(cmd_dly_data),quiet=quiet) # for now - same delay TODO: upgrade! + else: # only data from 'cmda_bspe' is available - use it for all + self.x393_mcntrl_timing.axi_set_cmda_odelay(combine_delay(delays[CMDA_KEY]),quiet=quiet) if refresh: self.x393_axi_tasks.enable_refresh(1) - if not dqs_idelays is None: - self.x393_mcntrl_timing.axi_set_dqs_idelay(combine_delay(dqs_idelays),quiet=quiet) - if not dq_idelays is None: - self.x393_mcntrl_timing.axi_set_dq_idelay(combine_delay(dq_idelays),quiet=quiet) - if not dqs_odelays is None: - self.x393_mcntrl_timing.axi_set_dqs_odelay(combine_delay(dqs_odelays),quiet=quiet) - if not dq_odelays is None: - self.x393_mcntrl_timing.axi_set_dq_odelay(combine_delay(dq_odelays),quiet=quiet) -# if refresh: #already set -# self.x393_axi_tasks.enable_refresh(1) + if DQSI_KEY in delays: + self.x393_mcntrl_timing.axi_set_dqs_idelay(combine_delay(delays[DQSI_KEY]),quiet=quiet) + if DQI_KEY in delays: + self.x393_mcntrl_timing.axi_set_dq_idelay(combine_delay(delays[DQI_KEY]),quiet=quiet) + if DQSO_KEY in delays: + self.x393_mcntrl_timing.axi_set_dqs_odelay(combine_delay(delays[DQSO_KEY]),quiet=quiet) + if DQO_KEY in delays: + self.x393_mcntrl_timing.axi_set_dq_odelay(combine_delay(delays[DQO_KEY]),quiet=quiet) return True + + + def get_all_delays(self, + phase, + filter_cmda=None, # may be special case: 'S + filter_dqsi=None, + filter_dqi= None, + filter_dqso=None, + filter_dqo= None, + forgive_missing=False, + cost=None, + quiet=3): + """ + Calculate dictionary of delays for specific phase. Only Non-None filters will generate items in the dictionary + @param phase phase value to calculate delays for or None to calculate a list for all phases + @param filter_cmda filter clock period branches for command and addresses. See documentation for + get_delays_for_phase() - b_filter + @param filter_dqsi filter for DQS output delays + @param filter_dqi filter for DQS output delays + @param filter_dqso filter for DQS output delays + @param filter_dqo filter for DQS output delays, + @param forgive_missing do not raise exceptions on missing data - just skip that delay group + @param quiet Reduce output + @return None if not possible for at east one non-None filter, otherwise a dictionary of delay to set. + Each value is either number set to all or a tuple/list (to set individual values) + raises Exception if required data is missing + """ + filters=dict(zip(SIG_LIST,[filter_cmda,filter_dqsi,filter_dqi,filter_dqso,filter_dqo])) + if phase is None: + all_delays=[] + dly_steps=self.x393_mcntrl_timing.get_dly_steps() + numPhaseSteps= int(dly_steps['SDCLK_PERIOD']/dly_steps['PHASE_STEP']+0.5) + for phase in range(numPhaseSteps): + all_delays.append(self.get_all_delays(phase=phase, + filter_cmda = filter_cmda, + filter_dqsi = filter_dqsi, + filter_dqi = filter_dqi, + filter_dqso = filter_dqso, + filter_dqo = filter_dqo, + cost= cost, + forgive_missing = forgive_missing, + quiet= quiet)) + return all_delays + + + delays={} + for k in SIG_LIST: + if not filters[k] is None: + #special case for cmda, and if self.adjustment_state['addr_odelay'] is not available + if (k == CMDA_KEY) and ((not 'addr_odelay' in self.adjustment_state) or + (isinstance (filter_cmda,str) and (len(filter_cmda)>1) and (filter_cmda.upper()[0]=='S'))): + if quiet < 3: + print ("\n===== processing '%s' using self.adjustment_state['cmda_bspe']"%(k)) + try: + cmda_bspe=self.adjustment_state['cmda_bspe'] + except: + raise Exception ('Data for filter_cmda is not available (self.adjustment_state["cmda_bspe"]') + try: + safe_phase=float(filter_cmda.upper()[1:]) + if quiet <2: + print ("using safe phase=",safe_phase) + except: + safe_phase=0 + if safe_phase >=0.5: + print ("Invalid 'safe range' (safe_phase). It is measured in clock cycles and should be < 0.5") + safe_phase=0 + if safe_phase and (not cmda_bspe[phase]['zerr'] is None) and (cmda_bspe[phase]['zerr']< 0.5-safe_phase): + delays[k]=0 # set to minimal delay (==0) + else: + delays[k]=cmda_bspe[phase]['ldly'] + else: + if quiet < 3: + print ("\n===== processing '%s'"%(k)) + if forgive_missing: + try: + delays[k]=self.get_delays_for_phase(phase = phase, + list_branches=False, # just get one set of filtered delay + target= k, + b_filter= filters[k], + cost= cost, + quiet = quiet+2) + except: + pass + delays[k]=self.get_delays_for_phase(phase = phase, + list_branches=False, # just get one set of filtered delay + target= k, + b_filter= filters[k], + cost= cost, + quiet = quiet+2) + if delays[k] is None: + return None + return delays + + def show_all_delays(self, + filter_cmda='A',#None, + filter_dqsi='A',#None, + filter_dqi= 'A',#None, + filter_dqso='A',#None, + filter_dqo= 'A',#None, + quiet=3): + """ + Print all optionally filtered delays, the results can be copied to a spreadsheet program to create graph + @param filter_cmda filter clock period branches for command and addresses. See documentation for + get_delays_for_phase() - b_filter + @param filter_dqsi filter for DQS output delays + @param filter_dqi filter for DQS output delays + @param filter_dqso filter for DQS output delays + @param filter_dqo filter for DQS output delays, + @param quiet Reduce output + """ + required_keys=('addr_odelay', + 'dqi_phase_multi', + 'dqi_phase_err', + 'dqo_phase_multi', + 'dqo_phase_err', + 'dqsi_phase_multi', + 'dqsi_phase_err', + 'dqso_phase_multi', + 'dqso_phase_err') + if not all (k in self.adjustment_state for k in required_keys): + print ("Running in simulation mode, using hardcoded data") + self.load_hardcoded_data() + self.proc_addr_odelay(True, 200.0, 4) + self.proc_dqsi_phase ('All', 50, 0, 0.0, 200, 3) + self.proc_dqso_phase ('All', 50, 0, 0.0, 200, 3) + #datasheet step per average delay per finedelay step + tSDQS=1000.0*self.x393_mcntrl_timing.get_dly_steps()['DLY_STEP']/NUM_FINE_STEPS + filters=dict(zip(SIG_LIST,[filter_cmda,filter_dqsi,filter_dqi,filter_dqso,filter_dqo])) +# filters={CMDA_KEY:filter_cmda,DQSI_KEY:filter_dqsi,DQI_KEY:filter_dqi,DQSO_KEY:filter_dqso,DQO_KEY:filter_dqo} + periods_phase={} + periods_all={} + for k in SIG_LIST: + if quiet < 3: + print ("\n===== processing '%s'"%(k)) + periods_phase[k]=self.get_delays_for_phase(phase = None, + list_branches=True, + target=k, + b_filter=filters[k], + #cost=NUM_FINE_STEPS, + quiet = quiet+2) + periods_all[k]=set() + for lp in periods_phase[k]: + try: + for p in lp: + periods_all[k].add(p) + except: + pass # None + periods_all[k]=list(periods_all[k]) + periods_all[k].sort() + if quiet <3: + print ("periods_all=",periods_all) + # Print the header + num_addr=15 + num_banks=3 + num_lines=16 + num_cmda=num_addr+num_banks+3+1 + num_lanes=num_lines//8 + positions={CMDA_KEY:num_cmda,DQSI_KEY:num_lanes,DQI_KEY:num_lines,DQSO_KEY:num_lanes,DQO_KEY:num_lines} + + print ("phase",end=" ") + for period in periods_all[CMDA_KEY]: + for i in range(num_addr): + print("A%d_%d"%(i,period),end=" ") + for i in range(num_banks): + print("BA%d_%d"%(i,period),end=" ") + print ("WE_%d RAS_%d CAS_%d AVG_%d"%(period,period,period,period), end=" ") # AVG - average for address, banks, RCW + for period in periods_all[DQSI_KEY]: + for lane in range(num_lanes): + print("DQSI_%d_%d"%(lane,period),end=" ") + for period in periods_all[DQI_KEY]: + for line in range(num_lines): + print("DQI_%d_%d/%d"%(line,period[0],period[1]),end=" ") + for period in periods_all[DQSO_KEY]: + for lane in range(num_lanes): + print("DQSO_%d_%d"%(lane,period),end=" ") + for period in periods_all[DQO_KEY]: + for line in range(num_lines): + print("DQO_%d_%d/%d"%(line,period[0],period[1]),end=" ") + + #TODO - add errors print +# """ + for period in periods_all[CMDA_KEY]: + print("ERR_CMDA_%d"%(period),end=" ") + for period in periods_all[DQSI_KEY]: + print("ERR_DQSI_%d"%(period),end=" ") + for period in periods_all[DQSO_KEY]: + print("ERR_DQSO_%d"%(period),end=" ") +# """ + print() + #print body + for phase in range(len(periods_phase[CMDA_KEY])): + print ("%d"%(phase),end=" ") + for k in SIG_LIST: + for period in periods_all[k]: + data_group=self.get_delays_for_phase(phase = phase, + list_branches=False, + target=k, + b_filter=[period,"A"], + #cost=NUM_FINE_STEPS, only used with 'B' + quiet = quiet+2) + for i in range(positions[k]): + try: + print("%d"%(data_group[i]), end=" ") + except: + print("?",end=" ") + + for k in [CMDA_KEY,DQSI_KEY,DQSO_KEY]: + for period in periods_all[k]: + err_ps=self.get_delays_for_phase(phase = phase, + list_branches='Err', + target=k, + b_filter=[period,"A"], + #cost=NUM_FINE_STEPS, only used with 'B' + quiet = quiet+2) + try: + print("%.1f"%(err_ps/tSDQS), end=" ") + except: + print("?",end=" ") + + print() + + + + + + + +#numPhaseSteps= len(delays[0]) + + + def set_phase_with_refresh(self, # check result for not None + phase, + quiet=1): + """ + Set specified phase and matching cmda_odelay while temporarily turning off refresh + @param phase phase to set, signed short + @param quiet reduce output + @return cmda_odelay linear value or None if there is no valid cmda output delay for this phase + """ + if not "cmda_bspe" in self.adjustment_state: + raise Exception ("No cmda_odelay data is available. 'adjust_cmda_odelay 0 1 0.1 3' command should run first.") + dly_steps=self.x393_mcntrl_timing.get_dly_steps() + numPhaseSteps= int(dly_steps['SDCLK_PERIOD']/dly_steps['PHASE_STEP']+0.5) + cmda_odly_data=self.adjustment_state['cmda_bspe'][phase % numPhaseSteps] + if (not cmda_odly_data): # phase is invalid for CMDA + return None + cmda_odly_lin=cmda_odly_data['ldly'] + self.x393_axi_tasks.enable_refresh(0) + self.x393_mcntrl_timing.axi_set_phase(phase,quiet=quiet) + self.x393_mcntrl_timing.axi_set_cmda_odelay(combine_delay(cmda_odly_lin),quiet=quiet) + self.x393_axi_tasks.enable_refresh(1) + return cmda_odly_lin def adjust_cmda_odelay(self, start_phase=0, @@ -671,18 +1210,26 @@ class X393McntrlAdjust(object): print ("}") return rdict - def adjust_write_levelling(self, + def measure_write_levelling(self, + compare_prim_steps = True, # while scanning, compare this delay with 1 less by primary(not fine) step, start_phase=0, reinits=1, #higher the number - more re-inits are used (0 - only where absolutely necessary invert=0, # anti-align DQS (should be 180 degrees off from the normal one) - max_phase_err=0.1, + dqs_patt=None, quiet=1 ): """ Find DQS output delay for each phase value Depends on adjust_cmda_odelay results + @param compare_prim_steps = True, # while scanning, compare this delay with 1 less by primary(not fine) step, + @param start_phase=0, + @param reinits=1, #higher the number - more re-inits are used (0 - only where absolutely necessary + @param invert=0, # anti-align DQS (should be 180 degrees off from the normal one), can be used to find duty cycle of the clock + @param dqs_patt set and store in global data DQS pattern to use during writes + @param quiet=1 """ nbursts=16 + numLanes=2 try: self.adjustment_state['cmda_bspe'] except: @@ -698,13 +1245,42 @@ class X393McntrlAdjust(object): print ("numPhaseSteps=%d"%(numPhaseSteps)) self.x393_pio_sequences.set_write_lev(nbursts) # write leveling, 16 times (full buffer - 128) - + if dqs_patt is None: + try: + dqs_patt=self.adjustment_state["dqs_pattern"] + except: + print("Skipping DQS pattern (0x55/0xaa) control as it is not provided and not in gloabal data (dqs_patt=self.adjustment_state['dqs_pattern'])") + + if not dqs_patt is None: # may be just set + self.x393_mcntrl_timing.axi_set_dqs_dqm_patterns(dqs_patt=dqs_patt, + dqm_patt=None, + quiet=quiet+2) def wlev_phase_step (phase): - def norm_wlev(wlev): #change results to invert wlev data - if invert: - return [1.0-wlev[0],1.0-wlev[1],wlev[2]] + dqso_cache=[None]*NUM_DLY_STEPS # cache for holding already measured delays. None - not measured, 0 - no data, [[]..[]] + def measure_dqso(dly,force_meas=False): + def norm_wlev(wlev): #change results to invert wlev data + if invert: + return [1.0-wlev[0],1.0-wlev[1],wlev[2]] + else: + return wlev + if (dqso_cache[dly] is None) or force_meas: + self.x393_mcntrl_timing.axi_set_dqs_odelay(combine_delay(dly),quiet=quiet) + wlev_rslt=norm_wlev(self.x393_pio_sequences.write_levelling(1, nbursts, quiet+1)) + if wlev_rslt[2]>wlev_max_bad: # should be 0 - otherwise wlev did not work (CMDA?) + raise Exception("Write levelling gave unexpected data, aborting (may be wrong command/address delay, incorrectly initialized") + dqso_cache[dly] = wlev_rslt + if quiet < 1: + print ('measure_dqso(%d) - new measurement'%(dly)) else: - return wlev + wlev_rslt = dqso_cache[dly] + if quiet < 1: + print ('measure_dqso(%d) - using cache'%(dly)) + return wlev_rslt + + + + + #currently looking for the lowest delay, may be multiple with higher frequency (full delay > period) dly90=int(0.25*numPhaseSteps*abs(self.adjustment_state['cmda_odly_a']) + 0.5) # linear delay step ~ SDCLK period/4 cmda_odly_data=self.adjustment_state['cmda_bspe'][phase % numPhaseSteps] if (not cmda_odly_data): # phase is invalid for CMDA @@ -714,10 +1290,7 @@ class X393McntrlAdjust(object): self.x393_mcntrl_timing.axi_set_cmda_odelay(combine_delay(cmda_odly_lin),quiet=quiet) d_low=0 while d_low <= max_lin_dly: - self.x393_mcntrl_timing.axi_set_dqs_odelay(combine_delay(d_low),quiet=quiet) - wlev_rslt=norm_wlev(self.x393_pio_sequences.write_levelling(1, nbursts, quiet+1)) - if wlev_rslt[2]>wlev_max_bad: # should be 0 - otherwise wlev did not work (CMDA?) - raise Exception("Write levelling gave unespected data, aborting (may be wrong command/address delay, incorrectly initializaed") + wlev_rslt=measure_dqso(d_low) if (wlev_rslt[0] <= wlev_max_bad) and (wlev_rslt[1] <= wlev_max_bad): break d_low+=dly90 @@ -728,10 +1301,7 @@ class X393McntrlAdjust(object): # Now find d_high>d_low to get both bytes result above d_high= d_low+dly90 while d_high <= max_lin_dly: - self.x393_mcntrl_timing.axi_set_dqs_odelay(combine_delay(d_high),quiet=quiet) - wlev_rslt=norm_wlev(self.x393_pio_sequences.write_levelling(1, nbursts, quiet+1)) - if wlev_rslt[2]>wlev_max_bad: # should be 0 - otherwise wlev did not work (CMDA?) - raise Exception("Write levelling gave unespected data, aborting (may be wrong command/address delay, incorrectly initializaed") + wlev_rslt=measure_dqso(d_high) if (wlev_rslt[0] >= (1.0 -wlev_max_bad)) and (wlev_rslt[1] >= (1.0-wlev_max_bad)): break d_high+=dly90 @@ -745,10 +1315,7 @@ class X393McntrlAdjust(object): while d_high > d_low: dly= (d_high + d_low)//2 - self.x393_mcntrl_timing.axi_set_dqs_odelay(combine_delay(dly),quiet=quiet) - wlev_rslt=norm_wlev(self.x393_pio_sequences.write_levelling(1, nbursts, quiet+1)) - if wlev_rslt[2]>wlev_max_bad: # should be 0 - otherwise wlev did not work (CMDA?) - raise Exception("Write levelling gave unespected data, aborting (may be wrong command/address delay, incorrectly initializaed") + wlev_rslt=measure_dqso(dly) if (wlev_rslt[0] <= wlev_max_bad) and (wlev_rslt[1] <= wlev_max_bad): if d_low == dly: break @@ -762,25 +1329,72 @@ class X393McntrlAdjust(object): print ("After common adjust d_low=%d, d_high=%d"%(d_low,d_high)) d_low=[d_low,d_low] d_high=[d_high,d_high] - for i in range(2): + for i in range(numLanes): while d_high[i] > d_low[i]: dly= (d_high[i] + d_low[i])//2 if quiet < 1: print ("i=%d, d_low=%d, d_high=%d, dly=%d"%(i,d_low[i],d_high[i],dly)) - dly01=[d_low[0],d_low[1]] - dly01[i]=dly - self.x393_mcntrl_timing.axi_set_dqs_odelay(combine_delay(dly01),quiet=quiet) - wlev_rslt=norm_wlev(self.x393_pio_sequences.write_levelling(1, nbursts, quiet+1)) - if wlev_rslt[2]>wlev_max_bad: # should be 0 - otherwise wlev did not work (CMDA?) - raise Exception("Write levelling gave unespected data, aborting (may be wrong command/address delay, incorrectly initializaed") + wlev_rslt=measure_dqso(dly) if wlev_rslt[i] <= wlev_max_bad: if d_low[i] == dly: break d_low[i]=dly else: d_high[i]=dly - return d_low + #return d_low + # now scan in the range +/- NUM_FINE_STEPS for each lane, get (dly, err) for each, err=None if binary + rslt=[] + bestDly=[None]*numLanes # [low_safe]*2 # otherwise may fail - check it? + bestDiffs=[None]*numLanes + comp_step=(1,NUM_FINE_STEPS)[compare_prim_steps] + for lane in range (numLanes): + lastPositive=0 + for dly in range (max(0,d_low[lane]-NUM_FINE_STEPS), min(NUM_DLY_STEPS,d_low[lane]+2*NUM_FINE_STEPS+1)): + ref_dly= dly-comp_step + if ref_dly <0: + continue + wlev_rslt_ref=measure_dqso(ref_dly) + wlev_rslt= measure_dqso(dly) + diff= wlev_rslt[lane]-0.5 + diff_ref=wlev_rslt_ref[lane]-0.5 + diffs_prev_this=(diff_ref,diff) + if diff > 0: + lastPositive+=1 + else: + lastPositive=0 + if quiet <2: + print ("lane=%d ref_dly=%d dly=%d, diffs_prev_this=%s"%(lane, ref_dly, dly, str(diffs_prev_this))) + if (diffs_prev_this[0] <= 0) and (diffs_prev_this[1] >= 0): + if abs(diffs_prev_this[0]) <= abs(diffs_prev_this[1]): # store previous sample + if (bestDiffs[lane] is None) or (abs (diffs_prev_this[0]) < abs(bestDiffs[lane])): + bestDly[lane]=ref_dly # dly-1/dly-NUM_FINE_STEPS + bestDiffs[lane]=diffs_prev_this[0] + else: + if (bestDiffs[lane] is None) or (abs (diffs_prev_this[1]) 0): + if lastPositive > NUM_FINE_STEPS: + break # no need to continue, data got already - Wrong, better analog may still be ahead + if bestDiffs[lane] == -0.5: + bestDiffs[lane] = None # single step jumps from none to all + elif not bestDiffs[lane] is None: + bestDiffs[lane] *= 2 + rslt.append((bestDly[lane],bestDiffs[lane])) + if quiet < 2: + print ("bestDly[%d]=%s, bestDiffs[%d]=%s"%(lane,str(bestDly[lane]),lane,str(bestDiffs[lane]))) + if quiet < 2: + print ('dly=%d rslt=%s'%(dly,str(rslt))) + if quiet < 2: + print ("Cache for phase=%d:"%(phase)) + for i,d in enumerate(dqso_cache): + if d: + print ("%d %d: %s"%(phase,i,str(d))) + return rslt + + # main method body + if (start_phase+numPhaseSteps)>128: old_start_phase=start_phase while (start_phase+numPhaseSteps)>128: @@ -811,15 +1425,60 @@ class X393McntrlAdjust(object): if quiet< 2: print() - if quiet <2: + if quiet < 4: + print("\nMeasured wlev data, When error is None add 1/2 of compare_prim_steps to the estimated result") + print("compare_prim_steps=",compare_prim_steps) + print("Phase dly0 dly1 fdly0 fdly1 err0 err1") for i,d in enumerate(wlev_dqs_delays): if d: - print ("%d %d %d"%(i, d[0], d[1])) + print ("%d %d %d"%(i, d[0][0], d[1][0]), end=" ") + for ld in d: + if not ld[1] is None: + print ("%d"%(ld[0]),end= " ") + else: + print ("?",end=" ") + for ld in d: + try: + print ("%.3f"%(ld[1]),end= " ") + except: + print ("?",end=" ") + print() else: print ("%d"%(i)) elif quiet < 5: print () + #measurement done, now processing results. TODO: move to a separate function + if quiet < 4: + print ("wlev_dqs_delays=",wlev_dqs_delays) + print ("wlev_dqs_steps=", compare_prim_steps) + + self.adjustment_state["wlev_dqs_delays"]=wlev_dqs_delays + self.adjustment_state["wlev_dqs_steps"]=compare_prim_steps + if not dqs_patt is None: + self.adjustment_state["dqs_pattern"]=dqs_patt + return wlev_dqs_delays + + + def proc_write_levelling(self, + data_set_number=2, # not number - use measured data + max_phase_err=0.1, + quiet=1): + if isinstance (data_set_number,(int,long)) and (data_set_number>=0) : + if quiet < 4: + print("Using hard-coded data set ") + wlev_dqs_delays=get_test_dq_dqs_data.get_wlev_dqs_delays() + else: + if quiet < 4: + print("Using measured data set") + try: + wlev_dqs_delays=self.adjustment_state["wlev_dqs_delays"] + except: + print ("Write levelling measured data is not available, exiting") + return + dly_steps=self.x393_mcntrl_timing.get_dly_steps() + numPhaseSteps= int(dly_steps['SDCLK_PERIOD']/dly_steps['PHASE_STEP']+0.5) + #find the largest positive step of cmda_marg_dly while cyclically increasing phase numValid=0 for i,d in enumerate(wlev_dqs_delays): @@ -827,7 +1486,9 @@ class X393McntrlAdjust(object): numValid += 1 if numValid < 2: raise Exception("Too few points with DQS output delay in write levelling mode: %d"%numValid) - + + print("wlev_dqs_delays=",wlev_dqs_delays) + firstIndex=[None]*2 for lane in range(2): maxPosSep=0 @@ -900,7 +1561,7 @@ class X393McntrlAdjust(object): if (quiet <2): print ("a[%d]=%f, b[%d]=%f"%(lane,a[lane],lane,b[lane])) #Make b fit into 0..max_lin_dly range - while (b[lane] > max_lin_dly): + while (b[lane] >= NUM_DLY_STEPS): b[lane]-=variantStep[lane] b_period[lane]-=1 while (b[lane] < 0): @@ -932,7 +1593,7 @@ class X393McntrlAdjust(object): y0 += variantStep[lane] periods += 1 dly_min= max(0,int(y0-4.5)) - dly_max= min(max_lin_dly,int(y0+5.5)) + dly_max= min(NUM_DLY_STEPS-1,int(y0+5.5)) dly_to_try=[] for d in range(dly_min,dly_max+1): dly_to_try.append((d,periods)) @@ -940,7 +1601,7 @@ class X393McntrlAdjust(object): y0+=variantStep[lane] periods += 1 dly_min= max(0,int(y0-4.5)) - dly_max= min(max_lin_dly,int(y0+5.5)) + dly_max= min(NUM_DLY_STEPS-1,int(y0+5.5)) for d in range(dly_min,dly_max+1): dly_to_try.append((d,periods)) bestDly=None @@ -1251,7 +1912,7 @@ class X393McntrlAdjust(object): diffs_prev_this=(patt_prev[b]-0.5,patt[b]-0.5) else: diffs_prev_this=(0.5-patt_prev[b],0.5-patt[b]) - if abs(diffs_prev_this[0]) <= abs(diffs_prev_this[1]): # store previos sample + if abs(diffs_prev_this[0]) <= abs(diffs_prev_this[1]): # store previous sample if (best_diff[inPhase][b] is None) or (abs (diffs_prev_this[0]) 0: + lastPositive[i] += 1 + else: + lastPositive[i] = 0 + for lane in range(len(adiffs)): diffs_prev_this=(adiffs_ref[lane],adiffs[lane]) if (diffs_prev_this[0] <= 0) and (diffs_prev_this[1] >= 0): - if abs(diffs_prev_this[0]) <= abs(diffs_prev_this[1]): # store previos sample + if abs(diffs_prev_this[0]) <= abs(diffs_prev_this[1]): # store previous sample if (bestDiffs[lane] is None) or (abs (diffs_prev_this[0]) < abs(bestDiffs[lane])): bestDly[lane]=ref_dly # dly-1/dly-NUM_FINE_STEPS bestDiffs[lane]=diffs_prev_this[0] @@ -1648,7 +2326,8 @@ class X393McntrlAdjust(object): if (bestDiffs[lane] is None) or (abs (diffs_prev_this[1]) 0) and (adiffs[1] > 0): +# if (adiffs[0] > 0) and (adiffs[1] > 0): + if (lastPositive[0] > NUM_FINE_STEPS) and (lastPositive[0] > NUM_FINE_STEPS): break # no need to continue, data got already for lane in range(len(adiffs)): if bestDiffs[lane] == -1.0: @@ -1664,7 +2343,7 @@ class X393McntrlAdjust(object): if d: print ("%d %s %d: %s"%(phase,branch,i,str(d))) return rslt - return None # All Early/Nominal/Late variants were exhausted, did not find critical DQS inoput delay for this phase value + return None # All Early/Nominal/Late variants were exhausted, did not find critical DQS input delay for this phase value # body of the measure_dqs_idly_phase() dqsi_vs_phase=[] for phase in range (numPhaseSteps): @@ -1702,6 +2381,7 @@ class X393McntrlAdjust(object): sel=1, quiet=1, start_dly=0): #just to check dependence + """ Scan dqs odelay (setting phase appropriately), write 0x0000/0xffff/0x0000/0xffff (same as fixed pattern) data and read it with known dqsi/dqi @@ -1720,7 +2400,23 @@ class X393McntrlAdjust(object): dqsi_phase=self.adjustment_state['dqsi_phase'] num_lanes=len(dqsi_phase) cmda_bspe=self.adjustment_state['cmda_bspe'] - wlev_dqs_bspe=self.adjustment_state['wlev_dqs_bspe'] + + # Replacement for older wlev_dqs_bspe=self.adjustment_state['wlev_dqs_bspe'] + # Can be improved + try: + wlev_p_l= self.get_delays_for_phase(phase = None, + list_branches=False, + target=DQSO_KEY, + b_filter=DFLT_DLY_FILT, + cost=None, # if None - will default to NUM_FINE_STEPS, if 0 - will keep it + quiet = quiet+1) + except: + raise Exception ("No write levelling data is available, this method should run after write levelling and proc_dqso_phase") + numLanes=max(len(wp) for wp in wlev_p_l if not wp is None) + if quiet < 1: + print("numLanes=",numLanes) +# wlev_dqs_bspe=self.adjustment_state['wlev_dqs_bspe'] + brc=(5, # 3'h5, # bank 0x1234, # 15'h1234, # row address 0x100) # 10'h100 # column address @@ -1730,7 +2426,15 @@ class X393McntrlAdjust(object): dly_step=int(NUM_FINE_STEPS*frac_step*timing['SDCLK_PERIOD']/timing['DLY_STEP']+0.5) numPhaseSteps= int(timing['SDCLK_PERIOD']/timing['PHASE_STEP']+0.5) step180= int(NUM_FINE_STEPS*0.5* timing['SDCLK_PERIOD'] / timing['DLY_STEP'] +0.5) - + try: + dqs_patt=self.adjustment_state["dqs_pattern"] + self.x393_mcntrl_timing.axi_set_dqs_dqm_patterns(dqs_patt=dqs_patt, + dqm_patt=None, + quiet=quiet+2) + + except: + print("Skipping DQS pattern (0x55/0xaa) control as it is not in gloabal data (dqs_patt=self.adjustment_state['dqs_pattern'])") + dqs_patt=None #Calculate phase for the best match for the DQS output delay (for both lanes - use average). If # solution for different lanes point to the opposite ends of the phase range - keep previous @@ -1745,7 +2449,7 @@ class X393McntrlAdjust(object): best_phase=None for phase in range(numPhaseSteps): try: - dly_phase=wlev_dqs_bspe[lane][phase]['ldly'] + dly_phase=wlev_p_l[phase][lane] # wlev_dqs_bspe[lane][phase]['ldly'] except: dly_phase=None if (not dly_phase is None) and (cmda_bspe[phase % numPhaseSteps] is None): # check that CMDA odelay exists for this phase @@ -1805,6 +2509,7 @@ class X393McntrlAdjust(object): # print("dly=%d best_phases=%s"%(dly, str(best_phases))) phase_dqso.append(sp) return phase_dqso + def get_dqsi_dqi_for_phase(): # Mark DQS idelay values that have all DQ delays valid # for each phase check that DQS input delay value exists and store DQi varinat (early/nominal/late @@ -1829,8 +2534,8 @@ class X393McntrlAdjust(object): break dqi += dq_lane[8*lane:8*(lane+1)] else: - dqsi_dqi_phase[phase]={'dqsi':dqsi, - 'dqi':dqi, + dqsi_dqi_phase[phase]={DQSI_KEY:dqsi, + DQI_KEY:dqi, 'invert':k in inv_vars, 'variant':k } # dqsi - a pair of dqs input delays, dqi - dq delays for the same phase break @@ -1846,7 +2551,6 @@ class X393McntrlAdjust(object): patt= self.x393_pio_sequences.read_levelling(nrep, -2, # Actually read block, but pre-process as a pattern quiet+1) - #invert pattern if using early/late (not nominal) variants # if (invert_patt): # for i in range(len(patt)): @@ -1905,8 +2609,8 @@ class X393McntrlAdjust(object): print ("Failed to set phase=%d for dly=%d- that should not happen (phase_dqso)- "%(phase,dqs_lin)) return None # no valid CMDA ODELAY exists for this phase #set DQS IDELAY and DQ IDELAY matching phase - dqs_idelay=dqsi_dqi_for_phase[phase]['dqsi'] # 2-element list - dq_idelay= dqsi_dqi_for_phase[phase]['dqi'] # 16-element list + dqs_idelay=dqsi_dqi_for_phase[phase][DQSI_KEY] # 2-element list + dq_idelay= dqsi_dqi_for_phase[phase][DQI_KEY] # 16-element list invert_patt= dqsi_dqi_for_phase[phase]['invert'] # 16-element list self.x393_mcntrl_timing.axi_set_dqs_idelay(combine_delay(dqs_idelay),quiet=quiet) self.x393_mcntrl_timing.axi_set_dq_idelay(combine_delay(dq_idelay),quiet=quiet) @@ -1963,7 +2667,7 @@ class X393McntrlAdjust(object): print ("Could not find initial bounds for DQS output delay = %d d_low=%s, d_high=%s"%(dqs_lin,str(d_low),str(d_high))) return None if quiet < 2: - print ("DQS input delay = %d , preliminary bounds: d_low=%s, d_high=%s"%(dqs_lin,str(d_low),str(d_high))) + print ("DQS outut delay = %d , preliminary bounds: d_low=%s, d_high=%s"%(dqs_lin,str(d_low),str(d_high))) for inPhase in range(2): if not d_high[inPhase] is None: # Try to squeeze d_low, d_high closer to reduce scan range @@ -2040,24 +2744,17 @@ class X393McntrlAdjust(object): if quiet < 2: print ("DQS output delay = %d , tight squeezed bounds: d_low=%s, d_high=%s"%(dqs_lin,str(d_low),str(d_high))) - +# if resetCacheBeforeScan: +# patt_cache=[None]*NUM_DLY_STEPS # cache for holding already measured delays # scan ranges, find closest solutions #compare_prim_steps best_dly= [[],[]] best_diff=[[],[]] for inPhase in range(2): if not d_high[inPhase] is None: -# patt=None best_dly[inPhase]=[d_low[inPhase]]*32 best_diff[inPhase]=[None]*32 -# for b,p in enumerate(patt): -# positiveJump=((not inPhase) and (b<16)) or (inPhase and (b >= 16)) # may be 0, False, True -# if positiveJump: -# best_diff[inPhase].append(p-0.5) -# else: -# best_diff[inPhase].append(0.5-p) for dly in range(d_low[inPhase]+1,d_high[inPhase]+1): -# patt_prev=patt #as measured data is cached, there is no need to specially maintain patt_prev from earlier measurement dly_prev= max(0,dly-(1,NUM_FINE_STEPS)[compare_prim_steps]) patt_prev=measure_block(dly_prev,invert_patt) # ,force_meas=False) - will be stored in cache @@ -2070,7 +2767,7 @@ class X393McntrlAdjust(object): diffs_prev_this=(patt_prev[b]-0.5,patt[b]-0.5) else: diffs_prev_this=(0.5-patt_prev[b],0.5-patt[b]) - if abs(diffs_prev_this[0]) <= abs(diffs_prev_this[1]): # store previos sample + if abs(diffs_prev_this[0]) <= abs(diffs_prev_this[1]): # store previous sample if (best_diff[inPhase][b] is None) or (abs (diffs_prev_this[0])0 -program with this fraction of clk period from the margin @@ -2315,31 +3017,22 @@ class X393McntrlAdjust(object): phase_try_step=numPhaseSteps//8 # when searching for marginal delay, try not optimal+perid/2 but smaller step to accommodate per-bit variations good_patt=0xaaaa bad_patt = good_patt ^ 0xffff - # make sure delay data is available - try: - delays_phase=self.adjustment_state['delays_phase'] - except: - print("Delays for phases (self.adjustment_state['delays_phase']) are not set, running 'get_delays_vs_phase' command ") + # find first suitable phase + for phase in range(numPhaseSteps): try: - delays_phase=self.get_delays_vs_phase(filter_dqo=2, - filter_dqi=2, - filter_dqso=2, - filter_dqsi=2, - filter_cmda=2, - filter_read=0, - filter_write=0, - filter_rsel=None, - filter_wsel=None, - keep_all=False, - set_table=True, - quiet=quiet+2) - self.adjustment_state['delays_phase']=delays_phase + ph_dlys= self.get_all_delays(phase=phase, + filter_cmda= DFLT_DLY_FILT, # may be special case: 'S + filter_dqsi= DFLT_DLY_FILT, + filter_dqi= DFLT_DLY_FILT, + filter_dqso= DFLT_DLY_FILT, #None, # these are not needed here + filter_dqo= DFLT_DLY_FILT, #None, + cost= None, + forgive_missing=False, + quiet= quiet) + if not ph_dlys is None: + break except: - raise Exception("Failed to execute get_'delays_vs_phase' command - probably incomplete calibration data") - # find first suitable phase - for phase,delays in enumerate(delays_phase): - if not delays is None: - break + pass else: raise Exception("Could not find a valid phase to use") #phase is usable delay @@ -2352,11 +3045,18 @@ class X393McntrlAdjust(object): inv_ba, 0) # verbose=0 # set usable timing, enable refresh - OK=self.set_phase_delays(phase=phase, - refresh=True, - quiet=quiet) # all the rest are defaults - if not OK: - raise Exception("measure_addr_odelay(): failed to set phase = %d"%(phase)) + used_delays=self.set_delays(phase=phase, + filter_cmda=DFLT_DLY_FILT, # may be special case: 'S + filter_dqsi=DFLT_DLY_FILT, + filter_dqi= DFLT_DLY_FILT, + filter_dqso=DFLT_DLY_FILT, + filter_dqo= DFLT_DLY_FILT, + cost=None, + refresh=True, + forgive_missing=True, + quiet=quiet) + if used_delays is None: + raise Exception("measure_addr_odelay(): failed to set phase = %d"%(phase)) # #Write 0xaaaa pattern to correct block (all used words), address number - to all with a single bit different self.x393_pio_sequences.set_read_block(ba,ra,ca,nbursts+3,sel_wr) #prepare and writ 'correct' block: @@ -2389,28 +3089,8 @@ class X393McntrlAdjust(object): # For each valid phase, set valid delays, then find marginal delay for one bit (start with the longest available delay? # if got for one bit - try other bits in vicinity # check that the particular phase is valid for all parameters - # To increase valid range it is possible to ignore write delays as they are not used here (recalculate self.adjustment_state['delays_phase'] - # after write is done - filter_cmda=2 - if safe_phase > 0: - filter_cmda=1.0*safe_phase - delays_phase=self.get_delays_vs_phase(filter_dqo=0, #2, - filter_dqi=1, #2, - filter_dqso=0, #2, - filter_dqsi=1, #2, - filter_cmda=filter_cmda, #2, # special mode - try to keep cmda low, with setup violation to test marginal phase - filter_read=0, - filter_write=0, - filter_rsel=None, - filter_wsel=None, - keep_all=False, - set_table=False, # True, - quiet=quiet+2) - if quiet < 2: - print ("delays_phase=",delays_phase) + # To increase valid range it is possible to ignore write delays as they are not used here -# self.adjustment_state['delays_phase']=delays_phase -# delays_phase=self.adjustment_state['delays_phase'] # self.set_phase_delays already ran, but may now need to ease requirements def addr_phase_step(phase): def measure_block(dly, addr_bit, @@ -2456,15 +3136,29 @@ class X393McntrlAdjust(object): return meas # pass # addr_phase_step body # check that the particular phase is valid for all parameters - # To increase valid range it is possible to ignore write delays as they are not used here (recalculate self.adjustment_state['delays_phase'] + # To increase valid range it is possible to ignore write delays as they are not used here # after write is done - # delays_phase=self.adjustment_state['delays_phase'] - if quiet < 1: + if quiet < 2: print ("****** phase=%d ******"%(phase),end=" ") - if delays_phase[phase] is None: - if quiet < 1: - print ("delays_phase[%d] is None"%(phase)) + try: + ph_dlys= self.get_all_delays(phase=phase, + filter_cmda= DFLT_DLY_FILT, # may be special case: 'S + filter_dqsi= DFLT_DLY_FILT, + filter_dqi= DFLT_DLY_FILT, + filter_dqso= None, # these are not needed here + filter_dqo= None, + cost= None, + forgive_missing=False, + quiet= quiet) + if ph_dlys is None: + if quiet < 1: + print ("get_all_delays(%d,...) is None"%(phase)) + return None + + except: + print ("********** Failed get_all_delays(%d,...) is None"%(phase)) return None + dly_optimal= cmda_odly[phase] if dly_optimal is None: if quiet < 1: @@ -2497,10 +3191,19 @@ class X393McntrlAdjust(object): return None # It is not possble to try delay lower than optimal with this method #set phase and all optimal delays for that phase - self.set_phase_delays(phase=phase, - refresh=True, - delays_phase=delays_phase, - quiet=quiet) # all the rest are defaults + #here use special delays for cmda + self.set_delays(phase=phase, + filter_cmda="S%f"%(safe_phase), # DFLT_DLY_FILT, # may be special case: 'S + filter_dqsi=DFLT_DLY_FILT, + filter_dqi= DFLT_DLY_FILT, + filter_dqso=None, #DFLT_DLY_FILT, + filter_dqo= None, #DFLT_DLY_FILT, + cost=None, + refresh=True, + forgive_missing=True, + quiet=quiet) + if used_delays is None: + raise Exception("measure_addr_odelay(): failed to set phase = %d"%(phase)) # Now try #raba_bits [(addr_bit,bank_bit),...] @@ -2603,12 +3306,51 @@ class X393McntrlAdjust(object): cmda_odly_early.append(cmda_odly[phase]) else: cmda_odly_early=cmda_odly - #get write levellimg data + #get write levellimg data - Maybe it is now not needed - just use set_delay()? + try: + wlev_p_l= self.get_delays_for_phase(phase = None, + list_branches=False, + target=DQSO_KEY, + b_filter=DFLT_DLY_FILT, + cost=None, # if None - will default to NUM_FINE_STEPS, if 0 - will keep it + quiet = quiet+1) + except: + raise Exception ("No write levelling data is available, this method should run after write levelling and proc_dqso_phase") + + #set DQS write pattern + try: + self.x393_mcntrl_timing.axi_set_dqs_dqm_patterns(dqs_patt=self.adjustment_state["dqs_pattern"], + dqm_patt=None, + quiet=quiet+2) + except: + print("Skipping DQS pattern (0x55/0xaa) control as it is not in gloabal data (dqs_patt=self.adjustment_state['dqs_pattern'])") + + """ if not "wlev_dqs_bspe" in self.adjustment_state: + print("self.adjustment_state={") + for k,v in self.adjustment_state.items(): + print("\n'%s': %s,"%(k,str(v))) + print("}") + raise Exception ("No wlev_dqs_bspe data is available, this method should run after write levelling") + """ + numLanes=max(len(wp) for wp in wlev_p_l if not wp is None) + if quiet < 1: + print("numLanes=",numLanes) wlev_odly=[] + for lane in range(numLanes): + wlev_lane=[] + for wl_phase in wlev_p_l: + if wl_phase is None or (wl_phase[lane] is None): + wlev_lane.append(None) + else: + wlev_lane.append(wl_phase[lane]) + wlev_odly.append(wlev_lane) + + """ for wlev_data in self.adjustment_state['wlev_dqs_bspe']: wlev_odly.append([None if (wlev_data[phase] is None) else wlev_data[phase]['ldly'] for phase in range(numPhaseSteps)]) + """ if quiet <1: print("wlev_odly=",wlev_odly) #fill gaps (if any - currently none @@ -2630,19 +3372,54 @@ class X393McntrlAdjust(object): wlev_lane[phase]=wlev_lane[otherPhase % numPhaseSteps] if quiet <1: print("wlev_odly=",wlev_odly) + + """ + if quiet <1: + print("wlev_p_l=",wlev_p_l) + #fill gaps (if any - currently none + if quiet <1: + #simulate + wlev_p_l[5][0]=None + wlev_p_l[3][1]=None + print("wlev_p_l=",wlev_p_l) + numLanes=max(len(wp) for wp in wlev_p_l if not wp is None) + if quiet <3: + print("numLanes=",numLanes) + for phase in range(numPhaseSteps): + if wlev_p_l[phase] is None: + wlev_p_l[phase] = [None]*numLanes + + for lane in range(numLanes): + for phase in range(numPhaseSteps): + if wlev_p_l[phase][lane] is None: + otherPhase=None + for p in range(phase-numPhaseSteps/8,phase+numPhaseSteps/8+1): + if not wlev_p_l[p % numPhaseSteps][lane] is None: + if (otherPhase is None) or (abs(phase-p) < abs(phase-otherPhase)): + otherPhase=p + if not otherPhase is None: + print ("phase=",phase,", otherPhase=",otherPhase) + wlev_p_l[phase][lane]=wlev_p_l[otherPhase % numPhaseSteps][lane] + if quiet <1: + print("wlev_p_l=",wlev_p_l) + """ + + + #shift by 90 degrees wlev_odly_late=[] for wlev_lane in wlev_odly: wlev_odly_late.append(wlev_lane[3*numPhaseSteps//4:]+wlev_lane[:3*numPhaseSteps//4]) if quiet <1: print("wlev_odly_late=",wlev_odly_late) + """ if quiet <1: for phase,dly in enumerate(cmda_odly): ldly=None if not self.adjustment_state['cmda_bspe'][phase] is None: ldly=self.adjustment_state['cmda_bspe'][phase]['ldly'] print("%d %s %s"%(phase,str(dly),str(ldly))) - + """ dly_try_step=NUM_FINE_STEPS # how far to step when looking for zero crossing (from predicted) phase_try_step=numPhaseSteps//8 # when searching for marginal delay, try not optimal+perid/2 but smaller step to accommodate per-bit variations #turn off refresh - it will not be needed in this test @@ -2774,11 +3551,6 @@ class X393McntrlAdjust(object): return None # It is not possble to try delay lower than optimal with this method #set phase and all optimal delays for that phase - # Maybe it is not needed at all? -# self.set_phase_delays(phase=phase, -# refresh=True, -# delays_phase=delays_phase, -# quiet=quiet) # all the rest are defaults dlyOK=set_delays_with_reinit(phase=phase, restart=False) # will check wlev and re-init if required if dlyOK is None: if quiet < 1: @@ -2859,6 +3631,41 @@ class X393McntrlAdjust(object): self.x393_pio_sequences.set_write_lev(16,False) # write leveling - 'good' mode (if it was not set so) return cmd_odelay + + def _map_varinats(self, + list_variants): + """ + @param list_variants list of sets of variants - for each variant find the longest steak (rolls over the end of the list) + @return dictionary with keys - variants, and values - tuples of starts and lengths of the longest streak + + """ + l=len(list_variants) + streaks={} + prev_vars=list_variants[l-1] + all_variants=set() + for s_phase, variants in enumerate(list_variants): + if variants: + all_variants |= variants + if prev_vars: + new_vars = variants - prev_vars + else: + new_vars = variants + for new_var in new_vars: + for streak_len in range(1,l): + if (list_variants[(s_phase+streak_len) % l] is None) or (not new_var in list_variants[(s_phase+streak_len) % l]): + if (not new_var in streaks) or (streaks[new_var][1] + filter_dqsi=None, #no need to read - just write + filter_dqi= None, + filter_dqso=DFLT_DLY_FILT, + filter_dqo= DFLT_DLY_FILT, + forgive_missing=False, + cost=None, + quiet=quiet+2) + for phase, v in enumerate(write_valid): + if not v is None: + break + else: + raise Exception("Could not find any valid phase for writing") + used_delay=self.set_delays(phase=phase, + filter_cmda=DFLT_DLY_FILT, # may be special case: 'S + filter_dqsi=None, #no need to read - just write + filter_dqi= None, + filter_dqso=DFLT_DLY_FILT, + filter_dqo= DFLT_DLY_FILT, + cost=None, + refresh=True, + forgive_missing=False, + quiet=quiet+2) + if used_delay is None: + raise Exception("Failed to set delay for writing block") + #write_block_inc, it may turn out to be shifted, have problems at the beginning or end - write is not set up yet + self.x393_pio_sequences.write_block_inc(num8=64, # max 512 16-bit words + startValue=startValue, + ca=ca, + ra=ra, + ba=ba, + extraTgl=extraTgl, + sel=wsel, + quiet=quiet+1) + + for variant, phase in centers.items(): #variant now a tuple of cmda variant an dqi variant which + used_delays=self.set_delays(phase=phase, + filter_cmda=[variant[0]], # may be special case: 'S + filter_dqsi=[variant[1][0]], + filter_dqi= [variant[1]], + filter_dqso=None, + filter_dqo= None, + cost=None, + refresh=True, + forgive_missing=False, + quiet=quiet+1) + if used_delays is None: + raise Exception("set_read_branch(): failed to set phase = %d"%(phase)) wbuf_dly_max=12 wdly=max(0,min(wbuf_dly,wbuf_dly_max)) rsel=0 #set_and_read_inc 8 16 0 0 1 1 last_wstep=0 read_problems=None - for _ in range(20): + for _ in range(20): # limit numer of repetiotions - just in case self.x393_mcntrl_timing.axi_set_wbuf_delay(wdly) read_problems=self.x393_pio_sequences. set_and_read_inc(num8=8, # max 512 16-bit words ca=ca+16, @@ -2956,7 +3837,7 @@ class X393McntrlAdjust(object): last_wstep = 1 wdly += 1 if wdly >= wbuf_dly_max: - print("Exceeded maximal write buffer delay = %d while setting up read for branch '%s', phase=%d"%(wdly,var,phase)) + print("Exceeded maximal write buffer delay = %d while setting up read for branch '%s', phase=%d"%(wdly,str(variant),phase)) read_problems=None break # continue with next branch continue @@ -2969,18 +3850,17 @@ class X393McntrlAdjust(object): last_wstep =- 1 wdly -= 1 if wdly < 1: - print("Exceeded minimal write buffer delay = %d while setting up read for branch '%s', phase=%d"%(wdly,var,phase)) + print("Exceeded minimal write buffer delay = %d while setting up read for branch '%s', phase=%d"%(wdly,str(variant),phase)) read_problems=None break # continue with next branch continue break # close to target if read_problems is None: continue # could not get initial wbuf delay -# read_problems_initial=read_problems read_problems_min=read_problems best_dw,best_sel=(0,0) if quiet < 2: - print("var=",var) + print("variant=",variant) print("Read_problems_min=",read_problems_min) print("wdly=",wdly) print("rsel=",rsel) @@ -3009,24 +3889,24 @@ class X393McntrlAdjust(object): print("-sum(read_problems_min)=",sum(read_problems_min)) if sum(read_problems_min) ==0: - rslt[var]={'wbuf_dly':wdly, 'sel':rsel} + rslt[variant]={'wbuf_dly':wdly, 'sel':rsel} if quiet < 2: print("-rslt=",rslt) elif (read_problems_min[0]%2) or (read_problems_min[1]%2): - odd_list.append(var) + odd_list.append(variant) if quiet < 3: print("Failed to find read settings for varinat '%s', phase=%d - best start read errors=%d, end read errors=%d"%( - var,phase,read_problems_min[0],read_problems_min[1])) + str(variant),phase,read_problems_min[0],read_problems_min[1])) print("Odd number of wrong read words means that there is a half clock period shift, you may need to change") print("primary_set parameter of proc_dqi_dqsi() from 2 to 0" ) else: if quiet < 2: print("Failed to find read settings for varinat '%s', phase=%d - best start read errors=%d, end read errors=%d"%( - var,phase,read_problems_min[0],read_problems_min[1])) + str(variant),phase,read_problems_min[0],read_problems_min[1])) if quiet < 2: print("odd_list=",odd_list) - for var,v in rslt.items(): + for v in rslt.values(): try: self.x393_mcntrl_timing.axi_set_wbuf_delay(v['wbuf_dly']) break @@ -3037,11 +3917,13 @@ class X393McntrlAdjust(object): rslt[ODD_KEY]=odd_list self.adjustment_state['read_variants']=rslt - if quiet < 3: print ('read_variants=',rslt) return rslt + + + def set_write_branch(self, dqs_pattern=None, quiet=1): @@ -3057,6 +3939,8 @@ class X393McntrlAdjust(object): @return dictioray with a key(s) (early,nominal,late) containing dictionary of {'wbuf_dly':xx, 'sel':Y} or value 'ODD' if the remaining number of errors is odd """ + #temporarily: + self.load_mcntrl('dbg/proc_addr_odelay_0x55.pickle') #write/used block parameters startValue=0 num8=8 # 8 bursts to read/write @@ -3069,91 +3953,224 @@ class X393McntrlAdjust(object): readVarKey='read_variants' if dqs_pattern is None: - dqs_pattern=vrlg.DFLT_DQS_PATTERN - else: # only set if not None - self.x393_mcntrl_timing.axi_set_dqs_dqm_patterns(dqs_patt=dqs_pattern, # use default - dqm_patt=None, # use default - quiet=quiet+2) - try: - delays_phase=self.adjustment_state['delays_phase'] - except: - print("Delays for phases (self.adjustment_state['delays_phase']) are not set, running 'get_delays_vs_phase' command ") try: - delays_phase=self.get_delays_vs_phase(filter_dqo=2, - filter_dqi=2, - filter_dqso=2, - filter_dqsi=2, - filter_cmda=2, - filter_read=0, - filter_write=0, - filter_rsel=None, - filter_wsel=None, - keep_all=False, - set_table=True, - quiet=quiet+2) - self.adjustment_state['delays_phase']=delays_phase + dqs_pattern=self.adjustment_state["dqs_pattern"] except: - print ("Failed to execute get_'delays_vs_phase' command") - return False + dqs_pattern=vrlg.DFLT_DQS_PATTERN + self.adjustment_state["dqs_pattern"] = dqs_pattern + print("Setting default DQS wirite pattern to self.adjustment_state['dqs_pattern'] and to hardware. Check that write levelling already ran") + self.x393_mcntrl_timing.axi_set_dqs_dqm_patterns(dqs_patt=dqs_pattern, + dqm_patt=None, + quiet=quiet+2) + """ +read_variants= {(-1, (0, 0)): {'sel': 1, 'wbuf_dly': 9}, + (0, (0, 0)): {'sel': 0, 'wbuf_dly': 8}} + """ + try: readVars=self.adjustment_state[readVarKey] except: raise Exception ("Read variants are not set up, need to run command set_read_branch90 first") - #verify read varinats have valid (not "ODD") branch - readBranch=None - for var in readVars: - if var != ODD_KEY: - readBranch=var - break - else: + + read_var_set=set() + for variant in readVars: + if variant != ODD_KEY: + read_var_set.add(variant) + + if not read_var_set: raise Exception ("No valid read variant is found, can not proceed with write setup") - readPhase=None - #find one valid phase per existing branch - phase_var={} - read_phase_var={} - for phase, dlys in enumerate(delays_phase): + + + + + cmda_vars= self.get_delays_for_phase(phase = None, + list_branches=True, + target=CMDA_KEY, + b_filter=None, # will default to earliest (lowest delay) branch, same as 'e', + cost=None, # if None - will default to NUM_FINE_STEPS, if 0 - will keep it + quiet = quiet+2) + dqsi_vars= self.get_delays_for_phase(phase = None, + list_branches=True, + target=DQSI_KEY, + b_filter=None, # will default to earliest (lowest delay) branch, same as 'e', + cost=None, # if None - will default to NUM_FINE_STEPS, if 0 - will keep it + quiet = quiet+2) + dqi_vars= self.get_delays_for_phase(phase = None, + list_branches=True, + target=DQI_KEY, + b_filter=None, # will default to earliest (lowest delay) branch, same as 'e', + cost=None, # if None - will default to NUM_FINE_STEPS, if 0 - will keep it + quiet = quiet+2) + dqso_vars= self.get_delays_for_phase(phase = None, + list_branches=True, + target=DQSO_KEY, + b_filter=None, # will default to earliest (lowest delay) branch, same as 'e', + cost=None, # if None - will default to NUM_FINE_STEPS, if 0 - will keep it + quiet = quiet+2) + dqo_vars= self.get_delays_for_phase(phase = None, + list_branches=True, + target=DQO_KEY, + b_filter=None, # will default to earliest (lowest delay) branch, same as 'e', + cost=None, # if None - will default to NUM_FINE_STEPS, if 0 - will keep it + quiet = quiet+2) + numPhases=len(cmda_vars) + write_phase_variants=[] +# all_read_variants=set() + #1. make a list of all write variants, + #2. try to find an intersection with valid read branch + #3. if not all found - use one of other branches, if none found - use any read branch + + for phase,cmda,dqso,dqo in zip(range(numPhases),cmda_vars,dqso_vars,dqo_vars): + if quiet < 3: + print ("phase=",phase,', cmda=',cmda,', dqso=',dqso,', dqo=',dqo) + if all([cmda,dqso,dqo]): + rv=set() + for cv in cmda: + for dv in dqo: + if dv[0] in dqso: + rv.add((cv,dv)) + if rv: + write_phase_variants.append(rv) +# all_read_variants |= rv + else: + write_phase_variants.append(None) +# print ("rv is not - it is ",rv) + else: + write_phase_variants.append(None) +# print ("Some are not: phase=",phase,', cmda=',cmda,', dqsi=',dqsi,', dqi=',dqi) + if quiet < 3: + print("\nwrite_phase_variants:") + for phase, v in enumerate(write_phase_variants): + print("%d: %s"%(phase,str(v))) + + #variant - just for writing + write_only_map=self._map_varinats(write_phase_variants) + if quiet < 3: + print ("write_only_map=",write_only_map) + + read_write_variants=[] + for phase,cmda,dqso,dqo,dqsi,dqi in zip(range(numPhases),cmda_vars,dqso_vars,dqo_vars,dqsi_vars,dqi_vars): + if quiet < 3: + print ("phase=",phase,', cmda=',cmda,', dqso=',dqso,', dqo=',dqo,', dqsi=',dqsi,', dqi=',dqi) + if all([cmda,dqso,dqo,dqsi,dqi]): + rv=set() + for cv in cmda: + for dvo in dqo: + if dvo[0] in dqso: + for dvi in dqi: + if (dvi[0] in dqsi) and ((cv,dvi) in read_var_set): + rv.add((cv,dvo,dvi)) + if rv: + read_write_variants.append(rv) +# all_read_variants |= rv + else: + read_write_variants.append(None) +# print ("rv is not - it is ",rv) + else: + read_write_variants.append(None) +# print ("Some are not: phase=",phase,', cmda=',cmda,', dqsi=',dqsi,', dqi=',dqi) + if quiet < 3: + print("\nread_write_variants:") + for phase, v in enumerate(read_write_variants): + print("%d: %s"%(phase,str(v))) + #read/write variants + + read_write_map=self._map_varinats(read_write_variants) + if quiet < 3: + print ("read_write_map=",read_write_map) + + + if not read_write_map: + default_read_var=readVars.keys()[0] + default_read={'cmda_read': default_read_var[0], + 'dqi': default_read_var[1], + 'dqs': default_read_var[1][0], + 'read_phase':(readVars[default_read_var][0]+readVars[default_read_var][1]//2)% numPhases} + else: # take a first in r/w map + default_read_var=read_write_map.keys()[0] + default_read={'cmda_read': default_read_var[0], # center of the first interval that works both for read and write + 'dqi': default_read_var[2], + 'dqsi': default_read_var[2][0], + 'read_phase':(read_write_map[default_read_var][0]+read_write_map[default_read_var][1]//2)% numPhases} + # now go through all write only ramnges, try to find included r/w one, if not - use default_read + write_variants={} + for k_wo in write_only_map.keys(): try: - for k,v in dlys[DQO_KEY].items(): - if not None in v: - if not k in phase_var: - phase_var[k]=phase - if not k in read_phase_var: # read phase is not set yet for this write variant - if not None in dlys[DQI_KEY][readBranch]: # usually will fail here - phase_var[k]= phase - read_phase_var[k] = phase - readPhase= phase # will hold phase that - except: - pass - if quiet <2: - print ("phase_var=",phase_var) - print ("readPhase=",readPhase) - print ("read_phase_var=",read_phase_var) - if not phase_var: - raise Exception("Could not find any valid phase for writing to consider") - if readPhase is None: #find some phase to correctly read data, even if it does not match any write phase - for phase, dlys in enumerate(delays_phase): - try: - if not None in dlys[DQI_KEY][readBranch]: # usually will fail here - readPhase= phase + for k_rw in read_write_map.keys(): + if (k_rw[0],k_rw[1]) == k_wo: + phase=(read_write_map[k_rw][0]+read_write_map[k_rw][1]//2)% numPhases + write_variants[k_wo]={'cmda_read': k_rw[0], + 'cmda_write': k_rw[0], + 'dqi': k_rw[2], + 'dqsi': k_rw[2][0], + 'dqo': k_rw[1], + 'dqso': k_rw[1][0], + 'read_phase': phase, + 'write_phase': phase} break - except: - pass - else: - raise Exception("Could not find any valid phase to read block correctly") - #see if any of the write varinats does not have read phase - use default readPhase - for var in phase_var: - if not var in read_phase_var: - read_phase_var[var]=readPhase + else: + raise Exception("failed") # just to get to "except" + except: + phase=(write_only_map[k_wo][0]+read_write_map[k_wo][1]//2)% numPhases + write_variants[k_wo]={'cmda_write': k_wo[0], + 'dqo': k_wo[1], + 'dqso': k_wo[1][0], + 'write_phase': phase} + write_variants[k_wo].update(default_read) + if quiet < 3: + print ("write_variants=",write_variants) + """ +write_variants= { + (0, (0, -1)): { + 'dqsi': 0, + 'cmda_write': 0, + 'write_phase': 37, + 'read_phase': 37, + 'dqso': 0, + 'cmda_read': 0, + 'dqo': (0, -1), + 'dqi': (0, 0)}, + (-1, (0, 0)): { + 'dqsi': 0, + 'cmda_write': -1, + 'write_phase': 85, + 'read_phase': 85, + 'dqso': 0, + 'cmda_read': -1, + 'dqo': (0, 0), + 'dqi': (0, 0)}, + (-1, (0, -1)): { + 'dqsi': 0, + 'cmda_write': -1, + 'write_phase': 46, + 'read_phase': 46, + 'dqso': 0, + 'cmda_read': -1, + 'dqo': (0, -1), + 'dqi': (0, 0)}, + (-1, (-1, -1)): { + 'dqsi': 0, + 'cmda_write': -1, + 'write_phase': 92, + 'read_phase': 92, + 'dqso': -1, + 'cmda_read': -1, + 'dqo': (-1, -1), + 'dqi': (0, 0)}} + """ + + + - if quiet <2: - print ("phase_var=",phase_var) - print ("readPhase=",readPhase) - print ("read_phase_var=",read_phase_var) - - if quiet <1: - print ("readVars=",readVars) + + + + + return + + ''' self.x393_mcntrl_timing.axi_set_wbuf_delay(readVars[readBranch]['wbuf_dly']) rsel=readVars[readBranch]['sel'] odd_list=[] @@ -3161,11 +4178,20 @@ class X393McntrlAdjust(object): problems_min=None best_wsel=None for wsel in range (2): - OK=self.set_phase_delays(phase=phase, - refresh=True, - quiet=quiet+2) # all the rest are defaults - if not OK: - raise Exception("set_read_branch(): failed to set phase = %d"%(phase)) + used_delays=self.set_delays(phase=phase, + filter_cmda=DFLT_DLY_FILT, # may be special case: 'S + filter_dqsi=DFLT_DLY_FILT, + filter_dqi= DFLT_DLY_FILT, + filter_dqso=DFLT_DLY_FILT, + filter_dqo= DFLT_DLY_FILT, + cost=None, + refresh=True, + forgive_missing=True, + quiet=quiet+2) + if used_delays is None: + raise Exception("measure_addr_odelay(): failed to set phase = %d"%(phase)) + + self.x393_pio_sequences.write_block_inc(num8=num8, # max 512 16-bit words startValue=startValue, ca=ca, @@ -3178,11 +4204,18 @@ class X393McntrlAdjust(object): startValue += 0x200 startValue &= 0xffff if phase != read_phase_var[var]: - OK=self.set_phase_delays(phase=read_phase_var[var], - refresh=True, - quiet=quiet+2) # all the rest are defaults - if not OK: - raise Exception("set_read_branch(): failed to set phase = %d"%(phase)) + used_delays=self.set_delays(phase=read_phase_var[var], + filter_cmda=DFLT_DLY_FILT, # may be special case: 'S + filter_dqsi=DFLT_DLY_FILT, + filter_dqi= DFLT_DLY_FILT, + filter_dqso=DFLT_DLY_FILT, + filter_dqo= DFLT_DLY_FILT, + cost=None, + refresh=True, + forgive_missing=True, + quiet=quiet+2) + if used_delays is None: + raise Exception("set_write_branch(): failed to set phase = %d"%(phase)) problems=self.x393_pio_sequences. set_and_read_inc(num8=num8, # max 512 16-bit words ca=ca, ra=ra, @@ -3215,6 +4248,8 @@ class X393McntrlAdjust(object): if quiet < 3: print ('write_variants=',rslt) return rslt + ''' + def get_phase_range(self, rsel=None, # None (any) or 0/1 @@ -3237,6 +4272,19 @@ class X393McntrlAdjust(object): write_variants=self.adjustment_state['write_variants'] except: write_variants=None + return + try: + dqs_pattern=self.adjustment_state["dqs_pattern"] + except: + dqs_pattern=vrlg.DFLT_DQS_PATTERN + self.adjustment_state["dqs_pattern"] = dqs_pattern + print("Setting default DQS wirite pattern to self.adjustment_state['dqs_pattern'] and to hardware. Check that write levelling already ran") + self.x393_mcntrl_timing.axi_set_dqs_dqm_patterns(dqs_patt=dqs_pattern, + dqm_patt=None, + quiet=quiet+2) + + #FIXME: + """ try: delays_phase=self.get_delays_vs_phase(filter_dqo=2, filter_dqi=2, @@ -3255,6 +4303,8 @@ class X393McntrlAdjust(object): except: print ("Failed to execute 'get_delays_vs_phase' command") return None + """ + delays_phase=None phase_starts=[] numPhases=len(delays_phase) for phase,dlys in enumerate (delays_phase): @@ -3316,17 +4366,21 @@ class X393McntrlAdjust(object): self.adjustment_state['optimal_phase']=rslt #set delays to set Verilog parameters. TODO: save sel-s somehow too? + #TODO: redo the following code + print('write_var=',write_var) + """ self.set_phase_delays(phase=optimal_phase, inp_period=read_var, out_period=write_var, refresh=False, delays_phase=delays_phase, # if None - use global quiet=quiet) + """ return rslt def measure_all(self, - tasks="ICWRPOASZB", + tasks="ICWRPOA", #"ICWRPOASZB", prim_steps=1, primary_set_in=2, primary_set_out=2, @@ -3346,6 +4400,10 @@ class X393McntrlAdjust(object): @param quiet reduce output """ # dqs_pattern=0x55 # 0xaa + try: + s_dqs_pattern="0x%x"%(dqs_pattern) + except: + s_dqs_pattern="" max_phase_err=0.1 frac_step=0.125 # read_sel=1 # set DDR3 command in the second cycle of two (0 - during the first omne) @@ -3357,7 +4415,9 @@ class X393McntrlAdjust(object): idly_phase_sel=1 bin_size_ps=50.0 read_phase_scale_w=0.0 + write_phase_scale_w=0.0 prim_steps_in=prim_steps + prim_steps_wl=prim_steps prim_steps_out=prim_steps wbuf_dly=9 # just a hint, start value can be different # primary_set_in=2 @@ -3365,7 +4425,9 @@ class X393McntrlAdjust(object): write_sel=1 # set DDR3 command in the second cycle of two (0 - during the first omne) safe_phase=0.25 # 0: strictly follow cmda_odelay, >0 -program with this fraction of clk period from the margin commonFine=True, # use same values for fine delay for address/bank lines - addr_odly_max_err= 0.125 # 1/8 period + DqsiMaxDlyErr=200.0 # currently just to check multiple overlapping DQSI branches + DqsoMaxDlyErr=200.0 # currently just to check multiple overlapping DQSI branches + CMDAMaxDlyErr=200.0 # currently just to check multiple overlapping DQSI branches task_data=[ {'key':'I', 'func':self.x393_pio_sequences.task_set_up, @@ -3379,21 +4441,43 @@ class X393McntrlAdjust(object): 'reinits':1, 'max_phase_err':max_phase_err, 'quiet':quiet+1}}, + {'key':'W', - 'func':self.adjust_write_levelling, + 'func':self.measure_write_levelling, 'comment':'Write levelling - measuring optimal DQS output delay for each phase', - 'params':{'start_phase':0, + 'params':{'compare_prim_steps':prim_steps_wl, + 'start_phase':0, 'reinits':1, 'invert':0, - 'max_phase_err':max_phase_err, + 'dqs_patt':dqs_pattern, + 'quiet':quiet+1}}, + # See what depends on it to use self.proc_dqo_dqso instead . Probably use self.proc_dqsi_phase with None for parameters + # Use zero finedelay and estimated step duration +# {'key':'W', +# 'func':self.proc_write_levelling, +# 'comment':'Processing measure write levellingresults', +# 'params':{'data_set_number':-1, +# 'max_phase_err':max_phase_err, +# 'quiet':quiet+1}}, + + {'key':'W', + 'func':self.proc_dqso_phase, + 'comment':'Processing measured write levelling results', + 'params':{'lane':'All', + 'bin_size_ps':bin_size_ps, + 'data_set_number':-1, # use measured data + 'scale_w':write_phase_scale_w, + 'maxDlyErr':DqsoMaxDlyErr, 'quiet':quiet+1}}, + + {'key':'A', 'func':self.measure_cmd_odelay, 'comment':'Measuring command (WE, RAS, CAS) lines output delays', 'params':{'safe_phase':safe_phase, 'reinits': 1, 'tryWrongWlev': 1, - 'quiet':quiet+1}}, + 'quiet': quiet+1}}, {'key':'R', 'func':self.measure_pattern, 'comment':'Read levelling - measuring predefined pattern to determine DQ input delays relative to DQS ones', @@ -3418,12 +4502,13 @@ class X393McntrlAdjust(object): 'sel':idly_phase_sel, 'quiet':quiet+1}}, {'key':'P', - 'func':self.proc_dqsi_phase, # compare_prim_steps??? + 'func':self.proc_dqsi_phase, 'comment':'Calculate optimal DQS input delays vs. clock phase', 'params':{'lane':'All', 'bin_size_ps':bin_size_ps, 'data_set_number':-1, # use measured data 'scale_w':read_phase_scale_w, + 'maxDlyErr':DqsiMaxDlyErr, 'quiet':quiet+1}}, {'key':'O', 'func':self.measure_dqo_dqso, @@ -3443,6 +4528,23 @@ class X393McntrlAdjust(object): 'scale_w':write_scale_w, 'quiet':quiet+1}}, + {'key':'O', + 'func':self.proc_dqso_phase, + 'comment':'Calculate optimal DQS output delays vs. clock phase', + 'params':{'lane':'All', + 'bin_size_ps':bin_size_ps, + 'data_set_number':-1, # use measured data + 'scale_w':write_phase_scale_w, + 'maxDlyErr':DqsoMaxDlyErr, + 'quiet':quiet+1}}, + + {'key':'O', + 'func':self.save_mcntrl, + 'comment':'Save current state as Python pickle', + 'params':{'path': 'proc_dqso_phase_%s.pickle'%(s_dqs_pattern), # None, # use path defined by the parameter 'PICKLE' + 'quiet':quiet+1}}, + + {'key':'A', 'func':self.measure_addr_odelay, 'comment':'Measuring address and bank lines output delays', @@ -3455,25 +4557,29 @@ class X393McntrlAdjust(object): 'func':self.proc_addr_odelay, 'comment':'Processing address and bank lines output delays (using average data for RAS,CAS, WE output delays)', 'params':{'commonFine':commonFine, - 'max_err':addr_odly_max_err, + 'maxErrPs':CMDAMaxDlyErr, 'quiet':quiet+1}}, - - {'key':'S', - 'func':self.get_delays_vs_phase, - 'comment':'Setting calculated delays to global parameters to be used when setting phase', - 'params':{'filter_dqo': 2, - 'filter_dqi': 2, - 'filter_dqso':2, - 'filter_dqsi':2, - 'filter_cmda':2, - 'filter_read':0, - 'filter_write':0, - 'filter_rsel':None, - 'filter_wsel':None, - 'keep_all':False, - 'set_table':True, + {'key':'A', + 'func':self.save_mcntrl, + 'comment':'Save current state as Python pickle', + 'params':{'path': 'proc_addr_odelay_%s.pickle'%(s_dqs_pattern), # None, # use path defined by the parameter 'PICKLE' 'quiet':quiet+1}}, - + +# {'key':'S', +# 'func':self.get_delays_vs_phase, +# 'comment':'Setting calculated delays to global parameters to be used when setting phase', +# 'params':{'filter_dqo': 2, +# 'filter_dqi': 2, +# 'filter_dqso':2, +# 'filter_dqsi':2, +# 'filter_cmda':2, +# 'filter_read':0, +# 'filter_write':0, +# 'filter_rsel':None, +# 'filter_wsel':None, +# 'keep_all':False, +# 'set_table':True, +# 'quiet':quiet+1}}, {'key':'B', 'func':self.set_read_branch, 'comment':'Try read mode branches and find sel (early/late read command) and wbuf delay, if possible.', @@ -3495,30 +4601,30 @@ class X393McntrlAdjust(object): 'comment':'Save current state as Python pickle', 'params':{'path': None, # use path defined by the parameter 'PICKLE' 'quiet':quiet+1}}, - {'key':'Z', - 'func':self.show_all_vs_phase, - 'comment':'Printing results table (delays and errors vs. phase)- all, including invalid phases', - 'params':{'keep_all':True, - 'filter_rw':False, - 'filter_rsel':None, - 'filter_wsel':None, - 'load_hardcoded':False}}, - {'key':'Z', - 'func':self.show_all_vs_phase, - 'comment':'Printing results table (delays and errors vs. phase)- only for valid clock phase values', - 'params':{'keep_all':False, - 'filter_rw':False, - 'filter_rsel':None, - 'filter_wsel':None, - 'load_hardcoded':False}}, - {'key':'BZ', - 'func':self.show_all_vs_phase, - 'comment':'Printing results table, filtered by read/write blocks', - 'params':{'keep_all':False, - 'filter_rw':True, - 'filter_rsel':rsel, - 'filter_wsel':wsel, - 'load_hardcoded':False}}, +# {'key':'Z', +# 'func':self.show_all_vs_phase, +# 'comment':'Printing results table (delays and errors vs. phase)- all, including invalid phases', +# 'params':{'keep_all':True, +# 'filter_rw':False, +# 'filter_rsel':None, +# 'filter_wsel':None, +# 'load_hardcoded':False}}, +# {'key':'Z', +# 'func':self.show_all_vs_phase, +# 'comment':'Printing results table (delays and errors vs. phase)- only for valid clock phase values', +# 'params':{'keep_all':False, +# 'filter_rw':False, +# 'filter_rsel':None, +# 'filter_wsel':None, +# 'load_hardcoded':False}}, +# {'key':'BZ', +# 'func':self.show_all_vs_phase, +# 'comment':'Printing results table, filtered by read/write blocks', +# 'params':{'keep_all':False, +# 'filter_rw':True, +# 'filter_rsel':rsel, +# 'filter_wsel':wsel, +# 'load_hardcoded':False}}, ] start_time=time.time() last_task_start_time=start_time @@ -3558,7 +4664,7 @@ class X393McntrlAdjust(object): # self.adjustment_state['addr_odelay_meas']= get_test_dq_dqs_data.get_addr_meas() self.adjustment_state['addr_meas']= get_test_dq_dqs_data.get_addr_meas() - self.adjustment_state['addr_odelay']= get_test_dq_dqs_data.get_addr_odly() + self.adjustment_state['addr_odelay']= get_test_dq_dqs_data.get_cmda_odelay() # get_addr_odly() self.adjustment_state['cmd_meas']= get_test_dq_dqs_data.get_cmd_meas() @@ -3622,7 +4728,7 @@ class X393McntrlAdjust(object): rslt = lma.lma_fit_dq_dqs(lane, bin_size, 1000.0*self.x393_mcntrl_timing.get_dly_steps()['SDCLK_PERIOD'], # 2500.0, # clk_period, - 78.0, # dly_step_ds, + 1000.0*self.x393_mcntrl_timing.get_dly_steps()['DLY_STEP'], # 78.0, # dly_step_ds, primary_set, meas_delays, compare_prim_steps, @@ -3656,6 +4762,7 @@ class X393McntrlAdjust(object): bin_size_ps=50, data_set_number=0, # not number - use measured data scale_w=0.1, # weight for "uncertain" values (where samples chane from all 0 to all 1 in one step) + maxDlyErr=200, #ps - trying overlapping dqs branches quiet=1): """ Run DQSI vs PHASE fitting for one data lane (0 or 1) using earlier acquired hard-coded data @@ -3666,7 +4773,8 @@ class X393McntrlAdjust(object): fine range wider than on primary step) If not number or <0 - use measured data @param scale_w weight for "uncertain" values (where samples change from all 0 to all 1 in one step) - For sufficient data 0.0 is OK (and seems to work better)- only "analog" samples are considered + For sufficient data 0.0 is OK (and seems to work better)- only "analog" samples are considered + @param maxDlyErr - maximal DQS error in ps (currently just to check multiple overlapping branches) @param quiet reduce output @return 3-element dictionary of ('early','nominal','late'), each being None or a 160-element list, each element being either None, or a list of 3 best DQ delay values for the DQS delay (some mey be None too) @@ -3680,13 +4788,24 @@ class X393McntrlAdjust(object): compare_prim_steps= get_test_dq_dqs_data.get_dqsi_vs_phase_prim_steps(data_set_number) dqsi_phase_data= get_test_dq_dqs_data.get_dqsi_vs_phase(data_set_number) dqsi_dqi_parameters=get_test_dq_dqs_data.get_dqi_dqsi_parameters() + try: + dqsi_dqi_parameters=get_test_dq_dqs_data.get_dqi_dqsi_parameters() + except: + dqsi_dqi_parameters=None + if quiet < 4: + print("DQ vs. DQS input delays calibration parameters are not available yet will use estimated ones") else: if quiet < 4: print("Using measured data set") try: compare_prim_steps= self.adjustment_state["dqsi_vs_phase_steps"] dqsi_phase_data= self.adjustment_state["dqsi_vs_phase"] - dqsi_dqi_parameters= self.adjustment_state["dqi_dqsi_parameters"] + try: + dqsi_dqi_parameters= self.adjustment_state["dqi_dqsi_parameters"] + except: + dqsi_dqi_parameters=None + if quiet < 4: + print("DQ vs. DQS input delays calibration parameters are not available yet will use estimated ones") except: print ("DQS input delay vs. phase measured data is not available, exiting") return @@ -3696,17 +4815,141 @@ class X393McntrlAdjust(object): # print("++++++proc_dqsi_phase(), quiet=",quiet) - dqsi_phase=lma.lma_fit_dqsi_phase(lane, # byte lane - bin_size_ps, - 1000.0*self.x393_mcntrl_timing.get_dly_steps()['SDCLK_PERIOD'], # 2500.0, # clk_period, - dqsi_dqi_parameters, - dqsi_phase_data, # data_set, - compare_prim_steps, - scale_w, - numPhaseSteps, - quiet) - self.adjustment_state.update(dqsi_phase) - return dqsi_phase + dqs_phase=lma.lma_fit_dqs_phase(lane= lane, # byte lane + bin_size_ps= bin_size_ps, + clk_period= 1000.0*self.x393_mcntrl_timing.get_dly_steps()['SDCLK_PERIOD'], # 2500.0, # clk_period, + dqs_dq_parameters= dqsi_dqi_parameters, + tSDQS= 1000.0*self.x393_mcntrl_timing.get_dly_steps()['DLY_STEP']/NUM_FINE_STEPS, # 78.0/5, # dly_step_ds, + data_set= dqsi_phase_data, # data_set, + compare_prim_steps= compare_prim_steps, + scale_w= scale_w, + numPhaseSteps= numPhaseSteps, + maxDlyErr= maxDlyErr, + fallingPhase= False, # fallingPhase + shiftFracPeriod= 0.5, # provided data is marginal, not centered + quiet= quiet) +# rslt_names=("dqs_optimal_ps","dqs_phase","dqs_phase_multi","dqs_phase_err","dqs_min_max_periods") + gen_keys=dqs_phase.keys() + for k in gen_keys: + dqs_phase[k.replace('dqs_','dqsi_')]=dqs_phase.pop(k) + if quiet < 3: + print ("dqsi_phase=",dqs_phase) + self.adjustment_state.update(dqs_phase) + + #combine DQSI and DQI data to get DQ vs. phase + delays, errors= self._combine_dq_dqs(dqs_data=self.adjustment_state['dqsi_phase_multi'], + dq_enl_data=self.adjustment_state["dqi_dqsi"], + dq_enl_err = self.adjustment_state["maxErrDqsi"], + quiet=quiet) + self.adjustment_state['dqi_phase_multi'] = delays + self.adjustment_state["dqi_phase_err"] = errors + return dqs_phase + + def proc_dqso_phase(self, + lane=0, # "all", + bin_size_ps=50, + data_set_number=0, # not number - use measured data + scale_w=0.1, # weight for "uncertain" values (where samples chane from all 0 to all 1 in one step) + maxDlyErr=200, #ps - trying overlapping dqs branches + quiet=1): + """ + Run DQSI vs PHASE fitting for one data lane (0 or 1) using earlier acquired hard-coded data + @param lane byte lane to process (or non-number - process all byte lanes of the device) + @param bin_size_ps histogram bin size (in ps) + @param data_set_number select one of the hard-coded data sets (sets 0 and 1 use comparing with the data 1 fine step below + set #0 (default) used measurement with previous primary step measurement (will not suffer from + fine range wider than on primary step) + If not number or <0 - use measured data + @param scale_w weight for "uncertain" values (where samples change from all 0 to all 1 in one step) + For sufficient data 0.0 is OK (and seems to work better)- only "analog" samples are considered + @param maxDlyErr - maximal DQS error in ps (currently just to check multiple overlapping branches) + @param quiet reduce output + @return 3-element dictionary of ('early','nominal','late'), each being None or a 160-element list, + each element being either None, or a list of 3 best DQ delay values for the DQS delay (some mey be None too) + """ + if quiet < 1: + print("self.adjustment_state={") + for k,v in self.adjustment_state.items(): + print("\n'%s': %s,"%(k,str(v))) + print("}") + if quiet < 3: + print ("proc_dqso_phase(): scale_w=%f"%(scale_w)) + if isinstance (data_set_number,(int,long)) and (data_set_number>=0) : +# self.load_hardcoded_data() + if quiet < 4: + print("Using hard-coded data set #%d"%data_set_number) + compare_prim_steps= get_test_dq_dqs_data.get_wlev_dqs_steps(data_set_number) + dqso_phase_data= get_test_dq_dqs_data.get_wlev_dqs_delays(data_set_number) + try: +# dqso_dqo_parameters=get_test_dq_dqs_data.get_dqo_dqso_parameters() + dqso_dqo_parameters=self.adjustment_state["dqo_dqso_parameters"] + except: + dqso_dqo_parameters=None + if quiet < 4: + print("DQ vs. DQS output delays calibration parameters are not available yet will use estimated ones") + else: + if quiet < 4: + print("Using measured data set") + try: + compare_prim_steps= self.adjustment_state["wlev_dqs_steps"] + dqso_phase_data= self.adjustment_state["wlev_dqs_delays"] + try: + dqso_dqo_parameters= self.adjustment_state["dqo_dqso_parameters"] + except: + dqso_dqo_parameters=None + if quiet < 4: + print("DQ vs. DQS output delays calibration parameters are not available yet will use estimated ones") + except: + print ("DQS output delay vs. phase measured data (during write levelling) is not available, exiting") + return + timing=self.x393_mcntrl_timing.get_dly_steps() + numPhaseSteps= int(timing['SDCLK_PERIOD']/timing['PHASE_STEP']+0.5) + lma=x393_lma.X393LMA() # use persistent one? + +# print("++++++proc_dqsi_phase(), quiet=",quiet) + + dqs_phase=lma.lma_fit_dqs_phase(lane=lane, # byte lane + bin_size_ps=bin_size_ps, + clk_period=1000.0*self.x393_mcntrl_timing.get_dly_steps()['SDCLK_PERIOD'], # 2500.0, # clk_period, + dqs_dq_parameters=dqso_dqo_parameters, + tSDQS=1000.0*self.x393_mcntrl_timing.get_dly_steps()['DLY_STEP']/NUM_FINE_STEPS, # 78.0/5, # dly_step_ds, + data_set=dqso_phase_data, # data_set, + compare_prim_steps=compare_prim_steps, + scale_w=scale_w, + numPhaseSteps=numPhaseSteps, + maxDlyErr=maxDlyErr, + fallingPhase=True, # fallingPhase + shiftFracPeriod= 0.0, # provided data is centered, not marginal + quiet=quiet) + + #Need to modify names to output ones +# rslt_names=("dqs_optimal_ps","dqs_phase","dqs_phase_multi","dqs_phase_err","dqs_min_max_periods") + gen_keys=dqs_phase.keys() + + for k in gen_keys: + dqs_phase[k.replace('dqs_','dqso_')]=dqs_phase.pop(k) + if quiet < 3: + print ("dqso_phase=",dqs_phase) + self.adjustment_state.update(dqs_phase) + #combine DQSO and DQO data to get DQO vs. phase + if not dqso_dqo_parameters is None: + delays, errors= self._combine_dq_dqs(dqs_data=self.adjustment_state['dqso_phase_multi'], + dq_enl_data=self.adjustment_state["dqo_dqso"], + dq_enl_err = self.adjustment_state["maxErrDqso"], + quiet=quiet) + self.adjustment_state['dqo_phase_multi'] = delays + self.adjustment_state["dqo_phase_err"] = errors + if quiet < 2: + print("self.adjustment_state={") + for k,v in self.adjustment_state.items(): + print("\n'%s': %s,"%(k,str(v))) + print("}") + + else: + if quiet < 3: + print ("DQO vs. DQSO dcata is not yet available, skipping '_combine_dq_dqs()'") + return dqs_phase + def proc_dqo_dqso(self, lane="all", @@ -3768,7 +5011,7 @@ class X393McntrlAdjust(object): rslt = lma.lma_fit_dq_dqs(lane, bin_size, 1000.0*self.x393_mcntrl_timing.get_dly_steps()['SDCLK_PERIOD'], # 2500.0, # clk_period, - 78.0, # dly_step_ds, + 1000.0*self.x393_mcntrl_timing.get_dly_steps()['DLY_STEP'], # 78.0, # dly_step_ds, primary_set, meas_delays, compare_prim_steps, @@ -3777,7 +5020,7 @@ class X393McntrlAdjust(object): if quiet < 4: lma.showENLresults(rslt) - self.adjustment_state["dqi_dqsi_parameters"]=rslt.pop('parameters') + self.adjustment_state["dqo_dqso_parameters"]=rslt.pop('parameters') try: self.adjustment_state["maxErrDqso"]=rslt.pop('maxErrDqs') if quiet < 4: @@ -3789,7 +5032,7 @@ class X393McntrlAdjust(object): print ("maxErrDqs does not exist") if quiet < 4: - print ("dqi_dqsi={") + print ("dqo_dqso={") for k,v in rslt.items(): print ("'%s':%s,"%(k,str(v))) print ("}") @@ -3798,7 +5041,7 @@ class X393McntrlAdjust(object): def proc_addr_odelay(self, commonFine=True, # use same values for fine delay - max_err=0.125, # 1/8 period + maxErrPs=200.0, #ps quiet=2): """ Process delay calibration data for address and bank line, calculate delay scales, shift and rise/fall differences. @@ -3984,83 +5227,94 @@ class X393McntrlAdjust(object): for i in range (NUM_FINE_STEPS): tAF5A[i]-=avg return tAF5A - - def get_optimal_dlys(phase,maxErr): + + def get_optimal_multi(phase,maxErrPs): """ - return list of delays and maximal error - expects average values in the last item(s) - use average to find the branch, all others - in the same branch - + Return a dictionary of two dictionaries, both indexed by integers (positive, 0 or negative + that mean number of full clock cycles. + Elements of the first dictionary are lists of bit delays, of the second - maximal error (in ps) + branches are determined by the average parameters (last set of parameters) """ avg_index=numLines # len(parameters['tA'])-1 num_items=numLines+1 s_avg=parameters['tSA'][avg_index] t_avg= parameters['tA'][avg_index]-phase_step*phase - clk_period/2 - periods=0 avg_max_delay=s_avg*NUM_DLY_STEPS # maximal delay with average line - - while t_avg < 0: + ''' + periods=0 + while t_avg < -maxErrPs: t_avg += clk_period periods += 1 if t_avg > avg_max_delay: t_avg -= clk_period periods -= 1 - if t_avg < -clk_period*maxErr: + if t_avg < -maxErrPs: if quiet < 2: print ("No solution for average signal for phase=",phase) return None - delays=[] - worst_err=0 # - if quiet < 1: - print ("Phase=%d"%(phase)) + ''' + periods=int(round((t_avg+ +maxErrPs)/clk_period - 0.5)) + period_options=[] + while (t_avg - clk_period*periods) < (avg_max_delay + maxErrPs): + period_options.append(periods) + periods-=1 + delays_multi={} + errors_multi={} + if quiet<2: + print ("\n%d: period_options=%s, t_avg=%f"%(phase,str(period_options),t_avg)) -# print("num_items=",num_items) -# print("len(parameters['tA'])=",len(parameters['tA'])) -# print("len(parameters['tSA'])=",len(parameters['tSA'])) -# print("len(parameters['tAF'])=",len(parameters['tAF'])) - - for line in range(num_items): #+1): - tAF5=parameters['tAF'][(NUM_FINE_STEPS-1)*line:(NUM_FINE_STEPS-1)*(line+1)] - tAF5.append(-sum(tAF5)) - best_dly=None - best_err=None - if quiet < 1: - dbg_dly=[] - for dly in range (NUM_DLY_STEPS): - #TODO: verify finedelay polarity - try: - t_dly=parameters['tA'][line]-parameters['tSA'][line]*dly -phase_step*phase - clk_period/2 + tAF5[dly %NUM_FINE_STEPS] + periods*clk_period - except: - print ("line=",line) - print ("parameters['tA']=",parameters['tA']) - print ("parameters['tSA']=",parameters['tSA']) - print ("tAF5=",tAF5) - - raise Exception("That's all") -# t_dly=parameters['tA'][line]-parameters['tSA'][line]*dly -phase_step*phase - clk_period/2 - tAF5[dly %NUM_FINE_STEPS] + periods*clk_period + for periods in period_options: + delays=[] + worst_err=-1 + for line in range(num_items): #+1): + tAF5=parameters['tAF'][(NUM_FINE_STEPS-1)*line:(NUM_FINE_STEPS-1)*(line+1)] + tAF5.append(-sum(tAF5)) + best_dly=None + best_err=None if quiet < 1: - dbg_dly.append(t_dly) - if (best_dly is None) or (abs(t_dly) < abs(best_err)): - best_dly=dly - best_err=t_dly + dbg_dly=[] + for dly in range (NUM_DLY_STEPS): + #TODO: verify finedelay polarity + try: +# t_dly=parameters['tA'][line]-parameters['tSA'][line]*dly -phase_step*phase - clk_period/2 + tAF5[dly %NUM_FINE_STEPS] + periods*clk_period + t_dly=parameters['tA'][line]-parameters['tSA'][line]*dly -phase_step*phase - clk_period/2 + tAF5[dly %NUM_FINE_STEPS] - periods*clk_period + if quiet<1: + print ("%d: period_options=%s, t_avg=%f"%(phase,str(period_options),t_avg)) + except: + print ("line=",line) + print ("parameters['tA']=",parameters['tA']) + print ("parameters['tSA']=",parameters['tSA']) + print ("tAF5=",tAF5) + + raise Exception("That's all") + if quiet < 1: + dbg_dly.append(t_dly) + if (best_dly is None) or (abs(t_dly) < abs(best_err)): + best_dly=dly + best_err=t_dly + if quiet < 2: + print ("phase=%d, periods=%d best_dly=%d, best_err=%f"%(phase, periods, best_dly, best_err),end=" ") + delays.append(best_dly) + if worst_err< abs(best_err): + worst_err = abs(best_err) if quiet < 1: - print ("%f"%(best_err),end=" ") - - delays.append(best_dly) - if worst_err< abs(best_err): - worst_err = abs(best_err) - if quiet < 1: - print () - print (dbg_dly) - if worst_err > maxErr*clk_period: - if quiet < 2: - print ("Worst signal error (%f ps) is too high (>%f ps, %f clk_periods) fpr phase %d"%(worst_err, maxErr*clk_period,maxErr, phase)) - return None - - return {'err':worst_err, - 'dlys':delays} - - pass + print () + print (dbg_dly) + if worst_err > maxErrPs: + if quiet < 2: + print ("Worst signal error (%f ps) is too high (>%f ps, %f clk_periods) for phase %d"%(worst_err, maxErrPs,maxErrPs/clk_period, phase)) + continue + if worst_err < 0: + if quiet < 2: + print ("No signal meets requirements for periods=%d, phase %d"%(periods, phase)) + continue + delays_multi[periods]=delays + errors_multi[periods]=worst_err + if delays_multi: + return {'err':errors_multi, + 'dlys':delays_multi} + else: + return None #main method body: @@ -4104,20 +5358,40 @@ class X393McntrlAdjust(object): delays=[] errors=[] for phase in range(numPhaseSteps): - dly_err=get_optimal_dlys(phase,max_err) +# dly_err=get_optimal_dlys(phase,max_err) + dly_err=get_optimal_multi(phase,maxErrPs) if not dly_err is None: delays.append(dly_err['dlys']) errors.append(dly_err['err']) else: delays.append(None) errors.append(None) + if quiet < 4: + min_max=None + for phase_data in delays: + for k in phase_data.keys(): + try: + min_max[0]=min(min_max[0],k) + min_max[1]=max(min_max[1],k) + except: + min_max=[k,k] + print ("\nmin_max=",min_max) + for phase in range(numPhaseSteps): print("%d"%(phase), end=" ") if not delays[phase] is None: - for d in delays[phase]: - print ("%s"%(str(d)),end=" ") - print ("%s"%(str(errors[phase])),end=" ") + for p in range(min_max[0],min_max[1]+1): + for line in range(numLines): +# for d in delays[phase][p]: + try: + print ("%s"%(str(delays[phase][p][line])),end=" ") + except: + print("?",end=" ") + try: + print ("%s"%(str(errors[phase][p])),end=" ") + except: + print("?",end=" ") print() rslt={'err':errors, 'dlys':delays} @@ -4128,9 +5402,9 @@ class X393McntrlAdjust(object): print("}") if quiet<3: print ("parameters=",parameters) - self.adjustment_state['addr_odelay']= rslt + self.adjustment_state['addr_odelay']= rslt return rslt - + ''' def get_delays_vs_phase(self, filter_dqo=2, filter_dqi=2, @@ -4267,36 +5541,37 @@ class X393McntrlAdjust(object): for phase in range(numPhaseSteps): delays_phase.append({}) if filter_cmda: + # for special case (float filter_cmda) use initial 'cmda_bspe', not 'addr_odelay' if (not addr_odelay is None) and (not isinstance(filter_cmda,float)): #TODO: add zerr to addr_odelay (error as a fraction of clock period if delay is set to 0) #special case to test address setup time - will never execute now if isinstance(filter_cmda,float) and (not addr_odelay['err'][phase] is None) and (addr_odelay['err'][phase] < 0.5-filter_cmda): - delays_phase[phase]['cmda']=0 + delays_phase[phase][CMDA_KEY]=0 else: if (addr_odelay['dlys'][phase] is None) and (not keep_all): delays_phase[phase]=None continue # next phase else: if not addr_odelay['dlys'][phase] is None: - delays_phase[phase]['cmda']=addr_odelay['dlys'][phase] # list, not single value! + delays_phase[phase][CMDA_KEY]=addr_odelay['dlys'][phase] # list, not single value! num_cmda=len(addr_odelay['dlys'][phase]) else: #special case to test address setup time if isinstance(filter_cmda,float) and (not cmda_bspe[phase]['zerr'] is None) and (cmda_bspe[phase]['zerr']< 0.5-filter_cmda): - delays_phase[phase]['cmda']=0 + delays_phase[phase][CMDA_KEY]=0 # set to minimal delay (==0) else: if (cmda_bspe[phase]['ldly'] is None) and (not keep_all): delays_phase[phase]=None continue # next phase else: if not cmda_bspe[phase]['ldly'] is None: - delays_phase[phase]['cmda']=cmda_bspe[phase]['ldly'] + delays_phase[phase][CMDA_KEY]=cmda_bspe[phase]['ldly'] #all(v is None for v in l) if filter_dqsi: dqsi=[dqsi_lane[phase] for dqsi_lane in dqsi_phase] if None in dqsi: if keep_all: if not all(v is None for v in dqsi): - delays_phase[phase]['dqsi']=dqsi + delays_phase[phase][DQSI_KEY]=dqsi else: delays_phase[phase]=None continue # next phase @@ -4304,13 +5579,13 @@ class X393McntrlAdjust(object): delays_phase[phase]=None continue # next phase else: - delays_phase[phase]['dqsi']=dqsi + delays_phase[phase][DQSI_KEY]=dqsi if filter_dqso: dqso=[None if wlev_lane[phase] is None else wlev_lane[phase]['ldly'] for wlev_lane in wlev_dqs_bspe] if None in dqso: if keep_all: if not all(v is None for v in dqso): - delays_phase[phase]['dqso']=dqso + delays_phase[phase][DQSO_KEY]=dqso else: delays_phase[phase]=None continue # next phase @@ -4318,7 +5593,7 @@ class X393McntrlAdjust(object): delays_phase[phase]=None continue # next phase else: - delays_phase[phase]['dqso']=dqso + delays_phase[phase][DQSO_KEY]=dqso if filter_dqi: dqsi=[dqsi_lane[phase] for dqsi_lane in dqsi_phase] if (None in dqsi) and (not keep_all): @@ -4328,6 +5603,7 @@ class X393McntrlAdjust(object): dqi_options={} for k in rslt_names: if (k in DQIvDQSI) and (not DQIvDQSI[k] is None): + #sum (...,[]) makes it a concatenation of lists, not arithmetic sum dqi= sum([[None]*8 if (dqs is None) or (DQIvDQSI[k][dqs] is None) else DQIvDQSI[k][dqs][8*lane:8*(lane+1)] for lane,dqs in enumerate(dqsi)], []) if keep_all: if not all(v is None for v in dqi): @@ -4343,7 +5619,7 @@ class X393McntrlAdjust(object): continue # failed filter, continue to the next branch dqi_options[k]=dqi if dqi_options: - delays_phase[phase]['dqi']=dqi_options + delays_phase[phase][DQI_KEY]=dqi_options elif not keep_all: delays_phase[phase]=None continue # next phase @@ -4371,7 +5647,7 @@ class X393McntrlAdjust(object): continue # failed filter, continue to the next branch dqo_options[k]=dqo if dqo_options: - delays_phase[phase]['dqo']=dqo_options + delays_phase[phase][DQO_KEY]=dqo_options elif not keep_all: delays_phase[phase]=None continue # next phase @@ -4482,42 +5758,42 @@ class X393McntrlAdjust(object): if not phase_data is None: if num_cmda ==0: try: - print ("%d"%(phase_data['cmda']),end=" ") + print ("%d"%(phase_data[CMDA_KEY]),end=" ") except: print ("?",end=" ") else: for line in range (num_cmda): try: - print ("%d"%(phase_data['cmda'][line]),end=" ") + print ("%d"%(phase_data[CMDA_KEY][line]),end=" ") except: print ("?",end=" ") for lane in range(numLanes): try: - print ("%d"%(phase_data['dqsi'][lane]),end=" ") + print ("%d"%(phase_data[DQSI_KEY][lane]),end=" ") except: print ("?",end=" ") for k in enl_list_in: for b in range(numBits): try: - print ("%d"%(phase_data['dqi'][k][b]),end=" ") + print ("%d"%(phase_data[DQI_KEY][k][b]),end=" ") except: print ("?",end=" ") for lane in range(numLanes): try: - print ("%d"%(phase_data['dqso'][lane]),end=" ") + print ("%d"%(phase_data[DQSO_KEY][lane]),end=" ") except: print ("?",end=" ") for k in enl_list_out: for b in range(numBits): try: - print ("%d"%(phase_data['dqo'][k][b]),end=" ") + print ("%d"%(phase_data[DQO_KEY][k][b]),end=" ") except: print ("?",end=" ") if not read_variants is None: for k in enl_list_in: try: - if not None in phase_data['dqi'][k]: + if not None in phase_data[DQI_KEY][k]: print ("%d"%(10*read_variants[k]['sel']),end=" ")# 10* - for graph visibility else: print ("?",end=" ") @@ -4527,8 +5803,8 @@ class X393McntrlAdjust(object): for k in enl_list_out: try: # print ('k=',k,end=" ") -# print ("phase_data['dqo']=",phase_data['dqo']) - if not None in phase_data['dqo'][k]: +# print ("phase_data[DQO_KEY]=",phase_data[DQO_KEY]) + if not None in phase_data[DQO_KEY][k]: print ("%d"%(12*write_variants[k]['sel']),end=" ")# 12* - for graph visibility else: print ("?",end=" ") @@ -4536,8 +5812,8 @@ class X393McntrlAdjust(object): print ("?",end=" ") for k in enl_list_in: try: - if not None in phase_data['dqsi']: - max_err=max(maxErrDqsi[k][dly][lane] for lane,dly in enumerate(phase_data['dqsi'])) + if not None in phase_data[DQSI_KEY]: + max_err=max(maxErrDqsi[k][dly][lane] for lane,dly in enumerate(phase_data[DQSI_KEY])) print("%.1f"%(max_err),end=" ") else: print ("X",end=" ") @@ -4545,8 +5821,8 @@ class X393McntrlAdjust(object): print ("?",end=" ") for k in enl_list_out: try: - if not None in phase_data['dqso']: - max_err=max(maxErrDqso[k][dly][lane] for lane,dly in enumerate(phase_data['dqso'])) + if not None in phase_data[DQSO_KEY]: + max_err=max(maxErrDqso[k][dly][lane] for lane,dly in enumerate(phase_data[DQSO_KEY])) print("%.1f"%(max_err),end=" ") else: print ("x",end=" ") @@ -4558,24 +5834,26 @@ class X393McntrlAdjust(object): if set_table: self.adjustment_state['delays_phase'] = delays_phase return delays_phase + ''' + ''' def show_all_vs_phase(self, keep_all=False, load_hardcoded=False, filter_rw=False, filter_rsel=None, filter_wsel=None): - ''' + """ Show table (to be copied to a spreadsheet) with all delay settings for each DDR3 memory clock phase value @param keep_all - show incomplete data (some of the delays may not have valid values for selected clock phase, false - show only data for valid phases @param load_hardcoded - get hard-coded data (false - use current) - ''' + """ if load_hardcoded: self.load_hardcoded_data() - self.get_delays_vs_phase( + return self.get_delays_vs_phase( filter_dqo=2, filter_dqi=2, filter_dqso=2, @@ -4587,7 +5865,9 @@ class X393McntrlAdjust(object): filter_wsel=filter_wsel, keep_all=keep_all, set_table=False, - quiet=2) + quiet=2) + ''' + def save_mcntrl(self, path=None, quiet=1): diff --git a/py393/x393_mcntrl_timing.py b/py393/x393_mcntrl_timing.py index 2f29bc2..3f6c797 100644 --- a/py393/x393_mcntrl_timing.py +++ b/py393/x393_mcntrl_timing.py @@ -546,11 +546,18 @@ class X393McntrlTiming(object): if dqm_patt is None: dqm_patt=vrlg.DFLT_DQM_PATTERN patt = (dqs_patt & 0xff) | ((dqm_patt & 0xff) << 8) - if quiet <2 : - print("SET DQS+DQM PATTERNS, patt= 0x%08x"%patt) + vrlg.dqs_dqm_patt=patt + if quiet < 2 : + print("axi_set_dqs_dqm_patterns(): SET DQS+DQM PATTERNS, patt= 0x%08x (TODO:reduce quiet threshold)"%patt) # set patterns for DM (always 0) and DQS - always the same (may try different for write lev.) self.x393_axi_tasks.write_contol_register(vrlg.MCONTR_PHY_16BIT_ADDR + vrlg.MCONTR_PHY_16BIT_PATTERNS, patt) # 32'h0055); + def get_dqs_dqm_patterns(self): + #print ('vrlg.dqs_dqm_patt=',vrlg.dqs_dqm_patt) + try: + return (vrlg.dqs_dqm_patt & 0xff,(vrlg.dqs_dqm_patt >> 8) & 0xff) + except: + return None def util_test4(self): # print("vrlg.globals():") # print(vrlg.globals()) -- 2.18.1