Introduce Rust FSBL
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
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
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.
This commit is contained in:
22
scripts/memory_ddr.x
Normal file
22
scripts/memory_ddr.x
Normal file
@@ -0,0 +1,22 @@
|
||||
MEMORY
|
||||
{
|
||||
/* Zedboard: 512 MB DDR3. Only use 63 MB for now, should be plenty for a bare-metal app.
|
||||
Leave 1 MB of memory which will be configured as uncached device memory by the MMU. This is
|
||||
recommended for something like DMA descriptors. */
|
||||
CODE(rx) : ORIGIN = 0x00100000, LENGTH = 63M
|
||||
UNCACHED(rx): ORIGIN = 0x4000000, LENGTH = 1M
|
||||
}
|
||||
|
||||
REGION_ALIAS("DATA", CODE);
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
/* Uncached memory */
|
||||
.uncached (NOLOAD) : ALIGN(4) {
|
||||
. = ALIGN(4);
|
||||
_sbss_uncached = .;
|
||||
*(.uncached .uncached.*);
|
||||
. = ALIGN(4);
|
||||
_ebss_uncached = .;
|
||||
} > UNCACHED
|
||||
}
|
||||
24
scripts/memory_ocm.x
Normal file
24
scripts/memory_ocm.x
Normal file
@@ -0,0 +1,24 @@
|
||||
MEMORY
|
||||
{
|
||||
/* The Zynq7000 has 192 kB of OCM memory which can be used for the FSBL */
|
||||
CODE(rx) : ORIGIN = 0x00000000, LENGTH = 192K
|
||||
OCM_UPPER(rx): ORIGIN = 0xFFFF0000, LENGTH = 64K
|
||||
/* Leave 1 MB of memory which will be configured as uncached device memory by the MMU. This can
|
||||
be used for something like DMA descriptors, but the DDR needs to be set up first in addition
|
||||
to configuring the page at address 0x400_0000 accordingly */
|
||||
UNCACHED(rx): ORIGIN = 0x4000000, LENGTH = 1M
|
||||
}
|
||||
|
||||
REGION_ALIAS("DATA", CODE);
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
/* Uncached memory */
|
||||
.uncached (NOLOAD) : ALIGN(4) {
|
||||
. = ALIGN(4);
|
||||
_sbss_uncached = .;
|
||||
*(.uncached .uncached.*);
|
||||
. = ALIGN(4);
|
||||
_ebss_uncached = .;
|
||||
} > UNCACHED
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Exit if no arguments are provided
|
||||
if [ "$#" -eq 0 ]; then
|
||||
echo "Error: No arguments provided."
|
||||
echo "Usage: run.sh <binary>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Get the absolute path to the `scripts/` directory
|
||||
SCRIPT_DIR="$(cd -- "$(dirname -- "$0")" && pwd)"
|
||||
|
||||
# Get the absolute path to the project root
|
||||
ROOT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
|
||||
# Run the initialization script
|
||||
"$SCRIPT_DIR/zynq7000-init.py"
|
||||
|
||||
# Run the GDB debugger in GUI mode.
|
||||
gdb-multiarch -q -x gdb.gdb "$@" -tui
|
||||
@@ -1,3 +0,0 @@
|
||||
#!/bin/bash
|
||||
cargo +stable test --target $(rustc -vV | grep host | cut -d ' ' -f2) -p zynq7000-hal
|
||||
cargo +stable test --target $(rustc -vV | grep host | cut -d ' ' -f2) -p zynq7000
|
||||
144
scripts/xsct-flasher.tcl
Normal file
144
scripts/xsct-flasher.tcl
Normal file
@@ -0,0 +1,144 @@
|
||||
if {[info exists env(ip_address_hw_server)]} {
|
||||
set ip $env(ip_address_hw_server)
|
||||
} else {
|
||||
set ip "localhost"
|
||||
}
|
||||
|
||||
# Defaults
|
||||
set init_tcl ""
|
||||
set app ""
|
||||
set bitstream ""
|
||||
|
||||
# Usage helper
|
||||
proc usage {} {
|
||||
puts "Usage: xsct xsct-helper.tcl <init.tcl> \[-a|--app app.elf\] \[-b|--bit design.bit]"
|
||||
puts "Options:"
|
||||
puts " -a, --app Path to application ELF to download"
|
||||
puts " -b, --bit Path to FPGA bitstream (.bit) to program"
|
||||
puts " -h, --help Show this help"
|
||||
}
|
||||
|
||||
# Compact, robust parser
|
||||
set expecting ""
|
||||
set endopts 0
|
||||
foreach arg $argv {
|
||||
# If previous option expects a value, take this arg
|
||||
if {$expecting ne ""} {
|
||||
set $expecting $arg
|
||||
set expecting ""
|
||||
continue
|
||||
}
|
||||
|
||||
# Option handling (until we see --)
|
||||
if {!$endopts && [string match "-*" $arg]} {
|
||||
if {$arg eq "--"} { set endopts 1; continue }
|
||||
if {$arg eq "-h" || $arg eq "--help"} { usage; exit 0 }
|
||||
if {$arg eq "-a" || $arg eq "--app"} { set expecting app; continue }
|
||||
if {$arg eq "-b" || $arg eq "--bit"} { set expecting bitstream; continue }
|
||||
puts "error: unknown option: $arg"; usage; exit 1
|
||||
}
|
||||
|
||||
# Positional: expect only <init.tcl>
|
||||
if {$init_tcl eq ""} {
|
||||
set init_tcl $arg
|
||||
} else {
|
||||
puts "error: unexpected positional argument: $arg"
|
||||
usage
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
# Validate required init script
|
||||
if {$init_tcl eq ""} {
|
||||
puts "error: missing required first argument pointing to initialization TCL script"
|
||||
usage
|
||||
exit 1
|
||||
}
|
||||
if {![file exists $init_tcl]} {
|
||||
puts "error: the PS init tcl script '$init_tcl' does not exist"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Resolve app: CLI takes precedence over env(APP)
|
||||
if {$app ne ""} {
|
||||
if {![file exists $app]} {
|
||||
puts "error: the app file '$app' does not exist"
|
||||
exit 1
|
||||
}
|
||||
} elseif {[info exists env(APP)]} {
|
||||
if {[file exists $env(APP)]} {
|
||||
set app $env(APP)
|
||||
} else {
|
||||
puts "warning: APP environment variable is set but file does not exist: $env(APP)"
|
||||
}
|
||||
}
|
||||
|
||||
# Validate bitstream if provided
|
||||
if {$bitstream ne "" && ![file exists $bitstream]} {
|
||||
puts "error: the bitstream file '$bitstream' does not exist"
|
||||
exit 1
|
||||
}
|
||||
|
||||
puts "Hardware server IP address: $ip"
|
||||
connect -url tcp:$ip:3121
|
||||
|
||||
set devices [targets]
|
||||
|
||||
set apu_line [string trim [targets -nocase -filter {name =~ "APU"}]]
|
||||
set arm_core_0_line [string trim [targets -nocase -filter {name =~ "ARM Cortex-A9 MPCore #0"}]]
|
||||
set fpga_line [string trim [targets -nocase -filter {name =~ "xc7z020"}]]
|
||||
|
||||
set apu_device_num [string index $apu_line 0]
|
||||
set arm_core_0_num [string index $arm_core_0_line 0]
|
||||
set fpga_device_num [string index $fpga_line 0]
|
||||
|
||||
puts "Select ps target with number: $apu_device_num"
|
||||
|
||||
# Select the target
|
||||
target $apu_device_num
|
||||
|
||||
# Resetting the target involved problems when an image is stored on the flash.
|
||||
# It has turned out that it is not essential to reset the system before loading
|
||||
# the software components into the device.
|
||||
puts "Reset target"
|
||||
# TODO: Make the reset optional/configurable via input argument.
|
||||
# Reset the target
|
||||
rst
|
||||
|
||||
# Check if bitstream is set and the file exists before programming FPGA
|
||||
if {$bitstream eq ""} {
|
||||
puts "Skipping bitstream programming (bitstream argument not set)"
|
||||
} elseif {![file exists $bitstream]} {
|
||||
puts "Error: The bitstream file '$bitstream' does not exist"
|
||||
} else {
|
||||
puts "Set FPGA target with number: $fpga_device_num"
|
||||
target $fpga_device_num
|
||||
|
||||
# Without this delay, the FPGA programming may fail
|
||||
after 1500
|
||||
|
||||
puts "Programming FPGA with bitstream: $bitstream"
|
||||
fpga -f $bitstream
|
||||
}
|
||||
|
||||
puts "Set ps target with device number: $arm_core_0_num"
|
||||
targets $arm_core_0_num
|
||||
|
||||
puts "Initialize processing system"
|
||||
# Init processing system
|
||||
source $init_tcl
|
||||
|
||||
ps7_init
|
||||
ps7_post_config
|
||||
|
||||
puts "Set arm core 0 target with number: $arm_core_0_num"
|
||||
target $arm_core_0_num
|
||||
|
||||
if {$app ne ""} {
|
||||
puts "Download app $app to target"
|
||||
dow $app
|
||||
puts "Starting app"
|
||||
con
|
||||
}
|
||||
|
||||
puts "Success"
|
||||
@@ -1,86 +0,0 @@
|
||||
if {[info exists env(ip_address_hw_server)]} {
|
||||
set ip $env(ip_address_hw_server)
|
||||
} else {
|
||||
set ip "localhost"
|
||||
}
|
||||
|
||||
set init_tcl ""
|
||||
if {[llength $argv] >= 1} {
|
||||
set init_tcl [lindex $argv 0]
|
||||
} else {
|
||||
puts "error: missing required first argument pointing to initialization TCL script"
|
||||
exit 1
|
||||
}
|
||||
|
||||
if {![file exists $init_tcl]} {
|
||||
puts "the ps init tcl script '$init_tcl' does not exist"
|
||||
exit 0
|
||||
}
|
||||
|
||||
# parse command-line arguments
|
||||
set bitstream ""
|
||||
if {[llength $argv] >= 2} {
|
||||
set bitstream [lindex $argv 1]
|
||||
}
|
||||
|
||||
puts "Hardware server IP address: $ip"
|
||||
connect -url tcp:$ip:3121
|
||||
|
||||
set devices [targets]
|
||||
|
||||
set apu_line [string trim [targets -nocase -filter {name =~ "APU"}]]
|
||||
set arm_core_0_line [string trim [targets -nocase -filter {name =~ "ARM Cortex-A9 MPCore #0"}]]
|
||||
set fpga_line [string trim [targets -nocase -filter {name =~ "xc7z020"}]]
|
||||
|
||||
set apu_device_num [string index $apu_line 0]
|
||||
set arm_core_0_num [string index $arm_core_0_line 0]
|
||||
set fpga_device_num [string index $fpga_line 0]
|
||||
|
||||
puts "Select ps target with number: $apu_device_num"
|
||||
|
||||
# Select the target
|
||||
target $apu_device_num
|
||||
|
||||
# Resetting the target involved problems when an image is stored on the flash.
|
||||
# It has turned out that it is not essential to reset the system before loading
|
||||
# the software components into the device.
|
||||
puts "Reset target"
|
||||
# TODO: Make the reset optional/configurable via input argument.
|
||||
# Reset the target
|
||||
rst
|
||||
|
||||
# Check if bitstream is set and the file exists before programming FPGA
|
||||
if {$bitstream eq ""} {
|
||||
puts "Skipping bitstream programming (bitstream argument not set)"
|
||||
} elseif {![file exists $bitstream]} {
|
||||
puts "Error: The bitstream file '$bitstream' does not exist"
|
||||
} else {
|
||||
puts "Set FPGA target with number: $fpga_device_num"
|
||||
target $fpga_device_num
|
||||
|
||||
# Without this delay, the FPGA programming may fail
|
||||
after 1500
|
||||
|
||||
puts "Programming FPGA with bitstream: $bitstream"
|
||||
fpga -f $bitstream
|
||||
}
|
||||
|
||||
puts "Set ps target with device number: $arm_core_0_num"
|
||||
targets $arm_core_0_num
|
||||
|
||||
puts "Initialize processing system"
|
||||
# Init processing system
|
||||
source $init_tcl
|
||||
|
||||
ps7_init
|
||||
ps7_post_config
|
||||
|
||||
puts "Set arm core 0 target with number: $arm_core_0_num"
|
||||
target $arm_core_0_num
|
||||
|
||||
if {[info exists env(APP)] && [file exists $env(APP)]} {
|
||||
puts "Download app $env(APP) to target"
|
||||
dow $env(APP)
|
||||
}
|
||||
|
||||
puts "Successful"
|
||||
@@ -7,7 +7,7 @@ import sys
|
||||
from pathlib import Path
|
||||
|
||||
# Define the default values
|
||||
TCL_SCRIPT_NAME = "xsct-init.tcl"
|
||||
TCL_SCRIPT_NAME = "xsct-flasher.tcl"
|
||||
SCRIPTS_DIR = "scripts"
|
||||
DEFAULT_IP_ADDRESS_HW_SERVER = "localhost"
|
||||
|
||||
@@ -55,7 +55,7 @@ def main():
|
||||
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"
|
||||
"It is also set implicitely when specifying the SDT folder with --sdt",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-b",
|
||||
@@ -63,7 +63,7 @@ def main():
|
||||
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"
|
||||
" also searched automatically if the --sdt option is used.\n",
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
@@ -91,9 +91,6 @@ def main():
|
||||
print(f"The app '{args.app}' does not exist")
|
||||
sys.exit(1)
|
||||
|
||||
# Export environment variables
|
||||
if args.app:
|
||||
os.environ["APP"] = args.app
|
||||
os.environ["IP_ADDRESS_HW_SERVER"] = args.ip
|
||||
init_tcl = None
|
||||
bitstream = None
|
||||
@@ -124,7 +121,9 @@ def main():
|
||||
bitstream = args.bit
|
||||
init_tcl = args.init_tcl
|
||||
|
||||
xsct_script = Path(TCL_SCRIPT_NAME)
|
||||
# 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))
|
||||
@@ -136,7 +135,11 @@ def main():
|
||||
# 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)
|
||||
|
||||
Reference in New Issue
Block a user