♻️ refactor(toolchain): replace impact/bootgen with xsct/program_flash + add fsbl

BREAKING: Replaces obsolete impact (ISE-era) and misused bootgen with
the correct Xilinx 2018.3–2023.2 toolchain.

Toolchain changes:
- vitis_checker: impact → xsct + program_flash + bootgen detection
- flash_programmer: bootgen/impact → program_flash (erase + program + verify)
- bitstream_programmer: impact → xsct fpga/dow (primary), vivado (fallback)
- Removed duplicated _get_impact_path() — now shared from vitis_checker

Config additions:
- fsbl_elf_path: FSBL ELF required by program_flash for QSPI init
- flash_type: QSPI mode (default: qspi-x4-single)

GUI additions:
- FSBL ELF file selector in Configuration panel
- Step 2 validates FSBL ELF is selected
- Step 1 now shows xsct/program_flash/bootgen in tool check
This commit is contained in:
Jeremy Shen
2026-06-10 12:13:02 +08:00
parent 1ad2dcdeb9
commit cddacc5d9f
6 changed files with 567 additions and 475 deletions
+23 -5
View File
@@ -184,6 +184,7 @@ class MainWindow(ctk.CTk):
self._config.bootloader_bit_path = files["bootloader_bit_path"]
self._config.bootloader_elf_path = files["bootloader_elf_path"]
self._config.bootloader_bin_path = files["bootloader_bin_path"]
self._config.fsbl_elf_path = files["fsbl_elf_path"]
self._config.firmware_bin_path = files["firmware_bin_path"]
def _save_config(self) -> None:
@@ -396,7 +397,7 @@ class MainWindow(ctk.CTk):
row=0, column=0, sticky="nsew",
padx=PADDING, pady=PADDING,
)
panel.grid_rowconfigure(5, weight=1)
panel.grid_rowconfigure(6, weight=1)
title = ctk.CTkLabel(
panel,
@@ -448,6 +449,17 @@ class MainWindow(ctk.CTk):
self._bootloader_bin_selector.set_path(str(resolved))
self._bootloader_bin_selector.grid(row=4, column=0, sticky="nsew", padx=PADDING, pady=PADDING_SMALL)
# FSBL ELF path (required by program_flash for QSPI programming)
self._fsbl_selector = FileSelector(
panel,
label_text="FSBL ELF (.elf):",
file_types=[("ELF files", "*.elf"), ("All files", "*")],
)
if self._config.fsbl_elf_path:
resolved = self._config.resolve_path(self._config.fsbl_elf_path)
self._fsbl_selector.set_path(str(resolved))
self._fsbl_selector.grid(row=5, column=0, sticky="nsew", padx=PADDING, pady=PADDING_SMALL)
# Firmware BIN path (TFTP upload)
self._firmware_bin_selector = FileSelector(
panel,
@@ -457,7 +469,7 @@ class MainWindow(ctk.CTk):
if self._config.firmware_bin_path:
resolved = self._config.resolve_path(self._config.firmware_bin_path)
self._firmware_bin_selector.set_path(str(resolved))
self._firmware_bin_selector.grid(row=5, column=0, sticky="nsew", padx=PADDING, pady=PADDING_SMALL)
self._firmware_bin_selector.grid(row=6, column=0, sticky="nsew", padx=PADDING, pady=PADDING_SMALL)
# Save button
save_btn = ctk.CTkButton(
@@ -466,7 +478,7 @@ class MainWindow(ctk.CTk):
font=FONT_SMALL,
command=self._save_config,
)
save_btn.grid(row=6, column=0, padx=PADDING, pady=PADDING)
save_btn.grid(row=7, column=0, padx=PADDING, pady=PADDING)
def _build_serial_panel(self, parent: ctk.CTkFrame) -> None:
"""Build the serial monitor panel."""
@@ -571,12 +583,13 @@ class MainWindow(ctk.CTk):
"""Get selected file paths from the UI.
Returns:
Dictionary with bootloader_bit_path, bootloader_elf_path, bootloader_bin_path, firmware_bin_path.
Dictionary with all file paths from UI selectors.
"""
return {
"bootloader_bit_path": self._bit_selector.get_path(),
"bootloader_elf_path": self._elf_selector.get_path(),
"bootloader_bin_path": self._bootloader_bin_selector.get_path(),
"fsbl_elf_path": self._fsbl_selector.get_path(),
"firmware_bin_path": self._firmware_bin_selector.get_path(),
}
@@ -681,7 +694,7 @@ class MainWindow(ctk.CTk):
self._uart_warning_label.pack(fill="x", padx=PADDING, pady=(0, PADDING_SMALL))
def _run_step_2_program_flash(self) -> bool:
"""Step 2: Program and verify Flash."""
"""Step 2: Program and verify Flash using program_flash."""
if not self._config:
return False
@@ -690,7 +703,12 @@ class MainWindow(ctk.CTk):
self._log_message(" No Bootloader BIN file selected")
return False
if not files["fsbl_elf_path"]:
self._log_message(" No FSBL ELF file selected (required by program_flash)")
return False
self._log_message(f"Step 2: Programming Flash with {files['bootloader_bin_path']}...")
self._log_message(f" FSBL: {files['fsbl_elf_path']}")
try:
bin_path = Path(files["bootloader_bin_path"])