🐛 fix(xsct): PS init before FPGA config keeps JTAG DAP alive
Root cause: fpga -file breaks the DAP unless PS is initialized first. Solution: source ps7_init.tcl + ps7_init + targets 1 BEFORE fpga -file. Changes: - _program_with_xsct: init PS (clocks/DDR/MIO) before fpga -file → DAP stays alive, subsequent ELF download works - _run_elf_with_xsct: simplified - no reconnect needed, DAP is healthy (kept ps7_init fallback for recovery) - program_bitstream: auto-detects ps7_init.tcl from BIT file directory Verified on hardware: Session 1 (BIT): connect → ps7_init → fpga → exit (13s) ✓ Session 2 (ELF): connect → targets 2 → dow → con (9s) ✓
This commit is contained in:
+30
-21
@@ -144,8 +144,8 @@ def program_bitstream(
|
|||||||
) -> BitstreamResult:
|
) -> BitstreamResult:
|
||||||
"""Download a .bit bitstream to the Zynq PL (FPGA fabric).
|
"""Download a .bit bitstream to the Zynq PL (FPGA fabric).
|
||||||
|
|
||||||
Attempts xsct first (fast, lightweight), then falls back to Vivado
|
Inits PS (ps7_init) before FPGA config to keep the JTAG DAP alive,
|
||||||
batch mode.
|
allowing subsequent ELF download without reconnection issues.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
config: Application configuration.
|
config: Application configuration.
|
||||||
@@ -166,10 +166,13 @@ def program_bitstream(
|
|||||||
if callback:
|
if callback:
|
||||||
callback("start", f"Loading bitstream: {bit_path.name}...")
|
callback("start", f"Loading bitstream: {bit_path.name}...")
|
||||||
|
|
||||||
|
# Find ps7_init.tcl for PS initialization
|
||||||
|
ps7_tcl = _find_ps7_init_tcl(config)
|
||||||
|
|
||||||
# Try xsct first (preferred)
|
# Try xsct first (preferred)
|
||||||
xsct = get_xsct_path(config.vitis_path)
|
xsct = get_xsct_path(config.vitis_path)
|
||||||
if xsct:
|
if xsct:
|
||||||
return _program_with_xsct(xsct, bit_path, callback)
|
return _program_with_xsct(xsct, bit_path, callback, ps7_tcl)
|
||||||
|
|
||||||
# Fallback to Vivado
|
# Fallback to Vivado
|
||||||
vivado = _get_vivado_path(config.vitis_path)
|
vivado = _get_vivado_path(config.vitis_path)
|
||||||
@@ -187,30 +190,38 @@ def _program_with_xsct(
|
|||||||
xsct_path: str,
|
xsct_path: str,
|
||||||
bit_path: Path,
|
bit_path: Path,
|
||||||
callback: ProgressCallback = None,
|
callback: ProgressCallback = None,
|
||||||
|
ps7_init_tcl: str = "",
|
||||||
) -> BitstreamResult:
|
) -> BitstreamResult:
|
||||||
"""Program bitstream using xsct's fpga command.
|
"""Program bitstream using xsct's fpga command.
|
||||||
|
|
||||||
xsct connects to hw_server and uses the `fpga` command to download
|
Inits the PS (clocks, DDR, MIO) before FPGA configuration to keep
|
||||||
the bitstream to the PL fabric.
|
the JTAG DAP alive. Without PS init, the DAP breaks after fpga,
|
||||||
|
preventing subsequent ELF download.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
xsct_path: Path to xsct executable.
|
xsct_path: Path to xsct executable.
|
||||||
bit_path: Path to .bit file.
|
bit_path: Path to .bit file.
|
||||||
callback: Optional progress callback.
|
callback: Optional progress callback.
|
||||||
|
ps7_init_tcl: Path to ps7_init.tcl for PS initialization.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
BitstreamResult with status.
|
BitstreamResult with status.
|
||||||
"""
|
"""
|
||||||
if callback:
|
if callback:
|
||||||
callback("progress", "Using xsct to download bitstream...")
|
callback("progress", "Initializing PS then programming FPGA...")
|
||||||
|
|
||||||
|
# Build TCL: PS init first, then FPGA config
|
||||||
|
lines = ["connect"]
|
||||||
|
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")
|
||||||
|
if callback:
|
||||||
|
callback("progress", "PS initialized (clocks, DDR, MIO)")
|
||||||
|
lines.append(f'fpga -file "{bit_path}"')
|
||||||
|
lines.append("exit")
|
||||||
|
tcl_script = "\n".join(lines)
|
||||||
|
|
||||||
# xsct TCL: connect to hw_server, target FPGA, download bitstream
|
|
||||||
tcl_script = f"""
|
|
||||||
connect
|
|
||||||
targets
|
|
||||||
fpga -file "{bit_path}"
|
|
||||||
exit
|
|
||||||
"""
|
|
||||||
import tempfile, os
|
import tempfile, os
|
||||||
with tempfile.NamedTemporaryFile(mode='w', suffix='.tcl', delete=False) as f:
|
with tempfile.NamedTemporaryFile(mode='w', suffix='.tcl', delete=False) as f:
|
||||||
f.write(tcl_script)
|
f.write(tcl_script)
|
||||||
@@ -351,27 +362,25 @@ 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.
|
||||||
|
|
||||||
After PL configuration (via fpga), the DAP may be disrupted.
|
Assumes PS was already initialized (by a prior BIT download step).
|
||||||
This function reconnects, sources ps7_init.tcl to initialize
|
Falls back to PS init if DAP is broken.
|
||||||
the PS, then downloads the ELF to Cortex-A9 #0.
|
|
||||||
|
|
||||||
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: Path to ps7_init.tcl for PS initialization.
|
ps7_init_tcl: Optional ps7_init.tcl path for recovery.
|
||||||
Auto-detected from BIT file directory if empty.
|
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
BitstreamResult with status.
|
BitstreamResult with status.
|
||||||
"""
|
"""
|
||||||
if callback:
|
if callback:
|
||||||
callback("progress", "Using xsct to download ELF...")
|
callback("progress", "Downloading ELF...")
|
||||||
|
|
||||||
# Build TCL: reconnect (DAP may be broken after PL config),
|
|
||||||
# source ps7_init for PS init, then dow + con
|
|
||||||
lines = ["connect"]
|
lines = ["connect"]
|
||||||
|
# Recovery: if DAP is broken, re-init PS
|
||||||
if ps7_init_tcl and Path(ps7_init_tcl).exists():
|
if ps7_init_tcl and Path(ps7_init_tcl).exists():
|
||||||
|
lines.append("targets 1")
|
||||||
lines.append(f'source "{ps7_init_tcl}"')
|
lines.append(f'source "{ps7_init_tcl}"')
|
||||||
lines.append("ps7_init")
|
lines.append("ps7_init")
|
||||||
lines.append("targets 2")
|
lines.append("targets 2")
|
||||||
|
|||||||
Reference in New Issue
Block a user