Files
zynq7000-rs/scripts/zynq7000-init.py
Robin Mueller 5d0f2837d1
Some checks failed
ci / Check build (pull_request) Has been cancelled
ci / Check formatting (pull_request) Has been cancelled
ci / Check Documentation Build (pull_request) Has been cancelled
ci / Clippy (pull_request) Has been cancelled
ci / Check build (push) Has been cancelled
ci / Check formatting (push) Has been cancelled
ci / Check Documentation Build (push) Has been cancelled
ci / Clippy (push) Has been cancelled
Introduce Rust FSBL
This PR introduces some major features while also changing the project structure to be more flexible
for multiple platforms (e.g. host tooling). It also includes a lot of
bugfixes, renamings for consistency purposes and dependency updates.

Added features:

1. Pure Rust FSBL for the Zedboard. This first variant is simplistic. It
   is currently only capable of QSPI boot. It searches for a bitstream
   and ELF file inside the boot binary, flashes them and jumps to them.
2. QSPI flasher for the Zedboard.
3. DDR, QSPI, DEVC, private CPU timer and PLL configuration modules
3. Tooling to auto-generate board specific DDR and DDRIOB config
   parameters from the vendor provided ps7init.tcl file

Changed project structure:

1. All target specific project are inside a dedicated workspace inside
   the `zynq` folder now.
2. All tool intended to be run on a host are inside a `tools` workspace
3. All other common projects are at the project root

Major bugfixes:

1. SPI module: CPOL was not configured properly
2. Logger flush implementation was empty, implemented properly now.
2025-10-08 20:21:04 +02:00

157 lines
5.3 KiB
Python
Executable File

#!/usr/bin/env python3
import shlex
import argparse
import os
import subprocess
import sys
from pathlib import Path
# Define the default values
TCL_SCRIPT_NAME = "xsct-flasher.tcl"
SCRIPTS_DIR = "scripts"
DEFAULT_IP_ADDRESS_HW_SERVER = "localhost"
def main():
parser = argparse.ArgumentParser(
description="Wrapper script for xsct-init.tcl\n"
"It launches xsct, initialize and prepare the processing system for debugging and "
"allows loading a bitstream and/or bare-metal application to the board.",
formatter_class=argparse.RawTextHelpFormatter, # This preserves line breaks
)
parser.add_argument(
"-t",
"--tools",
# Required only if env var is not set
required=not bool(os.getenv("AMD_TOOLS")),
# Use env var if set
default=os.getenv("AMD_TOOLS"),
help="The path to the tool to use. Must point to a valid Vivado tools installation which"
"also provides xsct, for example a Vitis installation.\nThe directory where the path "
"points to should contain a shell script named settings64.sh.\nYou can also set the "
"AMD_TOOLS env variable to set this.",
)
parser.add_argument(
"--sdt",
dest="sdt",
help="Path to a SDT output folder which contains a PS7 init TCL script and a bitstream.",
)
parser.add_argument(
"--no-bit",
dest="no_bit",
action="store_true",
help="No bitstream flashing for initialization with SDT.",
)
parser.add_argument("-a", "--app", dest="app", help="Path to the app to program")
parser.add_argument(
"-i",
"--ip",
default=DEFAULT_IP_ADDRESS_HW_SERVER,
help="The IP address of the hardware server (default: localhost)",
)
parser.add_argument(
"--itcl",
dest="init_tcl",
default=os.getenv("TCL_INIT_SCRIPT"),
help="Path to the ps7 initialization TCL file to prepare the processing system.\n"
"You can also set the TCL_INIT_SCRIPT env variable to set this.\n"
"It is also set implicitely when specifying the SDT folder with --sdt",
)
parser.add_argument(
"-b",
"--bit",
dest="bit",
default=os.getenv("ZYNQ_BITSTREAM"),
help="Optional path to the bitstream which will also be programed to the device. It is"
" also searched automatically if the --sdt option is used.\n",
)
args = parser.parse_args()
settings_script = os.path.join(args.tools, "settings64.sh")
if not os.path.isfile(settings_script):
print(f"Invalid tool path {args.tools}, did not find settings file.")
sys.exit(1)
# Source the settings script and check for xsdb availability
command = f"source {settings_script} && command -v xsct"
result = subprocess.run(
command,
shell=True,
capture_output=True,
executable="/bin/bash",
)
if result.returncode != 0:
print("Error: 'xsct' could not be found after sourcing settings64.sh.")
sys.exit(1)
if args.app and not os.path.isfile(args.app):
print(f"The app '{args.app}' does not exist")
sys.exit(1)
os.environ["IP_ADDRESS_HW_SERVER"] = args.ip
init_tcl = None
bitstream = None
if args.bit:
bitstream = args.bit
if args.sdt:
sdt_path = Path(args.sdt)
# CLI bitstream argument overrides implicit SDT bitstream.
if not args.no_bit and not bitstream:
# Search for .bit files in the SDT folder
bit_files = list(sdt_path.glob("*.bit"))
if len(bit_files) == 0:
print("Error: No .bit file found in the SDT folder.")
elif len(bit_files) > 1:
print("Error: Multiple .bit files found in the SDT folder.")
bitstream = str(bit_files[0])
# Search for the ps7_init.tcl file
init_script = sdt_path / "ps7_init.tcl"
if not init_script.exists():
sys.exit("Error: ps7_init.tcl file not found in the SDT folder.")
init_tcl = str(init_script)
else:
if not args.init_tcl:
print("Error: No ps7_init.tcl file specified.")
sys.exit(1)
if args.bit:
bitstream = args.bit
init_tcl = args.init_tcl
# Get the script's directory
script_dir = Path(__file__).resolve().parent
xsct_script = script_dir / TCL_SCRIPT_NAME
if not xsct_script.exists():
xsct_script = Path(os.path.join(SCRIPTS_DIR, TCL_SCRIPT_NAME))
if not xsct_script.exists():
print(f"Could not find the xsct initialization script {TCL_SCRIPT_NAME}")
sys.exit(1)
# Launch xsct with the initialization script
# Prepare tcl_args as a list to avoid manual string concatenation issues
cmd_list = ["xsct", str(xsct_script), init_tcl]
if bitstream:
cmd_list.append("--bit")
cmd_list.append(bitstream)
if args.app:
cmd_list.append("--app")
cmd_list.append(args.app)
# Join safely for shell execution
xsct_cmd = shlex.join(cmd_list)
print(f"Running xsct command: {xsct_cmd}")
command = f"bash -c 'source {settings_script} && {xsct_cmd} | tee xsct-output.log'"
subprocess.run(
command,
shell=True,
check=True,
)
if __name__ == "__main__":
main()