feat: user TCL flow + parser dedup + Python TFTP
1. bitstream_programmer — combined BIT+ELF flow (user's TCL):
- targets -set -nocase -filter {name =~ "arm*#0"}
- rst -processor (bypass BootROM, block Flash boot)
- dow fsbl → con → stop (FSBL hardware init)
- fpga -f bit (configure PL)
- dow app → con (run bootloader)
- Single xsct session, no ps7_init dependency
2. serial_monitor — parser fixes:
- Boot mode parsing: 'Boot mode is JTAG' → Boot=JTAG
- Version noise filter: rejects '3.1','update','mode','loaded'
- Deduplication: UartMonitor only emits when (boot_mode, IP, ver) changes
- Fixed false match: 'Boot mode' no longer captured as version
3. tftp_manager — pure Python TFTP client:
- _tftp_put(): RFC 1350 WRQ/DATA/ACK via UDP socket
- No external tftp command dependency
- tftp_download(): documented as not-implemented (needs PC server)
This commit is contained in:
+117
-8
@@ -535,7 +535,7 @@ def _run_elf_direct(
|
||||
message="ELF download timed out")
|
||||
|
||||
|
||||
# ── Full Workflow ───────────────────────────────────────────────────
|
||||
# ── Full Workflow (combined BIT+ELF in one xsct session) ──────────
|
||||
|
||||
|
||||
def full_bitstream_program(
|
||||
@@ -544,7 +544,13 @@ def full_bitstream_program(
|
||||
elf_path: str | Path,
|
||||
callback: ProgressCallback = None,
|
||||
) -> list[BitstreamResult]:
|
||||
"""Execute full bootloader workflow: program bitstream → run ELF.
|
||||
"""Execute full bootloader workflow in one xsct session.
|
||||
|
||||
Flow:
|
||||
1. rst -processor (bypass BootROM, block Flash boot)
|
||||
2. dow fsbl → con → stop (FSBL initializes clocks/DDR/MIO)
|
||||
3. fpga -f bit (configure PL)
|
||||
4. dow app → con (run bootloader)
|
||||
|
||||
Args:
|
||||
config: Application configuration.
|
||||
@@ -555,11 +561,114 @@ def full_bitstream_program(
|
||||
Returns:
|
||||
List of BitstreamResult for each step.
|
||||
"""
|
||||
results: list[BitstreamResult] = []
|
||||
import tempfile, os
|
||||
|
||||
results.append(program_bitstream(config, bit_path, callback))
|
||||
if not results[-1].success:
|
||||
return results
|
||||
bit_path = Path(bit_path)
|
||||
elf_path = Path(elf_path)
|
||||
fsbl_path = config.fsbl_elf_path if hasattr(config, 'fsbl_elf_path') else ""
|
||||
|
||||
results.append(run_elf(config, elf_path, callback))
|
||||
return results
|
||||
# Validate files
|
||||
if not bit_path.exists():
|
||||
return [BitstreamResult(step="bitstream", success=False,
|
||||
message=f"BIT not found: {bit_path}")]
|
||||
if not elf_path.exists():
|
||||
return [BitstreamResult(step="elf", success=False,
|
||||
message=f"ELF not found: {elf_path}")]
|
||||
if not fsbl_path or not Path(fsbl_path).exists():
|
||||
return [BitstreamResult(step="elf", success=False,
|
||||
message=f"FSBL not found: {fsbl_path or '(not configured)'}")]
|
||||
|
||||
xsct = get_xsct_path(
|
||||
vitis_path=config.vitis_path if hasattr(config, 'vitis_path') else "",
|
||||
xilinx_root=config.xilinx_path if hasattr(config, 'xilinx_path') else "",
|
||||
)
|
||||
if not xsct:
|
||||
return [BitstreamResult(step="bitstream", success=False,
|
||||
message="xsct not found")]
|
||||
|
||||
if callback:
|
||||
callback("start", "Initializing Zynq via JTAG (FSBL override)...")
|
||||
|
||||
tcl = "\n".join([
|
||||
'puts "INFO: Starting Zynq initialization via JTAG override..."',
|
||||
"connect",
|
||||
"after 500",
|
||||
# 1. Select ARM Core 0
|
||||
'targets -set -nocase -filter {name =~ "arm*#0"}',
|
||||
# 2. Reset processor (bypass BootROM Flash boot)
|
||||
'puts "INFO: Resetting processor (Bypassing BootROM Flash boot)..."',
|
||||
"rst -processor",
|
||||
"after 500",
|
||||
# 3. Download FSBL to OCM
|
||||
'puts "INFO: Downloading FSBL..."',
|
||||
'dow "%s"' % fsbl_path,
|
||||
# 4. Run FSBL for hardware init (clocks, DDR, MIO)
|
||||
'puts "INFO: Running FSBL for hardware initialization..."',
|
||||
"con",
|
||||
"after 2000",
|
||||
"stop",
|
||||
'puts "INFO: Hardware initialization completed."',
|
||||
# 5. Program PL bitstream
|
||||
'puts "INFO: Downloading Bitstream..."',
|
||||
'fpga -f "%s"' % bit_path,
|
||||
"after 1000",
|
||||
# 6. Back to ARM Core 0, download and run app
|
||||
'targets -set -nocase -filter {name =~ "arm*#0"}',
|
||||
'puts "INFO: Downloading Application ELF..."',
|
||||
'dow "%s"' % elf_path,
|
||||
'puts "INFO: Executing Application..."',
|
||||
"con",
|
||||
'puts "SUCCESS: Zynq target is running the specified application."',
|
||||
"exit",
|
||||
])
|
||||
|
||||
with tempfile.NamedTemporaryFile(
|
||||
mode="w", suffix=".tcl", delete=False
|
||||
) as tf:
|
||||
tf.write(tcl)
|
||||
tcl_file = tf.name
|
||||
|
||||
timeout = config.step_timeouts.get("bitstream", 60) + \
|
||||
config.step_timeouts.get("elf_download", 60)
|
||||
|
||||
try:
|
||||
if callback:
|
||||
callback("progress", "Executing combined JTAG flow...")
|
||||
|
||||
result = subprocess.run(
|
||||
[xsct, tcl_file],
|
||||
capture_output=True, text=True, timeout=timeout,
|
||||
)
|
||||
os.unlink(tcl_file)
|
||||
output = (result.stdout + result.stderr).strip()
|
||||
|
||||
success = result.returncode == 0 and "SUCCESS" in output
|
||||
|
||||
if callback:
|
||||
callback(
|
||||
"complete" if success else "error",
|
||||
"Bootloader " + ("running" if success else "failed"),
|
||||
)
|
||||
|
||||
return [
|
||||
BitstreamResult(
|
||||
step="bitstream",
|
||||
success=success,
|
||||
message="Bitstream loaded" if success else "Combined flow failed",
|
||||
output=output[:4000],
|
||||
),
|
||||
BitstreamResult(
|
||||
step="elf",
|
||||
success=success,
|
||||
message="ELF executed" if success else "Combined flow failed",
|
||||
output=output[:4000],
|
||||
),
|
||||
]
|
||||
except subprocess.TimeoutExpired:
|
||||
os.unlink(tcl_file)
|
||||
return [
|
||||
BitstreamResult(step="bitstream", success=False,
|
||||
message="Combined JTAG flow timed out"),
|
||||
BitstreamResult(step="elf", success=False,
|
||||
message="Combined JTAG flow timed out"),
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user