|
|
@ -0,0 +1,908 @@ |
|
|
|
|
|
|
|
from dataclasses import dataclass |
|
|
|
|
|
|
|
import re |
|
|
|
|
|
|
|
from typing import List, Optional, Dict, DefaultDict, Tuple |
|
|
|
|
|
|
|
import time |
|
|
|
|
|
|
|
from enum import Enum |
|
|
|
|
|
|
|
import logging |
|
|
|
|
|
|
|
from collections import defaultdict |
|
|
|
|
|
|
|
from parser.topology_parser import TopoMappingParser |
|
|
|
|
|
|
|
from parser.transceiver_config_parser import TransceiverConfigParser |
|
|
|
|
|
|
|
from toolbox.opt_reg_access_tool import OptRegAccessTool |
|
|
|
|
|
|
|
from gpu.biren.exp_util import DevWhiteRiverExp |
|
|
|
|
|
|
|
from parser.ibias_rssi_map_parser import IbiasRssiMapParser |
|
|
|
|
|
|
|
from regs_save_load_tool import LaneRegInfo |
|
|
|
|
|
|
|
from typing import NamedTuple, Optional |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
logger = logging.getLogger(__name__) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# -------------------------------------------------- |
|
|
|
|
|
|
|
# Eye Issue Definition (Corrected Logic) |
|
|
|
|
|
|
|
# -------------------------------------------------- |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class OptReg(Enum): |
|
|
|
|
|
|
|
MGC = '' |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class EyeIssue(Enum): |
|
|
|
|
|
|
|
EYE_NORMAL = 0 |
|
|
|
|
|
|
|
EYE_TOO_SMALL = 1 # 垂直开口太小: sum(|top|, |down|) < 30 |
|
|
|
|
|
|
|
EYE_TOO_LARGE = 2 |
|
|
|
|
|
|
|
EYE_TOO_DOWN = 3 # 眼图偏低: top < 15 |
|
|
|
|
|
|
|
EYE_TOO_UP = 4 # 眼图偏高: |down| < 15 (i.e., down > -15) |
|
|
|
|
|
|
|
EYE_TOO_BAD = 5 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@dataclass |
|
|
|
|
|
|
|
class EyeData: |
|
|
|
|
|
|
|
rt_phys_index: int = -1 |
|
|
|
|
|
|
|
phys_lane_index: int = -1 |
|
|
|
|
|
|
|
rt_index: int = -1 |
|
|
|
|
|
|
|
lane_index: int = -1 |
|
|
|
|
|
|
|
down: float = -1 # mV (usually negative) |
|
|
|
|
|
|
|
top: float = -1 # mV (usually positive) |
|
|
|
|
|
|
|
left: float = -1 # UI |
|
|
|
|
|
|
|
right: float = -1 # UI |
|
|
|
|
|
|
|
issue: EyeIssue = EyeIssue.EYE_NORMAL |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def __str__(self): |
|
|
|
|
|
|
|
return (f"RTMR{self.rt_index} EYE_A{self.lane_index:02d}: " |
|
|
|
|
|
|
|
f"({self.down:.1f}, {self.top:.1f}) mV | " |
|
|
|
|
|
|
|
f"({self.left:.2f}, {self.right:.2f}) UI") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@property |
|
|
|
|
|
|
|
def vertical_amplitude(self) -> float: |
|
|
|
|
|
|
|
return abs(self.down) + abs(self.top) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@property |
|
|
|
|
|
|
|
def horizontal_amplitude(self) -> float: |
|
|
|
|
|
|
|
return abs(self.left) + abs(self.right) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@property |
|
|
|
|
|
|
|
def quality_score(self) -> float: |
|
|
|
|
|
|
|
return self.vertical_amplitude |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def determine_issue(self) -> None: |
|
|
|
|
|
|
|
if self.vertical_amplitude < 65: |
|
|
|
|
|
|
|
self.issue = EyeIssue.EYE_TOO_SMALL |
|
|
|
|
|
|
|
elif self.vertical_amplitude > 220: |
|
|
|
|
|
|
|
self.issue = EyeIssue.EYE_TOO_LARGE |
|
|
|
|
|
|
|
elif self.top < 15: |
|
|
|
|
|
|
|
self.issue = EyeIssue.EYE_TOO_DOWN |
|
|
|
|
|
|
|
elif self.down > -15: # 因为 down 是负值,> -15 表示离 0 太近(太高) |
|
|
|
|
|
|
|
self.issue = EyeIssue.EYE_TOO_UP |
|
|
|
|
|
|
|
else: |
|
|
|
|
|
|
|
self.issue = EyeIssue.EYE_NORMAL |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class TuneViewResult(NamedTuple): |
|
|
|
|
|
|
|
rt_index: int |
|
|
|
|
|
|
|
lane_index: int |
|
|
|
|
|
|
|
remote: LaneRegInfo |
|
|
|
|
|
|
|
local: LaneRegInfo |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# -------------------------------------------------- |
|
|
|
|
|
|
|
# 🔧 EQ Tuning Tool |
|
|
|
|
|
|
|
# -------------------------------------------------- |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class EqTuneTool: |
|
|
|
|
|
|
|
def __init__(self, local_bmc: DevWhiteRiverExp, remote_bmc: DevWhiteRiverExp, |
|
|
|
|
|
|
|
local_reg_tool: OptRegAccessTool, remote_reg_tool: OptRegAccessTool, |
|
|
|
|
|
|
|
ibias_rssi_map: IbiasRssiMapParser, |
|
|
|
|
|
|
|
topo_map: TopoMappingParser, route_name: str): |
|
|
|
|
|
|
|
self.local_bmc = local_bmc |
|
|
|
|
|
|
|
self.remote_bmc = remote_bmc |
|
|
|
|
|
|
|
self.local_reg_tool = local_reg_tool |
|
|
|
|
|
|
|
self.remote_reg_tool = remote_reg_tool |
|
|
|
|
|
|
|
self.ibias_rssi_map = ibias_rssi_map |
|
|
|
|
|
|
|
self.route_name = route_name |
|
|
|
|
|
|
|
self.topo_map = topo_map |
|
|
|
|
|
|
|
self.topo_map.parse() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def eq_auto_tune(self, exp_id: int): |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
cmd = 'ver' |
|
|
|
|
|
|
|
raw_output = self.local_bmc.CmdVendorCommand(exp_id, cmd) |
|
|
|
|
|
|
|
# logging.info(raw_output) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
logger.info(f"Starting auto tune for exp id: {exp_id}") |
|
|
|
|
|
|
|
# retimers = [1, 2, 3, 4] |
|
|
|
|
|
|
|
retimers = [3] |
|
|
|
|
|
|
|
for retimer_index in retimers: |
|
|
|
|
|
|
|
bad_eyes = self.get_issue_eye_diagram(exp_id, retimer_index) |
|
|
|
|
|
|
|
time.sleep(1) |
|
|
|
|
|
|
|
if bad_eyes: |
|
|
|
|
|
|
|
self.process_worst_eyes(exp_id, retimer_index, bad_eyes) |
|
|
|
|
|
|
|
else: |
|
|
|
|
|
|
|
logger.info(f"No eye issues found on RTMR{retimer_index}") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def tune_view(self, exp_id: int, rt_index: int, lane_index: int) -> Optional[TuneViewResult]: |
|
|
|
|
|
|
|
#11,12, 21,22, 31,32, 41,42 |
|
|
|
|
|
|
|
success, rt_index, lane_index = self.verify_rt_index_lane_index(rt_index, lane_index) |
|
|
|
|
|
|
|
if success == False: |
|
|
|
|
|
|
|
return |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
remote_slot = self.topo_map.get_remote_slot_by_retimer(rt_index, lane_index, self.route_name) |
|
|
|
|
|
|
|
local_slot = self.topo_map.get_local_slot_by_retimer(rt_index, lane_index, self.route_name) |
|
|
|
|
|
|
|
logging.info(f'remote_slot: {remote_slot}, local_slot: {local_slot}') |
|
|
|
|
|
|
|
remote_slot_id = remote_slot[0] |
|
|
|
|
|
|
|
remote_lane_id = remote_slot[1] |
|
|
|
|
|
|
|
local_slot_id = local_slot[0] |
|
|
|
|
|
|
|
local_lane_id = local_slot[1] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
logger.info(f"Processing tune view for RTMR{rt_index} lane {lane_index}: " |
|
|
|
|
|
|
|
f"remote_slot=({remote_slot_id},{remote_lane_id}), " |
|
|
|
|
|
|
|
f"local_slot=({local_slot_id},{local_lane_id})") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
raw_opcurrent_value = self.remote_reg_tool.read_opcurrent_reg(exp_id, remote_slot_id, remote_lane_id) |
|
|
|
|
|
|
|
raw_high_freq_value = self.remote_reg_tool.read_high_freq_reg(exp_id, remote_slot_id, remote_lane_id) |
|
|
|
|
|
|
|
raw_low_freq_value = self.remote_reg_tool.read_low_freq_reg(exp_id, remote_slot_id, remote_lane_id) |
|
|
|
|
|
|
|
raw_tia_peak_value = self.local_reg_tool.read_tia_peak_reg(exp_id, local_slot_id, local_lane_id) |
|
|
|
|
|
|
|
raw_mgc_value = self.local_reg_tool.read_mgc_reg(exp_id, local_slot_id, local_lane_id) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ibias_value = self.remote_reg_tool.read_ibias_reg(exp_id, remote_slot_id, remote_lane_id) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ibias_lane = self.remote_reg_tool.get_ibias_by_logic_lane(remote_lane_id) |
|
|
|
|
|
|
|
rssi_lanes = self.ibias_rssi_map.get_rssi_lane(self.route_name, ibias_lane) |
|
|
|
|
|
|
|
if rssi_lanes is None: |
|
|
|
|
|
|
|
logging.error('RSSI lanes is none') |
|
|
|
|
|
|
|
return |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
rssi1_value = self.local_reg_tool.read_rssi_reg(exp_id, local_slot_id, rssi_lanes[0]) |
|
|
|
|
|
|
|
rssi2_value = self.local_reg_tool.read_rssi_reg(exp_id, local_slot_id, rssi_lanes[1]) |
|
|
|
|
|
|
|
# logging.info(f'RSSI values: rssi1={rssi1_value}, rssi2={rssi2_value}') |
|
|
|
|
|
|
|
logging.info(f'') |
|
|
|
|
|
|
|
logging.info(f'{self.remote_reg_tool.host} ---------- ibias: {ibias_value}, rssi1={rssi1_value}, rssi2={rssi2_value}, op:{raw_opcurrent_value}, high_freq:{raw_high_freq_value}, low_freq:{raw_low_freq_value}, mgc:{raw_mgc_value}, tia_peak: {raw_tia_peak_value}') |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
remote_info = LaneRegInfo() |
|
|
|
|
|
|
|
remote_info.logic_lane = remote_lane_id |
|
|
|
|
|
|
|
remote_info.slot_id = remote_slot_id |
|
|
|
|
|
|
|
remote_info.ibias = ibias_value |
|
|
|
|
|
|
|
remote_info.opcurrent = raw_opcurrent_value |
|
|
|
|
|
|
|
remote_info.lowfreq_eq = raw_low_freq_value |
|
|
|
|
|
|
|
remote_info.highfreq_eq = raw_high_freq_value |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
local_info = LaneRegInfo() |
|
|
|
|
|
|
|
local_info.logic_lane = local_lane_id |
|
|
|
|
|
|
|
local_info.slot_id = local_slot_id |
|
|
|
|
|
|
|
local_info.mgc = raw_mgc_value |
|
|
|
|
|
|
|
local_info.tia_peak = raw_tia_peak_value |
|
|
|
|
|
|
|
local_info.rssi1 = rssi1_value |
|
|
|
|
|
|
|
local_info.rssi2 = rssi2_value |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return TuneViewResult( |
|
|
|
|
|
|
|
rt_index=rt_index, |
|
|
|
|
|
|
|
lane_index=lane_index, |
|
|
|
|
|
|
|
remote=remote_info, |
|
|
|
|
|
|
|
local=local_info |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def tune_write(self, exp_id: int, rt_index: int, lane_index: int, reg_name: str, reg_value: int): |
|
|
|
|
|
|
|
success, rt_index, lane_index = self.verify_rt_index_lane_index(rt_index, lane_index) |
|
|
|
|
|
|
|
if success == False: |
|
|
|
|
|
|
|
return |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
remote_slot = self.topo_map.get_remote_slot_by_retimer(rt_index, lane_index, self.route_name) |
|
|
|
|
|
|
|
local_slot = self.topo_map.get_local_slot_by_retimer(rt_index, lane_index, self.route_name) |
|
|
|
|
|
|
|
logging.info(f'remote_slot: {remote_slot}, local_slot: {local_slot}') |
|
|
|
|
|
|
|
remote_slot_id = remote_slot[0] |
|
|
|
|
|
|
|
remote_lane_id = remote_slot[1] |
|
|
|
|
|
|
|
local_slot_id = local_slot[0] |
|
|
|
|
|
|
|
local_lane_id = local_slot[1] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
logger.info(f"Processing tune write for RTMR{rt_index} lane {lane_index}: " |
|
|
|
|
|
|
|
f"remote_slot=({remote_slot_id},{remote_lane_id}), " |
|
|
|
|
|
|
|
f"local_slot=({local_slot_id},{local_lane_id})") |
|
|
|
|
|
|
|
logging.info(f'-----------------------reg_name: {reg_name}, reg_value: {reg_value}') |
|
|
|
|
|
|
|
if reg_name == 'opcurrent': |
|
|
|
|
|
|
|
self.remote_reg_tool.write_opcurrent_reg(exp_id, remote_slot_id, remote_lane_id, reg_value) |
|
|
|
|
|
|
|
elif reg_name == 'highfreq_eq': |
|
|
|
|
|
|
|
self.remote_reg_tool.write_high_freq_reg(exp_id, remote_slot_id, remote_lane_id, reg_value) |
|
|
|
|
|
|
|
elif reg_name == 'lowfreq_eq': |
|
|
|
|
|
|
|
self.remote_reg_tool.write_low_freq_reg(exp_id, remote_slot_id, remote_lane_id, reg_value) |
|
|
|
|
|
|
|
elif reg_name == 'ibias': |
|
|
|
|
|
|
|
self.remote_reg_tool.write_ibias_reg(exp_id, remote_slot_id, remote_lane_id, reg_value) |
|
|
|
|
|
|
|
elif reg_name == 'tia_peak': |
|
|
|
|
|
|
|
self.local_reg_tool.write_tia_peak_reg(exp_id, local_slot_id, local_lane_id, reg_value) |
|
|
|
|
|
|
|
elif reg_name == 'mgc': |
|
|
|
|
|
|
|
self.local_reg_tool.write_mgc_reg(exp_id, local_slot_id, local_lane_id, reg_value) |
|
|
|
|
|
|
|
self.local_reg_tool.write_confirm_reg(exp_id, local_slot_id) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
self.tune_view(exp_id, rt_index, lane_index) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def eye_monitor(self, host:str, exp_id: int, route_name: str): |
|
|
|
|
|
|
|
retimers = [1, 2, 3, 4] |
|
|
|
|
|
|
|
all_bad_eyes: List['EyeData'] = [] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
logging.info(f"🔍 Starting eye diagram check for EXP {exp_id}") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for retimer_index in retimers: |
|
|
|
|
|
|
|
try: |
|
|
|
|
|
|
|
# 假设 get_issue_eye_diagram 返回 List[EyeData] |
|
|
|
|
|
|
|
bad_eyes: List[EyeData] = self.get_issue_eye_diagram(exp_id, retimer_index, 3) |
|
|
|
|
|
|
|
if bad_eyes: |
|
|
|
|
|
|
|
logging.warning(f"⚠️ Found {len(bad_eyes)} bad eye(s) on Retimer (logical) {retimer_index}") |
|
|
|
|
|
|
|
all_bad_eyes.extend(bad_eyes) |
|
|
|
|
|
|
|
except Exception as e: |
|
|
|
|
|
|
|
logging.error(f"❌ Failed to check Retimer {retimer_index}: {e}") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# === 汇总打印所有异常眼图(包含全部排查所需字段)=== |
|
|
|
|
|
|
|
if all_bad_eyes: |
|
|
|
|
|
|
|
logging.error("🚨==========================================================================") |
|
|
|
|
|
|
|
logging.error(" BAD EYE DIAGRAMS DETECTED ") |
|
|
|
|
|
|
|
logging.error(" Please replace or debug the modules below ") |
|
|
|
|
|
|
|
logging.error("🚨==========================================================================") |
|
|
|
|
|
|
|
logging.error(f"{'Host':^16} {'Slot':^6} {'Lane':^8} {'RT_ID':^6} {'RT_Lane':^9} " |
|
|
|
|
|
|
|
f"{'Down(mV)':^8} {'Top(mV)':^9} {'Left(UI)':^8} {'Right(UI)':^9} {'Issue':^18}") |
|
|
|
|
|
|
|
logging.error("-" * 100) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for idx, eye in enumerate(all_bad_eyes, 1): |
|
|
|
|
|
|
|
remote_slot = self.topo_map.get_remote_slot_by_retimer(eye.rt_index, eye.lane_index, route_name) |
|
|
|
|
|
|
|
local_slot = self.topo_map.get_local_slot_by_retimer(eye.rt_index, eye.lane_index, route_name) |
|
|
|
|
|
|
|
local_slot_id = local_slot[0] |
|
|
|
|
|
|
|
local_lane_id = local_slot[1] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
logging.error( |
|
|
|
|
|
|
|
f"{host:^16} " |
|
|
|
|
|
|
|
f"{local_slot_id:^6} " |
|
|
|
|
|
|
|
f"{local_lane_id:^8} " |
|
|
|
|
|
|
|
f"{eye.rt_phys_index:^6} " |
|
|
|
|
|
|
|
f"{eye.phys_lane_index:^9} " |
|
|
|
|
|
|
|
f"{eye.down:8.2f} " |
|
|
|
|
|
|
|
f"{eye.top:7.2f} " |
|
|
|
|
|
|
|
f"{eye.left:7.3f} " |
|
|
|
|
|
|
|
f"{eye.right:8.3f} " |
|
|
|
|
|
|
|
f"{EyeIssue(eye.issue).name:18}" |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
logging.error("💡 Tip: Check cabling, retimer settings, or optical module health.") |
|
|
|
|
|
|
|
else: |
|
|
|
|
|
|
|
logging.info("✅ All eye diagrams are within acceptable range. No issues detected.") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def verify_rt_index_lane_index(self, rt_index: int, lane_index: int) -> Tuple[bool, int, int]: |
|
|
|
|
|
|
|
if rt_index in [1, 2, 3, 4]: |
|
|
|
|
|
|
|
logging.info(f'use retimer phys index and lane, rt_index: {rt_index}, rt_lane: {lane_index}') |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if 0 <= lane_index <= 7: |
|
|
|
|
|
|
|
new_rt_index = rt_index * 10 + 1 # 1->11, 2->21, etc. |
|
|
|
|
|
|
|
return (True, new_rt_index, lane_index) |
|
|
|
|
|
|
|
elif 8 <= lane_index <= 15: |
|
|
|
|
|
|
|
new_rt_index = rt_index * 10 + 2 # 1->12, 2->22, etc. |
|
|
|
|
|
|
|
new_lane_index = lane_index - 8 |
|
|
|
|
|
|
|
return (True, new_rt_index, new_lane_index) |
|
|
|
|
|
|
|
else: |
|
|
|
|
|
|
|
logging.error('Invalid lane_index: must be in [0, 15]') |
|
|
|
|
|
|
|
return (False, 0, 0) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
elif rt_index in [11, 12, 21, 22, 31, 32, 41, 42]: |
|
|
|
|
|
|
|
logging.info(f'use retimer logic index and lane, rt_index: {rt_index}, rt_lane: {lane_index}') |
|
|
|
|
|
|
|
if lane_index > 7: |
|
|
|
|
|
|
|
logging.error('For logic rt_index, lane_index must be in [0, 7]') |
|
|
|
|
|
|
|
return (False, 0, 0) |
|
|
|
|
|
|
|
return (True, rt_index, lane_index) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
else: |
|
|
|
|
|
|
|
logging.error(f'Invalid rt_index: {rt_index}') |
|
|
|
|
|
|
|
return (False, 0, 0) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def process_worst_eyes_new(self, exp_id: int, retimer_index: int, bad_eyes: List[EyeData]) -> None: |
|
|
|
|
|
|
|
logger.warning(f"Detected eye issues on RTMR{retimer_index}:") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for eye in bad_eyes: |
|
|
|
|
|
|
|
logger.warning( |
|
|
|
|
|
|
|
f"RTMR {eye.rt_index} Lane {eye.lane_index:02d}: {eye.issue.name} " |
|
|
|
|
|
|
|
f"(Vertical: {eye.vertical_amplitude:.1f}mV, Top={eye.top:.1f}, Down={eye.down:.1f})" |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for eye in bad_eyes: |
|
|
|
|
|
|
|
logger.warning( |
|
|
|
|
|
|
|
f"Starting Process RTMR {eye.rt_index} Lane {eye.lane_index:02d}: {eye.issue.name} " |
|
|
|
|
|
|
|
f"(Vertical: {eye.vertical_amplitude:.1f}mV, Top={eye.top:.1f}, Down={eye.down:.1f})" |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
tmp_eye = eye |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
result = self.tune_view(exp_id, eye.rt_index, eye.lane_index) |
|
|
|
|
|
|
|
remote_reg_info = result.remote |
|
|
|
|
|
|
|
local_reg_info = result.local |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if tmp_eye.issue == EyeIssue.EYE_TOO_SMALL: |
|
|
|
|
|
|
|
if remote_reg_info.lowfreq_eq <= 150: |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
max_retry_cout = 2 |
|
|
|
|
|
|
|
try_count = 0 |
|
|
|
|
|
|
|
while tmp_eye.issue != EyeIssue.EYE_NORMAL and try_count < max_retry_cout: |
|
|
|
|
|
|
|
logging.info(f'------try count: {try_count}') |
|
|
|
|
|
|
|
if tmp_eye.issue == EyeIssue.EYE_TOO_SMALL: |
|
|
|
|
|
|
|
self.process_small_eye(exp_id, retimer_index, eye) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if tmp_eye.issue == EyeIssue.EYE_TOO_DOWN: |
|
|
|
|
|
|
|
self.process_down_eye(exp_id, retimer_index, eye) |
|
|
|
|
|
|
|
elif tmp_eye.issue == EyeIssue.EYE_TOO_UP: |
|
|
|
|
|
|
|
self.process_up_eye(exp_id, retimer_index, eye) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# if tmp_eye.issue == EyeIssue.EYE_TOO_LARGE: |
|
|
|
|
|
|
|
# logging.info(f"Eye issue: {eye.issue.name}") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
try_count +=1 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
break |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def process_worst_eyes(self, exp_id: int, retimer_index: int, bad_eyes: List[EyeData]) -> None: |
|
|
|
|
|
|
|
logger.warning(f"Detected eye issues on RTMR{retimer_index}:") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for eye in bad_eyes: |
|
|
|
|
|
|
|
logger.warning( |
|
|
|
|
|
|
|
f"RTMR {eye.rt_index} Lane {eye.lane_index:02d}: {eye.issue.name} " |
|
|
|
|
|
|
|
f"(Vertical: {eye.vertical_amplitude:.1f}mV, Top={eye.top:.1f}, Down={eye.down:.1f})" |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for eye in bad_eyes: |
|
|
|
|
|
|
|
logger.warning( |
|
|
|
|
|
|
|
f"Starting Process RTMR {eye.rt_index} Lane {eye.lane_index:02d}: {eye.issue.name} " |
|
|
|
|
|
|
|
f"(Vertical: {eye.vertical_amplitude:.1f}mV, Top={eye.top:.1f}, Down={eye.down:.1f})" |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
tmp_eye = eye |
|
|
|
|
|
|
|
max_retry_cout = 2 |
|
|
|
|
|
|
|
try_count = 0 |
|
|
|
|
|
|
|
while tmp_eye.issue != EyeIssue.EYE_NORMAL and try_count < max_retry_cout: |
|
|
|
|
|
|
|
logging.info(f'------try count: {try_count}') |
|
|
|
|
|
|
|
if tmp_eye.issue == EyeIssue.EYE_TOO_SMALL: |
|
|
|
|
|
|
|
self.process_small_eye(exp_id, retimer_index, eye) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if tmp_eye.issue == EyeIssue.EYE_TOO_DOWN: |
|
|
|
|
|
|
|
self.process_down_eye(exp_id, retimer_index, eye) |
|
|
|
|
|
|
|
elif tmp_eye.issue == EyeIssue.EYE_TOO_UP: |
|
|
|
|
|
|
|
self.process_up_eye(exp_id, retimer_index, eye) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# if tmp_eye.issue == EyeIssue.EYE_TOO_LARGE: |
|
|
|
|
|
|
|
# logging.info(f"Eye issue: {eye.issue.name}") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
try_count +=1 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
break |
|
|
|
|
|
|
|
# # if tmp_eye.issue == EyeIssue.EYE_TOO_LARGE: |
|
|
|
|
|
|
|
# # 如果rssi很大,那适当减少,减少ibias |
|
|
|
|
|
|
|
# # slot = self.topo_map.get_remote_slot_by_retimer(eye.rt_index, eye.lane_index) |
|
|
|
|
|
|
|
# # if slot is None: |
|
|
|
|
|
|
|
# # break |
|
|
|
|
|
|
|
# # slot_id = slot[0] |
|
|
|
|
|
|
|
# # lane_id = slot[1] |
|
|
|
|
|
|
|
# # ibias_value = self.remote_reg_tool. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def process_small_eye(self, exp_id: int, retimer_index: int, eye: EyeData): |
|
|
|
|
|
|
|
logger.info(f"Starting small eye issue processing for RTMR{retimer_index} lane {eye.lane_index}, adjusting ibias") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 获取slot信息 |
|
|
|
|
|
|
|
logging.info(f'--------- rt_index: {eye.rt_index}, lane_index: {eye.lane_index}, route_name: {self.route_name}') |
|
|
|
|
|
|
|
remote_slot = self.topo_map.get_remote_slot_by_retimer(eye.rt_index, eye.lane_index, self.route_name) |
|
|
|
|
|
|
|
local_slot = self.topo_map.get_local_slot_by_retimer(eye.rt_index, eye.lane_index, self.route_name) |
|
|
|
|
|
|
|
if remote_slot is None or local_slot is None: |
|
|
|
|
|
|
|
logger.error(f"Invalid slot for RTMR{retimer_index} lane {eye.lane_index}") |
|
|
|
|
|
|
|
return eye |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
remote_slot_id = remote_slot[0] |
|
|
|
|
|
|
|
remote_lane_id = remote_slot[1] |
|
|
|
|
|
|
|
local_slot_id = local_slot[0] |
|
|
|
|
|
|
|
local_lane_id = local_slot[1] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
logger.info(f"Processing small eye for RTMR{eye.rt_index} lane {eye.lane_index}: " |
|
|
|
|
|
|
|
f"remote_slot=({remote_slot_id},{remote_lane_id}), " |
|
|
|
|
|
|
|
f"local_slot=({local_slot_id},{local_lane_id})") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 调节ibias |
|
|
|
|
|
|
|
logger.info(f"Adjusting ibias for RTMR{eye.rt_index} lane {eye.lane_index}") |
|
|
|
|
|
|
|
eye = self.adjust_ibias_for_small_eye(exp_id, eye, remote_slot_id, remote_lane_id, local_slot_id, local_lane_id) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 如果依然很小,调节opcurrent |
|
|
|
|
|
|
|
if eye.issue == EyeIssue.EYE_TOO_SMALL: |
|
|
|
|
|
|
|
logger.info(f"Eye still too small for RTMR{retimer_index} lane {eye.lane_index}, adjusting opcurrent") |
|
|
|
|
|
|
|
eye = self.adjust_opcurrent_for_small_down_eye(exp_id, eye, remote_slot_id, remote_lane_id) |
|
|
|
|
|
|
|
# eye = self.adjust_opcurrent_for_up_eye(exp_id, eye, remote_slot_id, remote_lane_id) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 如果依然很小,调节mgc |
|
|
|
|
|
|
|
if eye.issue == EyeIssue.EYE_TOO_SMALL: |
|
|
|
|
|
|
|
logger.info(f"Eye still too small for RTMR{retimer_index} lane {eye.lane_index}, adjusting mgc") |
|
|
|
|
|
|
|
eye = self.adjust_mgc_for_small_eye(exp_id, eye, local_slot_id, local_lane_id) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
logger.info(f"Completed small eye processing for RTMR{retimer_index} lane {eye.lane_index}, " |
|
|
|
|
|
|
|
f"final issue: {eye.issue.name}") |
|
|
|
|
|
|
|
return eye |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def process_down_eye(self, exp_id: int, retimer_index: int, eye: EyeData): |
|
|
|
|
|
|
|
logging.info(f"Starting down eye issue processing for RTMR{retimer_index} lane {eye.lane_index}") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 获取slot信息 |
|
|
|
|
|
|
|
remote_slot = self.topo_map.get_remote_slot_by_retimer(eye.rt_index, eye.lane_index, self.route_name) |
|
|
|
|
|
|
|
local_slot = self.topo_map.get_local_slot_by_retimer(eye.rt_index, eye.lane_index, self.route_name) |
|
|
|
|
|
|
|
if remote_slot is None or local_slot is None: |
|
|
|
|
|
|
|
logger.error(f"Invalid slot for RTMR{retimer_index} lane {eye.lane_index}") |
|
|
|
|
|
|
|
return eye |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
remote_slot_id = remote_slot[0] |
|
|
|
|
|
|
|
remote_lane_id = remote_slot[1] |
|
|
|
|
|
|
|
local_slot_id = local_slot[0] |
|
|
|
|
|
|
|
local_lane_id = local_slot[1] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
logger.info(f"Processing down eye for RTMR{eye.rt_index} lane {eye.lane_index}: " |
|
|
|
|
|
|
|
f"remote_slot=({remote_slot_id},{remote_lane_id}), " |
|
|
|
|
|
|
|
f"local_slot=({local_slot_id},{local_lane_id})") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 先调节tia_peak(值调小) |
|
|
|
|
|
|
|
logger.info(f"Adjusting tia_peak for RTMR{eye.rt_index} lane {eye.lane_index}") |
|
|
|
|
|
|
|
eye = self.adjust_tia_peak_for_down_eye(exp_id, eye, local_slot_id, local_lane_id) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 如果依然偏下,调节high_freq(值调小) |
|
|
|
|
|
|
|
if eye.issue == EyeIssue.EYE_TOO_DOWN: |
|
|
|
|
|
|
|
logger.info(f"Eye still too down for RTMR{retimer_index} lane {eye.lane_index}, adjusting high_freq") |
|
|
|
|
|
|
|
eye = self.adjust_high_freq_for_down_eye(exp_id, eye, remote_slot_id, remote_lane_id) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 如果依然偏下,调节opcurrent |
|
|
|
|
|
|
|
if eye.issue == EyeIssue.EYE_TOO_DOWN: |
|
|
|
|
|
|
|
logger.info(f"Eye still too down for RTMR{retimer_index} lane {eye.lane_index}, adjusting opcurrent") |
|
|
|
|
|
|
|
eye = self.adjust_opcurrent_for_small_down_eye(exp_id, eye, remote_slot_id, remote_lane_id) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
logger.info(f"Completed down eye processing for RTMR{retimer_index} lane {eye.lane_index}, " |
|
|
|
|
|
|
|
f"final issue: {eye.issue.name}") |
|
|
|
|
|
|
|
return eye |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def process_up_eye(self, exp_id: int, retimer_index: int, eye: EyeData): |
|
|
|
|
|
|
|
logging.info(f"Starting up eye issue processing for RTMR{retimer_index} lane {eye.lane_index}") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 获取slot信息 |
|
|
|
|
|
|
|
remote_slot = self.topo_map.get_remote_slot_by_retimer(eye.rt_index, eye.lane_index, self.route_name) |
|
|
|
|
|
|
|
local_slot = self.topo_map.get_local_slot_by_retimer(eye.rt_index, eye.lane_index, self.route_name) |
|
|
|
|
|
|
|
if remote_slot is None or local_slot is None: |
|
|
|
|
|
|
|
logger.error(f"Invalid slot for RTMR{retimer_index} lane {eye.lane_index}") |
|
|
|
|
|
|
|
return eye |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
remote_slot_id = remote_slot[0] |
|
|
|
|
|
|
|
remote_lane_id = remote_slot[1] |
|
|
|
|
|
|
|
local_slot_id = local_slot[0] |
|
|
|
|
|
|
|
local_lane_id = local_slot[1] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
logger.info(f"Processing up eye for RTMR{eye.rt_index} lane {eye.lane_index}: " |
|
|
|
|
|
|
|
f"remote_slot=({remote_slot_id},{remote_lane_id}), " |
|
|
|
|
|
|
|
f"local_slot=({local_slot_id},{local_lane_id})") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 先调节tia_peak(值调大) |
|
|
|
|
|
|
|
logger.info(f"Adjusting tia_peak for RTMR{eye.rt_index} lane {eye.lane_index}") |
|
|
|
|
|
|
|
eye = self.adjust_tia_peak_for_up_eye(exp_id, eye, local_slot_id, local_lane_id) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 如果依然偏高,调节high_freq(值调大) |
|
|
|
|
|
|
|
if eye.issue == EyeIssue.EYE_TOO_UP: |
|
|
|
|
|
|
|
logger.info(f"Eye still too up for RTMR{retimer_index} lane {eye.lane_index}, adjusting high_freq") |
|
|
|
|
|
|
|
eye = self.adjust_high_freq_for_up_eye(exp_id, eye, remote_slot_id, remote_lane_id) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 如果依然偏高,调节opcurrent(值调小) |
|
|
|
|
|
|
|
if eye.issue == EyeIssue.EYE_TOO_UP: |
|
|
|
|
|
|
|
logger.info(f"Eye still too up for RTMR{retimer_index} lane {eye.lane_index}, adjusting opcurrent") |
|
|
|
|
|
|
|
eye = self.adjust_opcurrent_for_up_eye(exp_id, eye, remote_slot_id, remote_lane_id) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
logger.info(f"Completed up eye processing for RTMR{retimer_index} lane {eye.lane_index}, " |
|
|
|
|
|
|
|
f"final issue: {eye.issue.name}") |
|
|
|
|
|
|
|
return eye |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def adjust_ibias_for_small_eye(self, exp_id: int, eye: EyeData, remote_slot_id: int, remote_lane_id: int, |
|
|
|
|
|
|
|
local_slot_id: int, local_lane_id: int) -> EyeData: |
|
|
|
|
|
|
|
ibias_range = [2000, 3200] |
|
|
|
|
|
|
|
rssi_range = [5000, 10000] |
|
|
|
|
|
|
|
ibias_value = self.remote_reg_tool.read_ibias_reg(exp_id, remote_slot_id, remote_lane_id) |
|
|
|
|
|
|
|
logging.info(f'Initial ibias_value: {ibias_value}') |
|
|
|
|
|
|
|
# if ibias_value == 0: |
|
|
|
|
|
|
|
# logging.warning(f'read ibias reg again') |
|
|
|
|
|
|
|
# ibias_value = self.remote_reg_tool.read_ibias_reg(exp_id, remote_slot_id, remote_lane_id) |
|
|
|
|
|
|
|
# logging.info(f'Initial ibias_value: {ibias_value}') |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
while ibias_value < ibias_range[1]: |
|
|
|
|
|
|
|
# 根据当前值确定步长 |
|
|
|
|
|
|
|
step = 300 if ibias_value < 2500 else 150 |
|
|
|
|
|
|
|
ibias_value += step |
|
|
|
|
|
|
|
self.remote_reg_tool.write_ibias_reg(exp_id, remote_slot_id, remote_lane_id, ibias_value) |
|
|
|
|
|
|
|
logging.info(f'Adjusted ibias to {ibias_value} with step {step}') |
|
|
|
|
|
|
|
time.sleep(5) |
|
|
|
|
|
|
|
ibias_lane = self.remote_reg_tool.get_ibias_by_logic_lane(remote_lane_id) |
|
|
|
|
|
|
|
rssi_lanes = self.ibias_rssi_map.get_rssi_lane(self.route_name, ibias_lane) |
|
|
|
|
|
|
|
if rssi_lanes is None: |
|
|
|
|
|
|
|
logging.error('RSSI lanes is none') |
|
|
|
|
|
|
|
break |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
rssi1_value = self.local_reg_tool.read_rssi_reg(exp_id, local_slot_id, rssi_lanes[0]) |
|
|
|
|
|
|
|
rssi2_value = self.local_reg_tool.read_rssi_reg(exp_id, local_slot_id, rssi_lanes[1]) |
|
|
|
|
|
|
|
logging.info(f'RSSI values: rssi1={rssi1_value}, rssi2={rssi2_value}') |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
is_margin = False |
|
|
|
|
|
|
|
if rssi1_value > rssi_range[1] or rssi2_value > rssi_range[1]: |
|
|
|
|
|
|
|
# 回退一步 |
|
|
|
|
|
|
|
self.remote_reg_tool.write_ibias_reg(exp_id, remote_slot_id, remote_lane_id, ibias_value - step) |
|
|
|
|
|
|
|
logging.info(f'RSSI margin exceeded, rollback ibias to {ibias_value - step}') |
|
|
|
|
|
|
|
is_margin = True |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
eye = self.get_eye_diagram_per_lane(exp_id, eye.rt_phys_index, eye.phys_lane_index) |
|
|
|
|
|
|
|
logging.info(f'After ibias adjustment, eye issue: {eye.issue.name}') |
|
|
|
|
|
|
|
if eye.issue != EyeIssue.EYE_TOO_SMALL or is_margin: |
|
|
|
|
|
|
|
break |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
logging.info(f'Final ibias adjustment result: ibias={ibias_value}, eye issue={eye.issue.name}') |
|
|
|
|
|
|
|
return eye |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def adjust_opcurrent_for_small_down_eye(self, exp_id: int, eye: EyeData, remote_slot_id: int, remote_lane_id: int) -> EyeData: |
|
|
|
|
|
|
|
raw_eye_issue = eye.issue |
|
|
|
|
|
|
|
raw_opcurrent_value = self.remote_reg_tool.read_opcurrent_reg(exp_id, remote_slot_id, remote_lane_id) |
|
|
|
|
|
|
|
logging.info(f'Initial opcurrent_value: {raw_opcurrent_value}') |
|
|
|
|
|
|
|
op_range = [100, 190] |
|
|
|
|
|
|
|
opcurrent_value = raw_opcurrent_value |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
while opcurrent_value < op_range[1]: |
|
|
|
|
|
|
|
step = 10 |
|
|
|
|
|
|
|
opcurrent_value += step |
|
|
|
|
|
|
|
if opcurrent_value > op_range[1]: |
|
|
|
|
|
|
|
opcurrent_value = op_range[1] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
self.remote_reg_tool.write_opcurrent_reg(exp_id, remote_slot_id, remote_lane_id, opcurrent_value) |
|
|
|
|
|
|
|
logging.info(f'Adjusted opcurrent to {opcurrent_value}') |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
time.sleep(5) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
eye = self.get_eye_diagram_per_lane(exp_id, eye.rt_phys_index, eye.phys_lane_index) |
|
|
|
|
|
|
|
logging.info(f'After opcurrent adjustment, eye issue: {eye.issue.name}') |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if eye.issue != raw_eye_issue or opcurrent_value == op_range[1]: |
|
|
|
|
|
|
|
break |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 如果没有改善,恢复原始值 |
|
|
|
|
|
|
|
# if eye.issue == raw_eye_issue: |
|
|
|
|
|
|
|
# self.remote_reg_tool.write_opcurrent_reg(exp_id, remote_slot_id, remote_lane_id, raw_opcurrent_value) |
|
|
|
|
|
|
|
# logging.info(f'No improvement, rollback opcurrent to {raw_opcurrent_value}') |
|
|
|
|
|
|
|
# else: |
|
|
|
|
|
|
|
# logging.info(f'opcurrent adjustment successful, final value: {opcurrent_value}') |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return eye |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def adjust_mgc_for_small_eye(self, exp_id: int, eye: EyeData, local_slot_id: int, local_lane_id: int) -> EyeData: |
|
|
|
|
|
|
|
raw_mgc_value = self.local_reg_tool.read_mgc_reg(exp_id, local_slot_id, local_lane_id) |
|
|
|
|
|
|
|
logging.info(f'Initial mgc_value: {raw_mgc_value}') |
|
|
|
|
|
|
|
mgc_range = [raw_mgc_value, raw_mgc_value + 10] |
|
|
|
|
|
|
|
mgc_value = raw_mgc_value |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
while mgc_value < mgc_range[1]: |
|
|
|
|
|
|
|
step = 2 |
|
|
|
|
|
|
|
mgc_value += step |
|
|
|
|
|
|
|
self.local_reg_tool.write_mgc_reg(exp_id, local_slot_id, local_lane_id, mgc_value) |
|
|
|
|
|
|
|
logging.info(f'Adjusted mgc to {mgc_value}') |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
time.sleep(5) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
eye = self.get_eye_diagram_per_lane(exp_id, eye.rt_phys_index, eye.phys_lane_index) |
|
|
|
|
|
|
|
logging.info(f'After mgc adjustment, eye issue: {eye.issue.name}') |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if eye.issue != EyeIssue.EYE_TOO_SMALL: |
|
|
|
|
|
|
|
logging.info(f'mgc adjustment successful, final value: {mgc_value}') |
|
|
|
|
|
|
|
return eye |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 如果没有改善,恢复原始值 |
|
|
|
|
|
|
|
# self.local_reg_tool.write_mgc_reg(exp_id, local_slot_id, local_lane_id, raw_mgc_value) |
|
|
|
|
|
|
|
# logging.info(f'No improvement, rollback mgc to {raw_mgc_value}') |
|
|
|
|
|
|
|
return eye |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def adjust_tia_peak_for_down_eye(self, exp_id: int, eye: EyeData, local_slot_id: int, local_lane_id: int) -> EyeData: |
|
|
|
|
|
|
|
raw_tia_peak_value = self.local_reg_tool.read_tia_peak_reg(exp_id, local_slot_id, local_lane_id) |
|
|
|
|
|
|
|
logging.info(f'Initial tia_peak_value: {raw_tia_peak_value}') |
|
|
|
|
|
|
|
tia_peak_range = [0, 200] |
|
|
|
|
|
|
|
tia_peak_value = raw_tia_peak_value |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
while tia_peak_value > tia_peak_range[0]: |
|
|
|
|
|
|
|
step = 20 |
|
|
|
|
|
|
|
tia_peak_value -= step |
|
|
|
|
|
|
|
if tia_peak_value < tia_peak_range[0]: |
|
|
|
|
|
|
|
tia_peak_value = tia_peak_range[0] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
self.local_reg_tool.write_tia_peak_reg(exp_id, local_slot_id, local_lane_id, tia_peak_value) |
|
|
|
|
|
|
|
logging.info(f'Adjusted tia_peak to {tia_peak_value}') |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
eye = self.get_eye_diagram_per_lane(exp_id, eye.rt_phys_index, eye.phys_lane_index) |
|
|
|
|
|
|
|
logging.info(f'After tia_peak adjustment, eye issue: {eye.issue.name}') |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if eye.issue != EyeIssue.EYE_TOO_DOWN or tia_peak_value == tia_peak_range[0]: |
|
|
|
|
|
|
|
break |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
logging.info(f'Final tia_peak adjustment result: tia_peak={tia_peak_value}, eye issue={eye.issue.name}') |
|
|
|
|
|
|
|
return eye |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def adjust_high_freq_for_down_eye(self, exp_id: int, eye: EyeData, remote_slot_id: int, remote_lane_id: int) -> EyeData: |
|
|
|
|
|
|
|
raw_high_freq_value = self.remote_reg_tool.read_high_freq_reg(exp_id, remote_slot_id, remote_lane_id) |
|
|
|
|
|
|
|
logging.info(f'Initial high_freq_value: {raw_high_freq_value}') |
|
|
|
|
|
|
|
high_freq_range = [0, 150] |
|
|
|
|
|
|
|
high_freq_value = raw_high_freq_value |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
while high_freq_value > high_freq_range[0]: |
|
|
|
|
|
|
|
step = 20 |
|
|
|
|
|
|
|
high_freq_value -= step |
|
|
|
|
|
|
|
if high_freq_value < high_freq_range[0]: |
|
|
|
|
|
|
|
high_freq_value = high_freq_range[0] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
self.remote_reg_tool.write_high_freq_reg(exp_id, remote_slot_id, remote_lane_id, high_freq_value) |
|
|
|
|
|
|
|
logging.info(f'Adjusted high_freq to {high_freq_value}') |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
eye = self.get_eye_diagram_per_lane(exp_id, eye.rt_phys_index, eye.phys_lane_index) |
|
|
|
|
|
|
|
logging.info(f'After high_freq adjustment, eye issue: {eye.issue.name}') |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if eye.issue != EyeIssue.EYE_TOO_DOWN or high_freq_value == high_freq_range[0]: |
|
|
|
|
|
|
|
break |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
logging.info(f'Final high_freq adjustment result: high_freq={high_freq_value}, eye issue={eye.issue.name}') |
|
|
|
|
|
|
|
return eye |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def adjust_tia_peak_for_up_eye(self, exp_id: int, eye: EyeData, local_slot_id: int, local_lane_id: int) -> EyeData: |
|
|
|
|
|
|
|
raw_tia_peak_value = self.local_reg_tool.read_tia_peak_reg(exp_id, local_slot_id, local_lane_id) |
|
|
|
|
|
|
|
logging.info(f'Initial tia_peak_value: {raw_tia_peak_value}') |
|
|
|
|
|
|
|
tia_peak_range = [0, 200] |
|
|
|
|
|
|
|
max_value = tia_peak_range[1] |
|
|
|
|
|
|
|
tia_peak_value = raw_tia_peak_value |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
while tia_peak_value < max_value: |
|
|
|
|
|
|
|
step = 20 |
|
|
|
|
|
|
|
tia_peak_value += step |
|
|
|
|
|
|
|
if tia_peak_value > max_value: |
|
|
|
|
|
|
|
tia_peak_value = max_value |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
self.local_reg_tool.write_tia_peak_reg(exp_id, local_slot_id, local_lane_id, tia_peak_value) |
|
|
|
|
|
|
|
logging.info(f'Adjusted tia_peak to {tia_peak_value}') |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
eye = self.get_eye_diagram_per_lane(exp_id, eye.rt_phys_index, eye.phys_lane_index) |
|
|
|
|
|
|
|
logging.info(f'After tia_peak adjustment, eye issue: {eye.issue.name}') |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if eye.issue != EyeIssue.EYE_TOO_UP or tia_peak_value == max_value: |
|
|
|
|
|
|
|
break |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
logging.info(f'Final tia_peak adjustment result: tia_peak={tia_peak_value}, eye issue={eye.issue.name}') |
|
|
|
|
|
|
|
return eye |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def adjust_high_freq_for_up_eye(self, exp_id: int, eye: EyeData, remote_slot_id: int, remote_lane_id: int) -> EyeData: |
|
|
|
|
|
|
|
raw_high_freq_value = self.remote_reg_tool.read_high_freq_reg(exp_id, remote_slot_id, remote_lane_id) |
|
|
|
|
|
|
|
logging.info(f'Initial high_freq_value: {raw_high_freq_value}') |
|
|
|
|
|
|
|
high_freq_value = raw_high_freq_value |
|
|
|
|
|
|
|
high_freq_range = [0, 150] |
|
|
|
|
|
|
|
while high_freq_value < high_freq_range[1]: |
|
|
|
|
|
|
|
step = 20 |
|
|
|
|
|
|
|
high_freq_value += step |
|
|
|
|
|
|
|
if high_freq_value > high_freq_range[1]: |
|
|
|
|
|
|
|
high_freq_value = high_freq_range[1] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
self.remote_reg_tool.write_high_freq_reg(exp_id, remote_slot_id, remote_lane_id, high_freq_value) |
|
|
|
|
|
|
|
logging.info(f'Adjusted high_freq to {high_freq_value}') |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
eye = self.get_eye_diagram_per_lane(exp_id, eye.rt_phys_index, eye.phys_lane_index) |
|
|
|
|
|
|
|
logging.info(f'After high_freq adjustment, eye issue: {eye.issue.name}') |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if eye.issue != EyeIssue.EYE_TOO_UP or high_freq_value == high_freq_range[1]: |
|
|
|
|
|
|
|
break |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
logging.info(f'Final high_freq adjustment result: high_freq={high_freq_value}, eye issue={eye.issue.name}') |
|
|
|
|
|
|
|
return eye |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def adjust_opcurrent_for_up_eye(self, exp_id: int, eye: EyeData, remote_slot_id: int, remote_lane_id: int) -> EyeData: |
|
|
|
|
|
|
|
raw_eye_issue = eye.issue |
|
|
|
|
|
|
|
raw_opcurrent_value = self.remote_reg_tool.read_opcurrent_reg(exp_id, remote_slot_id, remote_lane_id) |
|
|
|
|
|
|
|
logging.info(f'Initial opcurrent_value: {raw_opcurrent_value}') |
|
|
|
|
|
|
|
op_range = [0, 190] |
|
|
|
|
|
|
|
opcurrent_value = raw_opcurrent_value |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
while opcurrent_value > op_range[0]: |
|
|
|
|
|
|
|
step = 10 |
|
|
|
|
|
|
|
opcurrent_value -= step |
|
|
|
|
|
|
|
if opcurrent_value < op_range[0]: |
|
|
|
|
|
|
|
opcurrent_value = op_range[0] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
self.remote_reg_tool.write_opcurrent_reg(exp_id, remote_slot_id, remote_lane_id, opcurrent_value) |
|
|
|
|
|
|
|
logging.info(f'Adjusted opcurrent to {opcurrent_value}') |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
eye = self.get_eye_diagram_per_lane(exp_id, eye.rt_phys_index, eye.phys_lane_index) |
|
|
|
|
|
|
|
logging.info(f'After opcurrent adjustment, eye issue: {eye.issue.name}') |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if eye.issue != raw_eye_issue or opcurrent_value == op_range[0]: |
|
|
|
|
|
|
|
break |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 如果没有改善,恢复原始值 |
|
|
|
|
|
|
|
if eye.issue == raw_eye_issue: |
|
|
|
|
|
|
|
self.remote_reg_tool.write_opcurrent_reg(exp_id, remote_slot_id, remote_lane_id, raw_opcurrent_value) |
|
|
|
|
|
|
|
logging.info(f'No improvement, rollback opcurrent to {raw_opcurrent_value}') |
|
|
|
|
|
|
|
else: |
|
|
|
|
|
|
|
logging.info(f'opcurrent adjustment successful, final value: {opcurrent_value}') |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return eye |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_issue_eye_diagram(self, exp_id: int, retimer_index: int, attempts: int = 1) -> List[EyeData]: |
|
|
|
|
|
|
|
all_measurements: DefaultDict[int, List[EyeData]] = defaultdict(list) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for attempt in range(1, attempts + 1): |
|
|
|
|
|
|
|
logger.info(f"RTMR{retimer_index} measurement attempt {attempt}/{attempts}") |
|
|
|
|
|
|
|
eye_data_list = self.get_eye_diagram(exp_id, retimer_index) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if not eye_data_list: |
|
|
|
|
|
|
|
logger.error(f"Attempt {attempt} failed for RTMR{retimer_index}") |
|
|
|
|
|
|
|
continue |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for eye_data in eye_data_list: |
|
|
|
|
|
|
|
all_measurements[eye_data.lane_index].append(eye_data) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if not all_measurements: |
|
|
|
|
|
|
|
logger.error(f"No valid measurements for RTMR{retimer_index}") |
|
|
|
|
|
|
|
return [] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
worst_eyes: List[EyeData] = [] |
|
|
|
|
|
|
|
for lane_idx, measurements in all_measurements.items(): |
|
|
|
|
|
|
|
logging.debug(f'---------- lan_inx: {lane_idx}, measurements: {measurements}') |
|
|
|
|
|
|
|
worst_eye = self.determine_issue(measurements) |
|
|
|
|
|
|
|
worst_eyes.append(worst_eye) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bad_eyes = [eye for eye in worst_eyes if eye.issue != EyeIssue.EYE_NORMAL] |
|
|
|
|
|
|
|
return bad_eyes |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def determine_issue(self, measurements: List[EyeData]): |
|
|
|
|
|
|
|
# 优先级: 小,大,上,下, |
|
|
|
|
|
|
|
# 假设不会有偏光导致眼图小的情况,一定是先解决眼图小和大的问题,再解决眼图上和下的问题 |
|
|
|
|
|
|
|
worst_eye = min(measurements, key=lambda x: x.quality_score) |
|
|
|
|
|
|
|
if worst_eye.issue in [EyeIssue.EYE_NORMAL, EyeIssue.EYE_TOO_LARGE]: |
|
|
|
|
|
|
|
# 如果是眼最小的是正常的或者偏大的, 那就返回最大的 |
|
|
|
|
|
|
|
worst_eye = max(measurements, key=lambda x: x.quality_score) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return worst_eye |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_worst_eye_diagram_per_lane(self, exp_id: int, retimer_phys_index: int, |
|
|
|
|
|
|
|
phys_lane: int, attempts: int = 3) -> EyeData: |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
measurements: List[EyeData] = [] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for attempt in range(1, attempts + 1): |
|
|
|
|
|
|
|
try: |
|
|
|
|
|
|
|
logger.info(f"Attempt {attempt}/{attempts} for RTMR{retimer_phys_index} Lane{phys_lane}") |
|
|
|
|
|
|
|
eye_data = self.get_eye_diagram_per_lane(exp_id, retimer_phys_index, phys_lane) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if eye_data.rt_phys_index != -1: |
|
|
|
|
|
|
|
measurements.append(eye_data) |
|
|
|
|
|
|
|
logger.info(f"Measurement {attempt}: {eye_data}") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 如果发现眼图有问题,直接返回,不再继续查询 |
|
|
|
|
|
|
|
if eye_data.issue != EyeIssue.EYE_NORMAL: |
|
|
|
|
|
|
|
logger.info(f"Eye issue detected: {eye_data.issue.name}, returning immediately") |
|
|
|
|
|
|
|
return eye_data |
|
|
|
|
|
|
|
else: |
|
|
|
|
|
|
|
logger.warning(f"Invalid measurement in attempt {attempt}") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
except Exception as e: |
|
|
|
|
|
|
|
logger.error(f"Attempt {attempt} failed: {str(e)}") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 如果所有尝试都是正常眼图,则进行综合判断 |
|
|
|
|
|
|
|
if not measurements: |
|
|
|
|
|
|
|
logger.error(f"No valid measurements obtained after {attempts} attempts") |
|
|
|
|
|
|
|
return EyeData() # 返回默认的空数据 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 找出质量最差的眼图 |
|
|
|
|
|
|
|
worst_eye = self.determine_issue(measurements) |
|
|
|
|
|
|
|
logger.warning(f"Worst eye diagram for RTMR{retimer_phys_index} Lane{phys_lane}: " |
|
|
|
|
|
|
|
f"Quality score: {worst_eye.quality_score:.2f}") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return worst_eye |
|
|
|
|
|
|
|
def get_eye_diagram_per_lane(self, exp_id: int, retimer_phys_index: int, |
|
|
|
|
|
|
|
phys_lane: int, attempts: int = 3) -> EyeData: |
|
|
|
|
|
|
|
measurements: List[EyeData] = [] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for attempt in range(1, attempts + 1): |
|
|
|
|
|
|
|
try: |
|
|
|
|
|
|
|
logger.info(f"Attempt {attempt}/{attempts} for RTMR{retimer_phys_index} Lane{phys_lane}") |
|
|
|
|
|
|
|
eye_data = self.get_eye_diagram_per_lane_1_count(exp_id, retimer_phys_index, phys_lane) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if eye_data.rt_phys_index != -1: |
|
|
|
|
|
|
|
measurements.append(eye_data) |
|
|
|
|
|
|
|
logger.info(f"Measurement {attempt}: {eye_data}") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 如果发现眼图有问题,直接返回,不再继续查询 |
|
|
|
|
|
|
|
if eye_data.issue != EyeIssue.EYE_NORMAL: |
|
|
|
|
|
|
|
logger.info(f"Eye issue detected: {eye_data.issue.name}, returning immediately") |
|
|
|
|
|
|
|
return eye_data |
|
|
|
|
|
|
|
else: |
|
|
|
|
|
|
|
logger.warning(f"Invalid measurement in attempt {attempt}") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
except Exception as e: |
|
|
|
|
|
|
|
logger.error(f"Attempt {attempt} failed: {str(e)}") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 如果所有尝试都是正常眼图,则进行综合判断 |
|
|
|
|
|
|
|
if not measurements: |
|
|
|
|
|
|
|
logger.error(f"No valid measurements obtained after {attempts} attempts") |
|
|
|
|
|
|
|
return EyeData() # 返回默认的空数据 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 找出质量最差的眼图 |
|
|
|
|
|
|
|
worst_eye = self.determine_issue(measurements) |
|
|
|
|
|
|
|
logger.warning(f"Worst eye diagram for RTMR{retimer_phys_index} Lane{phys_lane}: " |
|
|
|
|
|
|
|
f"Quality score: {worst_eye.quality_score:.2f}") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return worst_eye |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_eye_diagram_per_lane_1_count(self, exp_id: int, retimer_phys_index: int, phys_lane: int) -> EyeData: |
|
|
|
|
|
|
|
eye_data = EyeData() |
|
|
|
|
|
|
|
cmd = f"rtmr {retimer_phys_index} eye 0 a {phys_lane}" |
|
|
|
|
|
|
|
try: |
|
|
|
|
|
|
|
raw_output = self.local_bmc.CmdVendorCommand(exp_id, cmd) |
|
|
|
|
|
|
|
# logging.info(f'raw_output: {raw_output}') |
|
|
|
|
|
|
|
if raw_output == '': |
|
|
|
|
|
|
|
logger.error(f"No data returned from command: {cmd}") |
|
|
|
|
|
|
|
return eye_data |
|
|
|
|
|
|
|
eye_datas = self.parse_eye_data(raw_output) |
|
|
|
|
|
|
|
return eye_datas[0] |
|
|
|
|
|
|
|
except Exception as e: |
|
|
|
|
|
|
|
logger.error(f"Error executing command '{cmd}': {e}") |
|
|
|
|
|
|
|
return eye_data |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_eye_diagram(self, exp_id: int, retimer_index: int) -> List[EyeData]: |
|
|
|
|
|
|
|
cmd = f"rtmr {retimer_index} eye 0 a" |
|
|
|
|
|
|
|
try: |
|
|
|
|
|
|
|
raw_output = self.local_bmc.CmdVendorCommand(exp_id, cmd) |
|
|
|
|
|
|
|
if not raw_output: |
|
|
|
|
|
|
|
logger.error(f"No data returned from command: {cmd}") |
|
|
|
|
|
|
|
return [] |
|
|
|
|
|
|
|
return self.parse_eye_data(raw_output) |
|
|
|
|
|
|
|
except Exception as e: |
|
|
|
|
|
|
|
logger.error(f"Error executing command '{cmd}': {e}") |
|
|
|
|
|
|
|
return [] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def parse_eye_data(self, text: str) -> List[EyeData]: |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pattern = ( |
|
|
|
|
|
|
|
r"RTMR(\d+)\s+EYE_A(\d+):\s*" |
|
|
|
|
|
|
|
r"\((-?\d+\.?\d*),\s*(-?\d+\.?\d*)\)\s*mV\s*\|\s*" |
|
|
|
|
|
|
|
r"\((-?\d+\.?\d*),\s*(-?\d+\.?\d*)\)\s*UI" |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
regex = re.compile(pattern) |
|
|
|
|
|
|
|
results = [] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for line_num, line in enumerate(text.strip().splitlines(), 1): |
|
|
|
|
|
|
|
line = line.strip() |
|
|
|
|
|
|
|
if not line or "error" in line.lower(): |
|
|
|
|
|
|
|
continue |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
match = regex.search(line) # 使用 search 允许前后有额外字符 |
|
|
|
|
|
|
|
if not match: |
|
|
|
|
|
|
|
logger.debug(f"Line {line_num}: Skipped (no match) - {line}") |
|
|
|
|
|
|
|
continue |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
try: |
|
|
|
|
|
|
|
rtmr_prefix = match.group(1) |
|
|
|
|
|
|
|
eye_index = int(match.group(2)) |
|
|
|
|
|
|
|
down = float(match.group(3)) |
|
|
|
|
|
|
|
top = float(match.group(4)) |
|
|
|
|
|
|
|
left = float(match.group(5)) |
|
|
|
|
|
|
|
right = float(match.group(6)) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 计算真实 retimer_index 和 lane_index |
|
|
|
|
|
|
|
rt_phys_index = int(f"{rtmr_prefix}") |
|
|
|
|
|
|
|
phys_lane_index = eye_index |
|
|
|
|
|
|
|
if eye_index < 8: |
|
|
|
|
|
|
|
rt_index = int(f"{rtmr_prefix}1") |
|
|
|
|
|
|
|
lane_index = eye_index |
|
|
|
|
|
|
|
else: |
|
|
|
|
|
|
|
rt_index = int(f"{rtmr_prefix}2") |
|
|
|
|
|
|
|
lane_index = eye_index - 8 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
eye_data = EyeData( |
|
|
|
|
|
|
|
rt_phys_index=rt_phys_index, |
|
|
|
|
|
|
|
phys_lane_index=phys_lane_index, |
|
|
|
|
|
|
|
rt_index=rt_index, |
|
|
|
|
|
|
|
lane_index=lane_index, |
|
|
|
|
|
|
|
down=down, |
|
|
|
|
|
|
|
top=top, |
|
|
|
|
|
|
|
left=left, |
|
|
|
|
|
|
|
right=right |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
eye_data.determine_issue() # 初始化问题类型 |
|
|
|
|
|
|
|
results.append(eye_data) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
except Exception as e: |
|
|
|
|
|
|
|
logger.error(f"Failed to parse line {line_num}: {line} | Error: {e}") |
|
|
|
|
|
|
|
continue |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
logger.info(f"Parsed {len(results)} valid eye diagrams.") |
|
|
|
|
|
|
|
return results |