From 04ad61e6945a969a48f4e7e089aa07f39e487fed Mon Sep 17 00:00:00 2001 From: Jeremy Shen Date: Thu, 11 Jun 2026 18:11:44 +0800 Subject: [PATCH] fix: convert all TCL-embedded paths to forward slashes (cross-platform) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Windows backslashes in TCL strings are interpreted as escape sequences (\f → form feed, \t → tab). This caused 'dow "Files\fsbl..."' to fail with garbled paths — TCL couldn't find the file. Added _tcl_path() helper: replaces \ with / in any path before embedding in TCL. Forward slashes work on all platforms including Windows. Applied to all 7 path sites: source, fpga -file, dow. --- src/bitstream_programmer.py | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/src/bitstream_programmer.py b/src/bitstream_programmer.py index b672a09..0b3c09a 100644 --- a/src/bitstream_programmer.py +++ b/src/bitstream_programmer.py @@ -37,6 +37,15 @@ ProgressCallback = Callable[[str, str], None] | None # ── Helpers ───────────────────────────────────────────────────────── +def _tcl_path(path: str | Path) -> str: + """Convert a filesystem path to TCL-safe format. + + TCL interprets backslashes as escape sequences (\\f, \\t, \\n). + Forward slashes work on all platforms including Windows. + """ + return str(path).replace("\\", "/") + + def _find_ps7_init_tcl(config: Config) -> str: """Find the ps7_init.tcl file for PS initialization. @@ -187,11 +196,11 @@ def _program_with_xsct( 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(f'source "{_tcl_path(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(f'fpga -file {{{_tcl_path(bit_path)}}}') if ps7_init_tcl and Path(ps7_init_tcl).exists(): lines.append("ps7_post_config") if callback: @@ -381,13 +390,13 @@ def _run_elf_via_fsbl( tcl = "\n".join([ "connect", "targets 2", - "dow \"%s\"" % fsbl_path, + "dow {%s}" % _tcl_path(fsbl_path), "puts \"FSBL downloaded\"", "con", "after 3000", "stop", "puts \"FSBL done, CPU halted\"", - "dow \"%s\"" % elf_path, + "dow {%s}" % _tcl_path(elf_path), "mwr 0xF800025C 0x00000001", "con", "puts \"App running\"", @@ -461,7 +470,7 @@ def _run_elf_direct( tcl = "\n".join([ "connect", "targets 2", - "dow \"%s\"" % elf_path, + "dow {%s}" % _tcl_path(elf_path), "mwr 0xF800025C 0x00000001", "con", "exit", @@ -620,18 +629,18 @@ def full_bitstream_program( "rst -processor", "after 500", 'puts "INFO: Downloading FSBL..."', - 'dow "%s"' % fsbl_path, + 'dow {%s}' % _tcl_path(fsbl_path), 'puts "INFO: Running FSBL for hardware initialization..."', "con", "after 2000", "stop", 'puts "INFO: Hardware initialization completed."', 'puts "INFO: Downloading Bitstream..."', - 'fpga -f "%s"' % bit_path, + 'fpga -f {%s}' % _tcl_path(bit_path), "after 1000", 'targets -set -nocase -filter {name =~ "arm*#0"}', 'puts "INFO: Downloading Application ELF..."', - 'dow "%s"' % elf_path, + 'dow {%s}' % _tcl_path(elf_path), 'puts "INFO: Executing Application..."', "con", 'puts "SUCCESS: Zynq target is running the specified application."',