fix: ELF step no longer re-runs ps7_init unnecessarily
Problem: _run_elf_with_xsct() ALWAYS appended ps7_init before dow,
even though PS was already initialized by the prior BIT download step.
Re-running ps7_init after FPGA config resets PS registers (clocks,
DDR, MIO), which breaks subsequent ELF download.
Fix: two-attempt strategy —
1. First try WITHOUT ps7_init (DAP alive from BIT step):
connect → targets 2 → dow → con
2. If that fails, retry WITH ps7_init as DAP recovery:
connect → targets 1 → source ps7_init.tcl → ps7_init → targets 2 → dow → con
Additional improvements:
- Inner _run() helper deduplicates TCL execution logic
- Better progress messages distinguish attempts
- Extended success phrase detection (adds 'Successfully downloaded')
- Nested TimeoutExpired handling per attempt
This commit is contained in:
+80
-40
@@ -371,72 +371,112 @@ def _run_elf_with_xsct(
|
|||||||
) -> BitstreamResult:
|
) -> BitstreamResult:
|
||||||
"""Download and run ELF using xsct's dow command.
|
"""Download and run ELF using xsct's dow command.
|
||||||
|
|
||||||
Assumes PS was already initialized (by a prior BIT download step).
|
PS was already initialized by the prior BIT download step, so the
|
||||||
Falls back to PS init if DAP is broken.
|
DAP should be alive. First attempt skips ps7_init to avoid resetting
|
||||||
|
PS state. If DAP is broken, falls back to re-init PS.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
xsct_path: Path to xsct executable.
|
xsct_path: Path to xsct executable.
|
||||||
elf_path: Path to .elf file.
|
elf_path: Path to .elf file.
|
||||||
callback: Optional progress callback.
|
callback: Optional progress callback.
|
||||||
ps7_init_tcl: Optional ps7_init.tcl path for recovery.
|
ps7_init_tcl: Optional ps7_init.tcl path for recovery.
|
||||||
|
timeout: Subprocess timeout in seconds.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
BitstreamResult with status.
|
BitstreamResult with status.
|
||||||
"""
|
"""
|
||||||
if callback:
|
|
||||||
callback("progress", "Downloading ELF...")
|
|
||||||
|
|
||||||
lines = ["connect"]
|
|
||||||
# Recovery: if DAP is broken, re-init PS
|
|
||||||
if ps7_init_tcl and Path(ps7_init_tcl).exists():
|
|
||||||
lines.append("targets 1")
|
|
||||||
lines.append(f'source "{ps7_init_tcl}"')
|
|
||||||
lines.append("ps7_init")
|
|
||||||
lines.append("targets 2")
|
|
||||||
lines.append(f'dow "{elf_path}"')
|
|
||||||
lines.append("con")
|
|
||||||
lines.append("exit")
|
|
||||||
tcl_script = "\n".join(lines)
|
|
||||||
|
|
||||||
import tempfile, os
|
import tempfile, os
|
||||||
with tempfile.NamedTemporaryFile(mode='w', suffix='.tcl', delete=False) as f:
|
|
||||||
f.write(tcl_script)
|
|
||||||
tcl_file = f.name
|
|
||||||
|
|
||||||
|
has_ps7 = bool(ps7_init_tcl and Path(ps7_init_tcl).exists())
|
||||||
|
|
||||||
|
def _run(tcl: str) -> tuple[bool, str]:
|
||||||
|
"""Run TCL via xsct, return (success, output)."""
|
||||||
|
with tempfile.NamedTemporaryFile(
|
||||||
|
mode="w", suffix=".tcl", delete=False
|
||||||
|
) as tf:
|
||||||
|
tf.write(tcl)
|
||||||
|
tcl_file = tf.name
|
||||||
try:
|
try:
|
||||||
result = subprocess.run(
|
result = subprocess.run(
|
||||||
[xsct_path, tcl_file],
|
[xsct_path, tcl_file],
|
||||||
capture_output=True,
|
capture_output=True, text=True, timeout=timeout,
|
||||||
text=True,
|
|
||||||
timeout=timeout,
|
|
||||||
)
|
)
|
||||||
os.unlink(tcl_file)
|
os.unlink(tcl_file)
|
||||||
|
out = (result.stdout + result.stderr).strip()
|
||||||
|
ok = result.returncode == 0 or any(
|
||||||
|
p in out for p in (
|
||||||
|
"Download successful", "Done", "done",
|
||||||
|
"Successfully downloaded",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return ok, out
|
||||||
|
except subprocess.TimeoutExpired:
|
||||||
|
os.unlink(tcl_file)
|
||||||
|
raise
|
||||||
|
|
||||||
success = result.returncode == 0
|
# ── Attempt 1: no ps7_init (DAP alive from BIT step) ──
|
||||||
output = (result.stdout + result.stderr).strip()
|
if callback:
|
||||||
|
callback("progress", "Downloading ELF (DAP should be alive)...")
|
||||||
|
|
||||||
# xsct may return non-zero even if download succeeded
|
tcl1 = "\n".join([
|
||||||
if any(phrase in output for phrase in ("Download successful", "Done", "done")):
|
"connect",
|
||||||
success = True
|
"targets 2",
|
||||||
|
"dow \"%s\"" % elf_path,
|
||||||
|
"con",
|
||||||
|
"exit",
|
||||||
|
])
|
||||||
|
try:
|
||||||
|
ok1, out1 = _run(tcl1)
|
||||||
|
except subprocess.TimeoutExpired:
|
||||||
|
return BitstreamResult(step="elf", success=False,
|
||||||
|
message="ELF download timed out")
|
||||||
|
|
||||||
|
if ok1:
|
||||||
|
if callback:
|
||||||
|
callback("complete", "ELF executed")
|
||||||
|
return BitstreamResult(step="elf", success=True,
|
||||||
|
message="ELF executed successfully",
|
||||||
|
output=out1[:4000])
|
||||||
|
|
||||||
|
# ── Attempt 2: re-init PS to recover DAP ──
|
||||||
|
if not has_ps7:
|
||||||
|
if callback:
|
||||||
|
callback("error", "ELF failed — no ps7_init.tcl for recovery")
|
||||||
|
return BitstreamResult(step="elf", success=False,
|
||||||
|
message="ELF execution failed",
|
||||||
|
output=out1[:4000])
|
||||||
|
|
||||||
if callback:
|
if callback:
|
||||||
callback(
|
callback(
|
||||||
"complete" if success else "error",
|
"progress",
|
||||||
"ELF " + ("executed" if success else "failed"),
|
"DAP broken, re-initializing PS then retrying ELF...",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
tcl2 = "\n".join([
|
||||||
|
"connect",
|
||||||
|
"targets 1",
|
||||||
|
"source \"%s\"" % ps7_init_tcl,
|
||||||
|
"ps7_init",
|
||||||
|
"targets 2",
|
||||||
|
"dow \"%s\"" % elf_path,
|
||||||
|
"con",
|
||||||
|
"exit",
|
||||||
|
])
|
||||||
|
try:
|
||||||
|
ok2, out2 = _run(tcl2)
|
||||||
|
except subprocess.TimeoutExpired:
|
||||||
|
return BitstreamResult(step="elf", success=False,
|
||||||
|
message="ELF download (recovery) timed out")
|
||||||
|
|
||||||
|
if callback:
|
||||||
|
callback("complete" if ok2 else "error",
|
||||||
|
"ELF " + ("executed (recovery)" if ok2 else "failed after recovery"))
|
||||||
|
|
||||||
return BitstreamResult(
|
return BitstreamResult(
|
||||||
step="elf",
|
step="elf",
|
||||||
success=success,
|
success=ok2,
|
||||||
message="ELF executed successfully" if success else "ELF execution failed",
|
message=("ELF executed (DAP recovery)" if ok2 else "ELF execution failed"),
|
||||||
output=output[:4000],
|
output=out2[:4000],
|
||||||
)
|
|
||||||
except subprocess.TimeoutExpired:
|
|
||||||
os.unlink(tcl_file)
|
|
||||||
return BitstreamResult(
|
|
||||||
step="elf",
|
|
||||||
success=False,
|
|
||||||
message="xsct ELF download timed out",
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user