finished QSPI flasher
Some checks failed
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
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

This commit is contained in:
2025-09-27 15:53:20 +02:00
committed by Robin Mueller
parent 8463296c3f
commit 79042a68dd
160 changed files with 2477 additions and 924 deletions

View File

@@ -1,24 +1,3 @@
[target.armv7a-none-eabihf]
runner = "./scripts/runner.sh"
rustflags = [
"-Ctarget-cpu=cortex-a9",
"-Ctarget-feature=+vfp3",
"-Ctarget-feature=+neon",
"-Clink-arg=-Tlink.x",
# If this is not enabled, debugging / stepping can become problematic.
"-Cforce-frame-pointers=yes",
# Can be useful for debugging.
# "-Clink-args=-Map=app.map"
]
# Tier 3 target, so no pre-compiled artifacts included.
[unstable]
build-std = ["core", "alloc"]
[build]
target = "armv7a-none-eabihf"
[env]
# The following two env variables need to be set for the supplied runner.sh script to work.

View File

@@ -7,41 +7,69 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: extractions/setup-just@v3
- uses: dtolnay/rust-toolchain@nightly
with:
components: rust-src
# Copy config file for rustflags and to build core/alloc.
- run: cp .cargo/def-config.toml .cargo/config.toml
- run: cargo check --target armv7a-none-eabihf -p zynq7000
- run: cargo check --target armv7a-none-eabihf -p zynq7000-rt
- run: just check zynq
- uses: dtolnay/rust-toolchain@stable
- run: just check tools
- run: just check zynq7000-boot-image
build:
name: Check build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: extractions/setup-just@v3
- uses: dtolnay/rust-toolchain@nightly
with:
components: rust-src
- run: just build zynq
- uses: dtolnay/rust-toolchain@stable
- run: just build tools
- run: just build zynq7000-boot-image
fmt:
name: Check formatting
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@nightly
- uses: extractions/setup-just@v3
- uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt
- run: cargo fmt --all -- --check
- run: just fmt zynq
- run: just fmt tools
- run: just fmt zynq7000-boot-image
docs:
name: Check Documentation Build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: extractions/setup-just@v3
- uses: dtolnay/rust-toolchain@nightly
- run: RUSTDOCFLAGS="--cfg docsrs --generate-link-to-definition -Z unstable-options" cargo +nightly doc -p zynq7000-rt --all-features
- run: RUSTDOCFLAGS="--cfg docsrs --generate-link-to-definition -Z unstable-options" cargo +nightly doc -p zynq7000 --all-features
with:
components: rust-src
- run: just docs-zynq
clippy:
name: Clippy
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: extractions/setup-just@v3
- uses: dtolnay/rust-toolchain@nightly
with:
components: clippy, rust-src
# Copy config file for rustflags and to build core/alloc.
- run: cp .cargo/def-config.toml .cargo/config.toml
- run: cargo clippy --target armv7a-none-eabihf -- -D warnings
- run: just clippy zynq
- uses: dtolnay/rust-toolchain@stable
with:
components: clippy
- run: just clippy tools
- run: just clippy zynq7000-boot-image

3
.gitignore vendored
View File

@@ -1,4 +1,5 @@
/target
target
/app.map
/xsct-output.log
/.vscode

View File

@@ -1,33 +0,0 @@
[workspace]
resolver = "3"
members = [
"zynq7000-rt",
"zynq7000",
"zynq7000-hal",
"zynq7000-embassy",
"examples/simple",
"examples/embassy",
"examples/zedboard",
"zynq-mmu",
"zedboard-fsbl",
"zedboard-bsp",
"zynq-boot-image", "zedboard-qspi-flasher",
]
exclude = [
"zynq-boot-image/tester",
]
# cargo build/run --release
[profile.release]
codegen-units = 1
debug = 2
debug-assertions = false # <-
incremental = false
lto = true
opt-level = 3 # <-
overflow-checks = false # <-
[profile.small]
inherits = "release"
opt-level = "z"

View File

@@ -6,17 +6,23 @@ family of SoCs.
# List of crates
This workspace contains the following crates:
This project contains the following crates:
## Zynq Workspace
This workspace contains libraries and application which can only be run on the target system.
- The [`zynq7000-rt`](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/zynq7000-rt)
run-time crate containing basic low-level startup code necessary to boot a Rust app on the
Zynq7000.
- The [`zynq7000`](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/zynq7000) PAC
crate containing basic low-level register definition.
crate containing basic low-level register definitions.
- The [`zynq7000-mmu`](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/zynq7000-hal)
crate containing common MMU abstractions used by both the HAL and the run-time crate.
- The [`zynq7000-hal`](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/zynq7000-hal)
HAL crate containing higher-level abstractions on top of the PAC register crate.
- The [`zynq7000-embassy`](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/zynq7000-embassy)
crate containing support for running the embassy-rs RTOS.
crate containing support for running the embassy-rs asynchronous run-time.
It also contains the following helper crates:
@@ -25,13 +31,21 @@ It also contains the following helper crates:
This folder also contains dedicated example applications using the
[`embassy`](https://github.com/embassy-rs/embassy) native Rust RTOS.
The [`zedboard-fpga-design`](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/zedboard-fpga-design)
folder contains a sample FPGA design and block design which was used in
some of the provided software examples. The project was created with Vivado version 2024.1.
## Other libraries and tools
- The [`zedboard-fpga-design`](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/zedboard-fpga-design)
folder contains a sample FPGA design and block design which was used in some of the provided software examples. The project was created with Vivado version 2024.1.
The folder contains a README with all the steps required to load this project from a TCL script.
- The [`zynq7000-boot-image`](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/zynq7000-boot-image)
library contains generic helpers to interface with the AMD
[boot binary](https://docs.amd.com/r/en-US/ug1283-bootgen-user-guide).
- The [`tools/zynq7000-ps7init-extract`](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/tools/zynq7000-ps7init-extract)
tool allows extracting configuration from the AMD generated `ps7init.tcl` file which contains
static configuration parameters for DDR initialization.
# Using the `.cargo/config.toml` file
This is mostly relevant for development directly inside this repostiory.
Use the following command to have a starting `config.toml` file
```sh

View File

@@ -1,5 +1,45 @@
all: check-all build-all clean-all fmt-all clippy-all docs-zynq
check-all: (check "zynq") (check "tools") (check "zynq7000-boot-image")
clean-all: (clean "zynq") (clean "tools") (clean "zynq7000-boot-image")
build-all: build-zynq (build "tools") (build "zynq7000-boot-image")
fmt-all: (fmt "zynq") (fmt "tools") (fmt "zynq7000-boot-image")
clippy-all: (clippy "zynq") (clippy "tools") (clippy "zynq7000-boot-image")
check target:
cd {{target}} && cargo check
build target:
cd {{target}} && cargo build
build-zynq: (build "zynq")
cd "zynq/zedboard-fsbl" && cargo build --release
clean target:
cd {{target}} && cargo clean
fmt target:
cd {{target}} && cargo +stable fmt --all -- --check
clippy target:
cd {{target}} && cargo clippy -- -D warnings
[working-directory: 'zynq']
docs-zynq:
RUSTDOCFLAGS="--cfg docsrs --generate-link-to-definition -Z unstable-options" cargo +nightly doc -p zynq7000
RUSTDOCFLAGS="--cfg docsrs --generate-link-to-definition -Z unstable-options" cargo +nightly doc -p zynq7000-hal --features alloc
RUSTDOCFLAGS="--cfg docsrs --generate-link-to-definition -Z unstable-options" cargo +nightly doc -p zynq7000-mmu
RUSTDOCFLAGS="--cfg docsrs --generate-link-to-definition -Z unstable-options" cargo +nightly doc -p zynq7000-rt
[working-directory: 'zynq-boot-image/staging']
bootgen:
bootgen -arch zynq -image boot.bif -o boot.bin -w on
echo "Generated boot.bin at zynq-boot-image/staging"
[no-cd]
run binary:
# Run the initialization script. It needs to be run inside the justfile directory.
python3 {{justfile_directory()}}/scripts/zynq7000-init.py
# Run the GDB debugger in GUI mode.
gdb-multiarch -q -x {{justfile_directory()}}/zynq/gdb.gdb {{binary}} -tui

View File

@@ -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

View File

@@ -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

View File

@@ -121,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))

796
tools/Cargo.lock generated Normal file
View File

@@ -0,0 +1,796 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "aho-corasick"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
dependencies = [
"memchr",
]
[[package]]
name = "anstream"
version = "0.6.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a"
dependencies = [
"anstyle",
"anstyle-parse",
"anstyle-query",
"anstyle-wincon",
"colorchoice",
"is_terminal_polyfill",
"utf8parse",
]
[[package]]
name = "anstyle"
version = "1.0.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78"
[[package]]
name = "anstyle-parse"
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2"
dependencies = [
"utf8parse",
]
[[package]]
name = "anstyle-query"
version = "1.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e231f6134f61b71076a3eab506c379d4f36122f2af15a9ff04415ea4c3339e2"
dependencies = [
"windows-sys 0.60.2",
]
[[package]]
name = "anstyle-wincon"
version = "3.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e0633414522a32ffaac8ac6cc8f748e090c5717661fddeea04219e2344f5f2a"
dependencies = [
"anstyle",
"once_cell_polyfill",
"windows-sys 0.60.2",
]
[[package]]
name = "arbitrary-int"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "825297538d77367557b912770ca3083f778a196054b3ee63b22673c4a3cae0a5"
[[package]]
name = "arbitrary-int"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c858caffa49edfc4ecc45a4bec37abd3e88041a2903816f10f990b7b41abc281"
[[package]]
name = "arm-targets"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3371884971a96d71d8bd4e781188a7d327d7e5e455d07ef4c352922c66695e9e"
[[package]]
name = "bitbybit"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec187a89ab07e209270175faf9e07ceb2755d984954e58a2296e325ddece2762"
dependencies = [
"arbitrary-int 1.3.0",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "boot-image-test"
version = "0.1.0"
dependencies = [
"clap",
"zynq7000-boot-image",
]
[[package]]
name = "clap"
version = "4.5.48"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2134bb3ea021b78629caa971416385309e0131b351b25e01dc16fb54e1b5fae"
dependencies = [
"clap_builder",
"clap_derive",
]
[[package]]
name = "clap_builder"
version = "4.5.48"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2ba64afa3c0a6df7fa517765e31314e983f51dda798ffba27b988194fb65dc9"
dependencies = [
"anstream",
"anstyle",
"clap_lex",
"strsim",
]
[[package]]
name = "clap_derive"
version = "4.5.47"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbfd7eae0b0f1a6e63d4b13c9c478de77c2eb546fba158ad50b4203dc24b9f9c"
dependencies = [
"heck",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "clap_lex"
version = "0.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675"
[[package]]
name = "colorchoice"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
[[package]]
name = "colored"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c"
dependencies = [
"lazy_static",
"windows-sys 0.59.0",
]
[[package]]
name = "cortex-ar"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4ea2a354642e242870bc43b57a517359b0be6e96d302b2811cd0644c979c54e"
dependencies = [
"arbitrary-int 2.0.0",
"arm-targets",
"bitbybit",
"num_enum",
"thiserror",
]
[[package]]
name = "critical-section"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b"
[[package]]
name = "deranged"
version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a41953f86f8a05768a6cda24def994fd2f424b04ec5c719cf89989779f199071"
dependencies = [
"powerfmt",
]
[[package]]
name = "derive-mmio"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "005a6dabf68a87a460d3cb9b8e2fd5de3f474fc34e8d9451f5a1b6db518da143"
dependencies = [
"derive-mmio-macro",
"rustversion",
]
[[package]]
name = "derive-mmio-macro"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "584dc8e12e4aeb88000c2be8ef7db15657c817fba3e77999a24807d1efcdeefa"
dependencies = [
"proc-macro-error2",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "heck"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]]
name = "is_terminal_polyfill"
version = "1.70.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
[[package]]
name = "itoa"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
[[package]]
name = "lazy_static"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]]
name = "libc"
version = "0.2.176"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "58f929b4d672ea937a23a1ab494143d968337a5f47e56d0815df1e0890ddf174"
[[package]]
name = "log"
version = "0.4.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432"
[[package]]
name = "memchr"
version = "2.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273"
[[package]]
name = "mmu-table-gen"
version = "0.1.0"
dependencies = [
"zynq7000-mmu",
"zynq7000-rt",
]
[[package]]
name = "num-conv"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
[[package]]
name = "num_enum"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a973b4e44ce6cad84ce69d797acf9a044532e4184c4f267913d1b546a0727b7a"
dependencies = [
"num_enum_derive",
"rustversion",
]
[[package]]
name = "num_enum_derive"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77e878c846a8abae00dd069496dbe8751b16ac1c3d6bd2a7283a938e8228f90d"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "num_threads"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9"
dependencies = [
"libc",
]
[[package]]
name = "once_cell"
version = "1.21.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
dependencies = [
"critical-section",
"portable-atomic",
]
[[package]]
name = "once_cell_polyfill"
version = "1.70.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad"
[[package]]
name = "portable-atomic"
version = "1.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483"
[[package]]
name = "powerfmt"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
[[package]]
name = "proc-macro-error-attr2"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5"
dependencies = [
"proc-macro2",
"quote",
]
[[package]]
name = "proc-macro-error2"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802"
dependencies = [
"proc-macro-error-attr2",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "proc-macro2"
version = "1.0.101"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.41"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1"
dependencies = [
"proc-macro2",
]
[[package]]
name = "regex"
version = "1.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b5288124840bee7b386bc413c487869b360b2b4ec421ea56425128692f2a82c"
dependencies = [
"aho-corasick",
"memchr",
"regex-automata",
"regex-syntax",
]
[[package]]
name = "regex-automata"
version = "0.4.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "833eb9ce86d40ef33cb1306d8accf7bc8ec2bfea4355cbdebb3df68b40925cad"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001"
[[package]]
name = "rustversion"
version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
[[package]]
name = "serde"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
dependencies = [
"serde_core",
]
[[package]]
name = "serde_core"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "simple_logger"
version = "5.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8c5dfa5e08767553704aa0ffd9d9794d527103c736aba9854773851fd7497eb"
dependencies = [
"colored",
"log",
"time",
"windows-sys 0.48.0",
]
[[package]]
name = "static_assertions"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "strsim"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]]
name = "syn"
version = "2.0.106"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "thiserror"
version = "2.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "2.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "time"
version = "0.3.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d"
dependencies = [
"deranged",
"itoa",
"libc",
"num-conv",
"num_threads",
"powerfmt",
"serde",
"time-core",
"time-macros",
]
[[package]]
name = "time-core"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b"
[[package]]
name = "time-macros"
version = "0.2.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "30cfb0125f12d9c277f35663a0a33f8c30190f4e4574868a330595412d34ebf3"
dependencies = [
"num-conv",
"time-core",
]
[[package]]
name = "unicode-ident"
version = "1.0.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d"
[[package]]
name = "utf8parse"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]]
name = "windows-link"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
[[package]]
name = "windows-sys"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
dependencies = [
"windows-targets 0.48.5",
]
[[package]]
name = "windows-sys"
version = "0.59.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
dependencies = [
"windows-targets 0.52.6",
]
[[package]]
name = "windows-sys"
version = "0.60.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb"
dependencies = [
"windows-targets 0.53.5",
]
[[package]]
name = "windows-targets"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
dependencies = [
"windows_aarch64_gnullvm 0.48.5",
"windows_aarch64_msvc 0.48.5",
"windows_i686_gnu 0.48.5",
"windows_i686_msvc 0.48.5",
"windows_x86_64_gnu 0.48.5",
"windows_x86_64_gnullvm 0.48.5",
"windows_x86_64_msvc 0.48.5",
]
[[package]]
name = "windows-targets"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
dependencies = [
"windows_aarch64_gnullvm 0.52.6",
"windows_aarch64_msvc 0.52.6",
"windows_i686_gnu 0.52.6",
"windows_i686_gnullvm 0.52.6",
"windows_i686_msvc 0.52.6",
"windows_x86_64_gnu 0.52.6",
"windows_x86_64_gnullvm 0.52.6",
"windows_x86_64_msvc 0.52.6",
]
[[package]]
name = "windows-targets"
version = "0.53.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3"
dependencies = [
"windows-link",
"windows_aarch64_gnullvm 0.53.1",
"windows_aarch64_msvc 0.53.1",
"windows_i686_gnu 0.53.1",
"windows_i686_gnullvm 0.53.1",
"windows_i686_msvc 0.53.1",
"windows_x86_64_gnu 0.53.1",
"windows_x86_64_gnullvm 0.53.1",
"windows_x86_64_msvc 0.53.1",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53"
[[package]]
name = "windows_aarch64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
name = "windows_aarch64_msvc"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006"
[[package]]
name = "windows_i686_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
[[package]]
name = "windows_i686_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
[[package]]
name = "windows_i686_gnu"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3"
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]]
name = "windows_i686_gnullvm"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c"
[[package]]
name = "windows_i686_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
[[package]]
name = "windows_i686_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
name = "windows_i686_msvc"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2"
[[package]]
name = "windows_x86_64_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]]
name = "windows_x86_64_gnu"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1"
[[package]]
name = "windows_x86_64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]]
name = "windows_x86_64_msvc"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650"
[[package]]
name = "zynq7000"
version = "0.1.0"
dependencies = [
"arbitrary-int 2.0.0",
"bitbybit",
"derive-mmio",
"once_cell",
"rustversion",
"static_assertions",
"thiserror",
]
[[package]]
name = "zynq7000-boot-image"
version = "0.1.0"
dependencies = [
"arbitrary-int 2.0.0",
"bitbybit",
"thiserror",
]
[[package]]
name = "zynq7000-mmu"
version = "0.1.0"
dependencies = [
"cortex-ar",
"thiserror",
]
[[package]]
name = "zynq7000-ps7init-extract"
version = "0.1.0"
dependencies = [
"clap",
"log",
"proc-macro2",
"quote",
"regex",
"simple_logger",
"syn",
"zynq7000",
]
[[package]]
name = "zynq7000-rt"
version = "0.1.0"
dependencies = [
"arbitrary-int 2.0.0",
"cortex-ar",
"zynq7000-mmu",
]

7
tools/Cargo.toml Normal file
View File

@@ -0,0 +1,7 @@
[workspace]
resolver = "3"
members = [
"boot-image-test",
"mmu-table-gen",
"zynq7000-ps7init-extract",
]

View File

@@ -1,10 +1,8 @@
[workspace]
[package]
name = "tester"
name = "boot-image-test"
version = "0.1.0"
edition = "2024"
[dependencies]
zynq-boot-image= { path = ".." }
zynq7000-boot-image= { path = "../../zynq7000-boot-image" }
clap = { version = "4", features = ["derive"] }

View File

@@ -2,7 +2,7 @@
use std::{io::Read, path::Path};
use clap::Parser as _;
use zynq_boot_image::{BootHeader, FIXED_BOOT_HEADER_SIZE};
use zynq7000_boot_image::{BootHeader, FIXED_BOOT_HEADER_SIZE};
#[derive(clap::Parser, Debug)]
#[command(version, about)]

View File

@@ -0,0 +1,8 @@
[package]
name = "mmu-table-gen"
version = "0.1.0"
edition = "2024"
[dependencies]
zynq7000-rt = { path = "../../zynq/zynq7000-rt", default-features = false }
zynq7000-mmu = { path = "../../zynq/zynq7000-mmu", features = ["tools"] }

View File

@@ -16,7 +16,7 @@ macro_rules! write_l1_section {
}
fn main() {
let file_path = "src/mmu_table.rs";
let file_path = "mmu_table.rs";
let file = File::create(file_path).expect("Failed to create file");
let mut offset = 0;
@@ -56,7 +56,7 @@ fn main() {
writeln!(buf_writer, "use crate::mmu::section_attrs;").unwrap();
writeln!(buf_writer, "use cortex_ar::mmu::L1Section;").unwrap();
writeln!(buf_writer, "use zynq_mmu::L1Table;").unwrap();
writeln!(buf_writer, "use zynq7000_mmu::L1Table;").unwrap();
writeln!(buf_writer, "").unwrap();
writeln!(buf_writer, "/// MMU Level 1 Page table.").unwrap();

View File

@@ -0,0 +1,2 @@
/ddrc_config_autogen.rs
/ddriob_config_autogen.rs

251
tools/zynq7000-ps7init-extract/Cargo.lock generated Normal file
View File

@@ -0,0 +1,251 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "anstream"
version = "0.6.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a"
dependencies = [
"anstyle",
"anstyle-parse",
"anstyle-query",
"anstyle-wincon",
"colorchoice",
"is_terminal_polyfill",
"utf8parse",
]
[[package]]
name = "anstyle"
version = "1.0.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78"
[[package]]
name = "anstyle-parse"
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2"
dependencies = [
"utf8parse",
]
[[package]]
name = "anstyle-query"
version = "1.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e231f6134f61b71076a3eab506c379d4f36122f2af15a9ff04415ea4c3339e2"
dependencies = [
"windows-sys",
]
[[package]]
name = "anstyle-wincon"
version = "3.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e0633414522a32ffaac8ac6cc8f748e090c5717661fddeea04219e2344f5f2a"
dependencies = [
"anstyle",
"once_cell_polyfill",
"windows-sys",
]
[[package]]
name = "clap"
version = "4.5.48"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2134bb3ea021b78629caa971416385309e0131b351b25e01dc16fb54e1b5fae"
dependencies = [
"clap_builder",
"clap_derive",
]
[[package]]
name = "clap_builder"
version = "4.5.48"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2ba64afa3c0a6df7fa517765e31314e983f51dda798ffba27b988194fb65dc9"
dependencies = [
"anstream",
"anstyle",
"clap_lex",
"strsim",
]
[[package]]
name = "clap_derive"
version = "4.5.47"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbfd7eae0b0f1a6e63d4b13c9c478de77c2eb546fba158ad50b4203dc24b9f9c"
dependencies = [
"heck",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "clap_lex"
version = "0.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675"
[[package]]
name = "colorchoice"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
[[package]]
name = "heck"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]]
name = "is_terminal_polyfill"
version = "1.70.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
[[package]]
name = "once_cell_polyfill"
version = "1.70.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad"
[[package]]
name = "proc-macro2"
version = "1.0.101"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.41"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1"
dependencies = [
"proc-macro2",
]
[[package]]
name = "strsim"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]]
name = "syn"
version = "2.0.106"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "unicode-ident"
version = "1.0.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d"
[[package]]
name = "utf8parse"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]]
name = "windows-link"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
[[package]]
name = "windows-sys"
version = "0.60.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.53.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3"
dependencies = [
"windows-link",
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_gnullvm",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53"
[[package]]
name = "windows_aarch64_msvc"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006"
[[package]]
name = "windows_i686_gnu"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3"
[[package]]
name = "windows_i686_gnullvm"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c"
[[package]]
name = "windows_i686_msvc"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2"
[[package]]
name = "windows_x86_64_gnu"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1"
[[package]]
name = "windows_x86_64_msvc"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650"
[[package]]
name = "zynq7000-ps7init-extract"
version = "0.1.0"
dependencies = [
"clap",
]

View File

@@ -0,0 +1,14 @@
[package]
name = "zynq7000-ps7init-extract"
version = "0.1.0"
edition = "2024"
[dependencies]
clap = { version = "4", features = ["derive"] }
zynq7000 = { path = "../../zynq/zynq7000" }
log = "0.4"
simple_logger = "5"
regex = "1"
quote = "1"
syn = "2"
proc-macro2 = "1"

View File

@@ -0,0 +1,26 @@
Zynq7000 PS7 Init Extractor
=========
AMD provides tooling to auto-generate some of the hardware initialization for the external DDR
as native Rust code.
The AMD tooling generates these files as `ps7init.tcl`, `ps7init.c`, `ps7init.h` files but not as
Rust files. The specific parameters required for different DDR chips are proprietary, so that
portion is required for Rust programs as well. Do avoid the need of compiling the PS7 initialization
scripts with a C compiler, this tool extracts all required configuration parameters for DDR and
DDRIOB initialization and configuration and exports them as native Rust constants.
The generates files can be placed in individual projects or board support packages to initialize
the DDR in conjunction with the [Zynq7000 HAL library](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/fsbl-rs/zynq/zynq7000-hal).
Right now, the script expects the `ps7init.tcl` file to be passed as a command line argument
for `-p` or `--path`. It then generates the configuration as a `ddrc_config_autogen.rs` and
`ddrc_config_autogen.rs` file.
For example, assuming that there is a `ps7init.tcl` script in the current directory, you can use
```sh
cargo run -- --path ./ps7init.tcl
```
to generate the configuration files.

View File

@@ -0,0 +1,341 @@
use std::{collections::HashMap, ops::RangeInclusive, path::Path};
use clap::Parser as _;
use simple_logger::SimpleLogger;
const DDRC_ADDR_RANGE: RangeInclusive<u32> = 0xf800_6000..=0xf800_62b4;
const DDRIOB_ADDR_RANGE: RangeInclusive<u32> = 0xf800_0b40..=0xf800_0b68;
const DDRC_FILE_NAME: &str = "ddrc_config_autogen.rs";
const DDRIOB_FILE_NAME: &str = "ddriob_config_autogen.rs";
#[derive(clap::Parser, Debug)]
#[command(version, about)]
pub struct Cli {
/// Path to ps7init.tcl file.
#[arg(short, long)]
path: String,
}
fn extract_hex_values(line: &str) -> Option<(u32, u32, u32)> {
let re = regex::Regex::new(r"0[xX]([0-9A-Fa-f]+)").unwrap();
let captures: Vec<u32> = re
.captures_iter(line)
.filter_map(|cap| u32::from_str_radix(&cap[1], 16).ok())
.collect();
if captures.len() == 3 {
Some((captures[0], captures[1], captures[2]))
} else {
None
}
}
#[derive(Default)]
pub struct RegisterToValueMap(pub HashMap<u32, u32>);
impl RegisterToValueMap {
fn val_as_token(&self, reg_name: &str, addr: u32) -> proc_macro2::TokenStream {
let val = self.0.get(&addr).unwrap_or_else(|| {
panic!(
"failed to retrieve register value for register {}",
reg_name
)
});
format!("{:#010x}", val)
.parse::<proc_macro2::TokenStream>()
.unwrap()
}
}
enum ParsingMode {
DdrRev3,
MioRev3,
}
fn main() -> std::io::Result<()> {
SimpleLogger::new().init().unwrap();
let cli = Cli::parse();
let ps7init_tcl = Path::new(&cli.path);
if !ps7init_tcl.exists() {
log::error!("File not found: {}", ps7init_tcl.display());
std::process::exit(1);
}
let mut parsing_mode = None;
let mut reg_to_values = RegisterToValueMap::default();
for line in std::fs::read_to_string(ps7init_tcl)?.lines() {
match parsing_mode {
None => {
if line.contains("ps7_ddr_init_data_3_0") {
parsing_mode = Some(ParsingMode::DdrRev3);
} else if line.contains("ps7_mio_init_data_3_0") {
parsing_mode = Some(ParsingMode::MioRev3);
}
continue;
}
Some(ParsingMode::MioRev3) => {
if line.contains("}") {
parsing_mode = None;
continue;
}
}
Some(ParsingMode::DdrRev3) => {
if line.contains("}") {
parsing_mode = None;
continue;
}
}
}
if let Some((addr, _mask, value)) = extract_hex_values(line)
&& (DDRC_ADDR_RANGE.contains(&addr) || DDRIOB_ADDR_RANGE.contains(&addr))
&& addr % 4 == 0
{
// Only use first value.
if reg_to_values.0.contains_key(&addr) {
if addr != 0xF800_6000 {
log::warn!("detected duplicate register value for address {}", addr);
}
continue;
}
reg_to_values.0.insert(addr, value);
}
}
log::info!("generating DDRC config files: {}", DDRC_FILE_NAME);
generate_ddrc_config(&reg_to_values, DDRC_FILE_NAME)?;
log::info!("generating DDRIOB config files: {}", DDRIOB_FILE_NAME);
generate_ddriob_config(&reg_to_values, DDRIOB_FILE_NAME)?;
Ok(())
}
fn generate_ddrc_config(
reg_to_values: &RegisterToValueMap,
file_name: &str,
) -> std::io::Result<()> {
// Format as hex strings
let ddrc = reg_to_values.val_as_token("DDRC Control", 0xF800_6000);
let two_rank = reg_to_values.val_as_token("Two Rank", 0xF800_6004);
let hpr = reg_to_values.val_as_token("HPR", 0xF800_6008);
let lpr = reg_to_values.val_as_token("LPR", 0xF800_600C);
let wr = reg_to_values.val_as_token("WR", 0xF800_6010);
let dram_param_0 = reg_to_values.val_as_token("DRAM Reg0", 0xF800_6014);
let dram_param_1 = reg_to_values.val_as_token("DRAM Reg1", 0xF800_6018);
let dram_param_2 = reg_to_values.val_as_token("DRAM Reg2", 0xF800_601C);
let dram_param_3 = reg_to_values.val_as_token("DRAM Reg3", 0xF800_6020);
let dram_param_4 = reg_to_values.val_as_token("DRAM Reg4", 0xF800_6024);
let dram_init_param = reg_to_values.val_as_token("DRAM Init Param", 0xF800_6028);
let dram_emr = reg_to_values.val_as_token("DRAM EMR", 0xF800_602C);
let dram_emr_mr = reg_to_values.val_as_token("DRAM EMR MR", 0xF800_6030);
let dram_burst8_rdwr = reg_to_values.val_as_token("DRAM Burst8 RDWR", 0xF800_6034);
let dram_disable_dq = reg_to_values.val_as_token("DRAM Disable DQ", 0xF800_6038);
let dram_addr_map_bank = reg_to_values.val_as_token("DRAM Addr Map Bank", 0xF800_603C);
let dram_addr_map_col = reg_to_values.val_as_token("DRAM Addr Map Col", 0xF800_6040);
let dram_addr_map_row = reg_to_values.val_as_token("DRAM Addr Map Row", 0xF800_6044);
let dram_odt = reg_to_values.val_as_token("DRAM ODT", 0xF800_6048);
let phy_cmd_timeout_rddata_cpt = reg_to_values.val_as_token("PHY CMD Timeout", 0xF800_6050);
let dll_calib = reg_to_values.val_as_token("DLL Calib", 0xF800_6058);
let odt_delay_hold = reg_to_values.val_as_token("ODT Delay Hold", 0xF800_605C);
let ctrl_reg1 = reg_to_values.val_as_token("CTRL Reg 1", 0xF800_6060);
let ctrl_reg2 = reg_to_values.val_as_token("CTRL Reg 2", 0xF800_6064);
let ctrl_reg3 = reg_to_values.val_as_token("CTRL Reg 3", 0xF800_6068);
let ctrl_reg4 = reg_to_values.val_as_token("CTRL Reg 4", 0xF800_606C);
let ctrl_reg5 = reg_to_values.val_as_token("CTRL Reg 5", 0xF800_6078);
let ctrl_reg6 = reg_to_values.val_as_token("CTRL Reg 6", 0xF800_607C);
let che_t_zq = reg_to_values.val_as_token("CHE T ZQ", 0xF800_60A4);
let che_t_zq_short_interval_reg =
reg_to_values.val_as_token("CHE T ZQ Short Interval", 0xF800_60A4);
let deep_powerdown = reg_to_values.val_as_token("Deep Powerdown", 0xF800_60AC);
let reg_2c = reg_to_values.val_as_token("Reg 2C", 0xF800_60B0);
let reg_2d = reg_to_values.val_as_token("Reg 2D", 0xF800_60B4);
let dfi_timing = reg_to_values.val_as_token("DFI Timing", 0xF800_60B8);
let che_ecc_ctrl = reg_to_values.val_as_token("CHE ECC CTRL", 0xF800_60C4);
let ecc_scrub = reg_to_values.val_as_token("ECC Scrub", 0xF800_60F4);
let phy_receiver_enable = reg_to_values.val_as_token("PHY Receiver Enable", 0xF800_6114);
let phy_config_0 = reg_to_values.val_as_token("PHY Config 0", 0xF800_6118);
let phy_config_1 = reg_to_values.val_as_token("PHY Config 1", 0xF800_611C);
let phy_config_2 = reg_to_values.val_as_token("PHY Config 2", 0xF800_6120);
let phy_config_3 = reg_to_values.val_as_token("PHY Config 3", 0xF800_6124);
let phy_init_ratio_0 = reg_to_values.val_as_token("PHY Init Ratio 0", 0xF800_612C);
let phy_init_ratio_1 = reg_to_values.val_as_token("PHY Init Ratio 1", 0xF800_6130);
let phy_init_ratio_2 = reg_to_values.val_as_token("PHY Init Ratio 2", 0xF800_6134);
let phy_init_ratio_3 = reg_to_values.val_as_token("PHY Init Ratio 3", 0xF800_6138);
let phy_rd_dqs_config_0 = reg_to_values.val_as_token("PHY RD DQS Config 0", 0xF800_6140);
let phy_rd_dqs_config_1 = reg_to_values.val_as_token("PHY RD DQS Config 1", 0xF800_6144);
let phy_rd_dqs_config_2 = reg_to_values.val_as_token("PHY RD DQS Config 2", 0xF800_6148);
let phy_rd_dqs_config_3 = reg_to_values.val_as_token("PHY RD DQS Config 3", 0xF800_614C);
let phy_wr_dqs_config_0 = reg_to_values.val_as_token("PHY WR DQS Config 0", 0xF800_6154);
let phy_wr_dqs_config_1 = reg_to_values.val_as_token("PHY WR DQS Config 1", 0xF800_6158);
let phy_wr_dqs_config_2 = reg_to_values.val_as_token("PHY WR DQS Config 2", 0xF800_615C);
let phy_wr_dqs_config_3 = reg_to_values.val_as_token("PHY WR DQS Config 3", 0xF800_6160);
let phy_we_cfg_0 = reg_to_values.val_as_token("PHY WE Config 0", 0xF800_6168);
let phy_we_cfg_1 = reg_to_values.val_as_token("PHY WE Config 1", 0xF800_616C);
let phy_we_cfg_2 = reg_to_values.val_as_token("PHY WE Config 2", 0xF800_6170);
let phy_we_cfg_3 = reg_to_values.val_as_token("PHY WE Config 3", 0xF800_6174);
let phy_wr_data_slv_0 = reg_to_values.val_as_token("PHY WR Data Slv 0", 0xF800_617C);
let phy_wr_data_slv_1 = reg_to_values.val_as_token("PHY WR Data Slv 1", 0xF800_6180);
let phy_wr_data_slv_2 = reg_to_values.val_as_token("PHY WR Data Slv 2", 0xF800_6184);
let phy_wr_data_slv_3 = reg_to_values.val_as_token("PHY WR Data Slv 3", 0xF800_6188);
let reg64 = reg_to_values.val_as_token("Reg64", 0xF800_6190);
let reg65 = reg_to_values.val_as_token("Reg65", 0xF800_6194);
let page_mask = reg_to_values.val_as_token("Page Mask", 0xF800_6204);
let axi_priority_wr_port_0 = reg_to_values.val_as_token("AXI Priority WR Port 0", 0xF800_6208);
let axi_priority_wr_port_1 = reg_to_values.val_as_token("AXI Priority WR Port 1", 0xF800_620C);
let axi_priority_wr_port_2 = reg_to_values.val_as_token("AXI Priority WR Port 2", 0xF800_6210);
let axi_priority_wr_port_3 = reg_to_values.val_as_token("AXI Priority WR Port 3", 0xF800_6214);
let axi_priority_rd_port_0 = reg_to_values.val_as_token("AXI Priority RD Port 0", 0xF800_6218);
let axi_priority_rd_port_1 = reg_to_values.val_as_token("AXI Priority RD Port 1", 0xF800_621C);
let axi_priority_rd_port_2 = reg_to_values.val_as_token("AXI Priority RD Port 2", 0xF800_6220);
let axi_priority_rd_port_3 = reg_to_values.val_as_token("AXI Priority RD Port 3", 0xF800_6224);
let lpddr_ctrl_0 = reg_to_values.val_as_token("LPDDR CTRL 0", 0xF800_62A8);
let lpddr_ctrl_1 = reg_to_values.val_as_token("LPDDR CTRL 1", 0xF800_62AC);
let lpddr_ctrl_2 = reg_to_values.val_as_token("LPDDR CTRL 2", 0xF800_62B0);
let lpddr_ctrl_3 = reg_to_values.val_as_token("LPDDR CTRL 3", 0xF800_62B4);
let generated = quote::quote! {
//!This file was auto-generated by the [zynq7000-ps7init-extract](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/tools/zynq7000-ps7init-extract) program.
//!
//!This configuration file contains static DDR configuration parameters extracted from the
//!AMD ps7init.tcl file
use zynq7000::ddrc::regs;
use zynq7000_hal::ddr::DdrcConfigSet;
pub const DDRC_CONFIG_ZEDBOARD: DdrcConfigSet = DdrcConfigSet {
ctrl: regs::DdrcControl::new_with_raw_value(#ddrc),
two_rank: regs::TwoRankConfig::new_with_raw_value(#two_rank),
hpr: regs::LprHprQueueControl::new_with_raw_value(#hpr),
lpr: regs::LprHprQueueControl::new_with_raw_value(#lpr),
wr: regs::WriteQueueControl::new_with_raw_value(#wr),
dram_param_0: regs::DramParamReg0::new_with_raw_value(#dram_param_0),
dram_param_1: regs::DramParamReg1::new_with_raw_value(#dram_param_1),
dram_param_2: regs::DramParamReg2::new_with_raw_value(#dram_param_2),
dram_param_3: regs::DramParamReg3::new_with_raw_value(#dram_param_3),
dram_param_4: regs::DramParamReg4::new_with_raw_value(#dram_param_4),
dram_init_param: regs::DramInitParam::new_with_raw_value(#dram_init_param),
dram_emr: regs::DramEmr::new_with_raw_value(#dram_emr),
dram_emr_mr: regs::DramEmrMr::new_with_raw_value(#dram_emr_mr),
dram_burst8_rdwr: regs::DramBurst8ReadWrite::new_with_raw_value(#dram_burst8_rdwr),
disable_dq: regs::DisableDq::new_with_raw_value(#dram_disable_dq),
dram_addr_map_bank: regs::DramAddrMapBank::new_with_raw_value(#dram_addr_map_bank),
dram_addr_map_col: regs::DramAddrMapColumn::new_with_raw_value(#dram_addr_map_col),
dram_addr_map_row: regs::DramAddrMapRow::new_with_raw_value(#dram_addr_map_row),
dram_odt: regs::DramOdt::new_with_raw_value(#dram_odt),
phy_cmd_timeout_rddata_cpt: regs::PhyCmdTimeoutRdDataCpt::new_with_raw_value(#phy_cmd_timeout_rddata_cpt),
dll_calib: regs::DllCalib::new_with_raw_value(#dll_calib),
odt_delay_hold: regs::OdtDelayHold::new_with_raw_value(#odt_delay_hold),
ctrl_reg1: regs::CtrlReg1::new_with_raw_value(#ctrl_reg1),
ctrl_reg2: regs::CtrlReg2::new_with_raw_value(#ctrl_reg2),
ctrl_reg3: regs::CtrlReg3::new_with_raw_value(#ctrl_reg3),
ctrl_reg4: regs::CtrlReg4::new_with_raw_value(#ctrl_reg4),
ctrl_reg5: regs::CtrlReg5::new_with_raw_value(#ctrl_reg5),
ctrl_reg6: regs::CtrlReg6::new_with_raw_value(#ctrl_reg6),
che_t_zq: regs::CheTZq::new_with_raw_value(#che_t_zq),
che_t_zq_short_interval_reg: regs::CheTZqShortInterval::new_with_raw_value(#che_t_zq_short_interval_reg),
deep_powerdown: regs::DeepPowerdown::new_with_raw_value(#deep_powerdown),
reg_2c: regs::Reg2c::new_with_raw_value(#reg_2c),
reg_2d: regs::Reg2d::new_with_raw_value(#reg_2d),
dfi_timing: regs::DfiTiming::new_with_raw_value(#dfi_timing),
che_ecc_ctrl: regs::CheEccControl::new_with_raw_value(#che_ecc_ctrl),
ecc_scrub: regs::EccScrub::new_with_raw_value(#ecc_scrub),
phy_receiver_enable: regs::PhyReceiverEnable::new_with_raw_value(#phy_receiver_enable),
phy_config: [
regs::PhyConfig::new_with_raw_value(#phy_config_0),
regs::PhyConfig::new_with_raw_value(#phy_config_1),
regs::PhyConfig::new_with_raw_value(#phy_config_2),
regs::PhyConfig::new_with_raw_value(#phy_config_3),
],
phy_init_ratio: [
regs::PhyInitRatio::new_with_raw_value(#phy_init_ratio_0),
regs::PhyInitRatio::new_with_raw_value(#phy_init_ratio_1),
regs::PhyInitRatio::new_with_raw_value(#phy_init_ratio_2),
regs::PhyInitRatio::new_with_raw_value(#phy_init_ratio_3),
],
phy_rd_dqs_config: [
regs::PhyDqsConfig::new_with_raw_value(#phy_rd_dqs_config_0),
regs::PhyDqsConfig::new_with_raw_value(#phy_rd_dqs_config_1),
regs::PhyDqsConfig::new_with_raw_value(#phy_rd_dqs_config_2),
regs::PhyDqsConfig::new_with_raw_value(#phy_rd_dqs_config_3),
],
phy_wr_dqs_config: [
regs::PhyDqsConfig::new_with_raw_value(#phy_wr_dqs_config_0),
regs::PhyDqsConfig::new_with_raw_value(#phy_wr_dqs_config_1),
regs::PhyDqsConfig::new_with_raw_value(#phy_wr_dqs_config_2),
regs::PhyDqsConfig::new_with_raw_value(#phy_wr_dqs_config_3),
],
phy_we_cfg: [
regs::PhyWriteEnableConfig::new_with_raw_value(#phy_we_cfg_0),
regs::PhyWriteEnableConfig::new_with_raw_value(#phy_we_cfg_1),
regs::PhyWriteEnableConfig::new_with_raw_value(#phy_we_cfg_2),
regs::PhyWriteEnableConfig::new_with_raw_value(#phy_we_cfg_3),
],
phy_wr_data_slv: [
regs::PhyWriteDataSlaveConfig::new_with_raw_value(#phy_wr_data_slv_0),
regs::PhyWriteDataSlaveConfig::new_with_raw_value(#phy_wr_data_slv_1),
regs::PhyWriteDataSlaveConfig::new_with_raw_value(#phy_wr_data_slv_2),
regs::PhyWriteDataSlaveConfig::new_with_raw_value(#phy_wr_data_slv_3),
],
reg64: regs::Reg64::new_with_raw_value(#reg64),
reg65: regs::Reg65::new_with_raw_value(#reg65),
page_mask: #page_mask,
axi_priority_wr_port: [
regs::AxiPriorityWritePort::new_with_raw_value(#axi_priority_wr_port_0),
regs::AxiPriorityWritePort::new_with_raw_value(#axi_priority_wr_port_1),
regs::AxiPriorityWritePort::new_with_raw_value(#axi_priority_wr_port_2),
regs::AxiPriorityWritePort::new_with_raw_value(#axi_priority_wr_port_3),
],
axi_priority_rd_port: [
regs::AxiPriorityReadPort::new_with_raw_value(#axi_priority_rd_port_0),
regs::AxiPriorityReadPort::new_with_raw_value(#axi_priority_rd_port_1),
regs::AxiPriorityReadPort::new_with_raw_value(#axi_priority_rd_port_2),
regs::AxiPriorityReadPort::new_with_raw_value(#axi_priority_rd_port_3),
],
lpddr_ctrl_0: regs::LpddrControl0::new_with_raw_value(#lpddr_ctrl_0),
lpddr_ctrl_1: regs::LpddrControl1::new_with_raw_value(#lpddr_ctrl_1),
lpddr_ctrl_2: regs::LpddrControl2::new_with_raw_value(#lpddr_ctrl_2),
lpddr_ctrl_3: regs::LpddrControl3::new_with_raw_value(#lpddr_ctrl_3),
};
};
std::fs::write(file_name, generated.to_string())?;
Ok(())
}
fn generate_ddriob_config(
reg_to_values: &RegisterToValueMap,
file_name: &str,
) -> std::io::Result<()> {
// Format as hex strings
let addr0 = reg_to_values.val_as_token("DDRIOB Addr 0", 0xF800_0B40);
let addr1 = reg_to_values.val_as_token("DDRIOB Addr 1", 0xF800_0B44);
let data0 = reg_to_values.val_as_token("DDRIOB Data 0", 0xF800_0B48);
let data1 = reg_to_values.val_as_token("DDRIOB Data 1", 0xF800_0B4C);
let diff0 = reg_to_values.val_as_token("DDRIOB Diff 0", 0xF800_0B50);
let diff1 = reg_to_values.val_as_token("DDRIOB Diff 1", 0xF800_0B54);
let clock = reg_to_values.val_as_token("DDRIOB Clock", 0xF800_0B58);
let generated = quote::quote! {
//!This file was auto-generated by the [zynq7000-ps7init-extract](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/tools/zynq7000-ps7init-extract) program.
//!
//!This configuration file contains static DDRIOB configuration parameters extracted from the
//!AMD ps7init.tcl file
use zynq7000::ddrc::regs;
use zynq7000_hal::ddr::DdriobConfigSet;
pub const DDRIOB_CONFIG_SET_ZEDBOARD: DdriobConfigSet = DdriobConfigSet {
addr0: regs::DdriobConfig::new_with_raw_value(#addr0),
addr1: regs::DdriobConfig::new_with_raw_value(#addr1),
data0: regs::DdriobConfig::new_with_raw_value(#data0),
data1: regs::DdriobConfig::new_with_raw_value(#data1),
diff0: regs::DdriobConfig::new_with_raw_value(#diff0),
diff1: regs::DdriobConfig::new_with_raw_value(#diff1),
clock: regs::DdriobConfig::new_with_raw_value(#clock),
};
};
std::fs::write(file_name, generated.to_string())?;
Ok(())
}

View File

@@ -1,4 +0,0 @@
#![no_std]
pub mod phy_marvell;
pub mod qspi_spansion;

View File

@@ -38,3 +38,25 @@ vivado zedboard-rust.xpr
You can perform all the steps specified in the Vivado GUI as well using `Execute TCL script` and
`Load Project`.
# Generating the SDT folder from a hardware description
You can generate a hardware description by building the block design by using `Generate Bitstream`
inside the Vivado GUI and then exporting the hardware description via
`File -> Export -> Export Hardware`. This allows to generate a `*.xsa` file which describes the
hardware.
After that, you can generate the SDT output folder which contains various useful files like
the `ps7_init.tcl` script. The provided ` sdtgen.tcl` and `stdgen.py` script simplify this process.
For example, the following command generates the SDT output folder inside a folder
named `sdt_out` for a hardware description files `zedboard-rust/zedboard-rust.xsa`,
assuming that the Vitis tool suite is installed at `/tools/Xilinx/Vitis/2024.1`:
```sh
export AMD_TOOLS="/tools/Xilinx/Vitis/2024.1"
./sdtgen.py -x ./zedboard-rust/zedboard-rust.xsa
```
Run `stdgen.py -h` for more information and configuration options. The `stdgen.py` is a helper
script which will invoke `sdtgen.tcl` to generate the SDT.

View File

@@ -1,503 +0,0 @@
use arbitrary_int::{u2, u3, u4, u5, u6, u7, u9, u10, u11, u12, u20};
use zynq7000::{
ddrc::regs::{
AxiPriorityReadPort, AxiPriorityWritePort, CheEccControl, CheTZq, CheTZqShortInterval,
CtrlReg1, CtrlReg2, CtrlReg3, CtrlReg4, CtrlReg5, CtrlReg6, DataBusWidth, DdrcControl,
DeepPowerdown, DfiTiming, DisableDq, DllCalib, DllCalibSel, DramAddrMapBank,
DramAddrMapColumn, DramAddrMapRow, DramBurst8ReadWrite, DramEmr, DramEmrMr, DramInitParam,
DramOdt, DramParamReg0, DramParamReg1, DramParamReg2, DramParamReg3, DramParamReg4,
EccMode, EccScrub, LpddrBit, LpddrControl0, LpddrControl1, LpddrControl2, LpddrControl3,
LprHprQueueControl, MobileSetting, ModeRegisterType, OdtDelayHold, PhyCmdTimeoutRdDataCpt,
PhyConfig, PhyDqsConfig, PhyInitRatio, PhyReceiverEnable, PhyWriteDataSlaveConfig,
PhyWriteEnableConfig, Reg2c, Reg2d, Reg64, Reg65, SoftReset, TwoRankConfig,
WriteQueueControl,
},
slcr::ddriob::{DciType, DdriobConfig, InputType, OutputEnable},
};
use zynq7000_hal::ddr::{DdrcConfigSet, DdriobConfigSet};
const DDRIOB_ADDR_CFG: DdriobConfig = DdriobConfig::builder()
.with_pullup_enable(false)
.with_output_enable(OutputEnable::OBuf)
.with_term_disable_mode(false)
.with_ibuf_disable_mode(false)
.with_dci_type(DciType::Disabled)
.with_termination_enable(false)
.with_dci_update_enable(false)
.with_inp_type(InputType::Off)
.build();
const DDRIOB_DATA_CFG: DdriobConfig = DdriobConfig::builder()
.with_pullup_enable(false)
.with_output_enable(OutputEnable::OBuf)
.with_term_disable_mode(false)
.with_ibuf_disable_mode(false)
.with_dci_type(DciType::DciTermination)
.with_termination_enable(true)
.with_dci_update_enable(false)
.with_inp_type(InputType::VRefBasedDifferentialReceiverForSstlHstl)
.build();
const DDRIOB_DIFF_CFG: DdriobConfig = DdriobConfig::builder()
.with_pullup_enable(false)
.with_output_enable(OutputEnable::OBuf)
.with_term_disable_mode(false)
.with_ibuf_disable_mode(false)
.with_dci_type(DciType::DciTermination)
.with_termination_enable(true)
.with_dci_update_enable(false)
.with_inp_type(InputType::DifferentialInputReceiver)
.build();
const DDRIOB_CLOCK_CFG: DdriobConfig = DdriobConfig::builder()
.with_pullup_enable(false)
.with_output_enable(OutputEnable::OBuf)
.with_term_disable_mode(false)
.with_ibuf_disable_mode(false)
.with_dci_type(DciType::Disabled)
.with_termination_enable(false)
.with_dci_update_enable(false)
.with_inp_type(InputType::Off)
.build();
// TODO: Auto-generate from ps7init.tcl
pub const DDRIOB_CONFIG_SET_ZEDBOARD: DdriobConfigSet = DdriobConfigSet {
addr0: DDRIOB_ADDR_CFG,
addr1: DDRIOB_ADDR_CFG,
data0: DDRIOB_DATA_CFG,
data1: DDRIOB_DATA_CFG,
diff0: DDRIOB_DIFF_CFG,
diff1: DDRIOB_DIFF_CFG,
clock: DDRIOB_CLOCK_CFG,
};
// TODO: Auto-generate from ps7init.tcl
pub const DDRC_CONFIG_ZEDBOARD_FULL_BUILDERS: DdrcConfigSet = DdrcConfigSet {
ctrl: DdrcControl::builder()
.with_disable_auto_refresh(false)
.with_disable_active_bypass(false)
.with_disable_read_bypass(false)
.with_read_write_idle_gap(u7::new(1))
.with_burst8_refresh(u3::new(0))
.with_data_bus_width(DataBusWidth::_32Bit)
.with_power_down_enable(false)
.with_soft_reset(SoftReset::Reset)
.build(),
two_rank: TwoRankConfig::builder()
.with_addrmap_cs_bit0(u5::new(0))
.with_ddrc_active_ranks(u2::new(1))
.with_rfc_nom_x32(u12::new(0x82))
.build(),
hpr: LprHprQueueControl::builder()
.with_xact_run_length(u4::new(0xf))
.with_max_starve_x32(u11::new(0xf))
.with_min_non_critical_x32(u11::new(0xf))
.build(),
lpr: LprHprQueueControl::builder()
.with_xact_run_length(u4::new(0x8))
.with_max_starve_x32(u11::new(0x2))
.with_min_non_critical_x32(u11::new(0x1))
.build(),
wr: WriteQueueControl::builder()
.with_max_starve_x32(u11::new(0x2))
.with_xact_run_length(u4::new(0x8))
.with_min_non_critical_x32(u11::new(0x1))
.build(),
dram_param_0: DramParamReg0::builder()
.with_post_selfref_gap_x32(u7::new(0x10))
.with_t_rfc_min(0x56)
.with_t_rc(u6::new(0x1b))
.build(),
dram_param_1: DramParamReg1::builder()
.with_t_cke(u4::new(0x4))
.with_t_ras_min(u5::new(0x13))
.with_t_ras_max(u6::new(0x24))
.with_t_faw(u6::new(0x16))
.with_powerdown_to_x32(u5::new(0x6))
.with_wr2pre(u5::new(0x13))
.build(),
dram_param_2: DramParamReg2::builder()
.with_t_rcd(u4::new(0x7))
.with_rd2pre(u5::new(0x5))
.with_pad_pd(u3::new(0x0))
.with_t_xp(u5::new(0x5))
.with_wr2rd(u5::new(0xf))
.with_rd2wr(u5::new(0x7))
.with_write_latency(u5::new(0x5))
.build(),
dram_param_3: DramParamReg3::builder()
.with_disable_pad_pd_feature(false)
.with_read_latency(u5::new(0x7))
.with_enable_dfi_dram_clk_disable(false)
.with_mobile(MobileSetting::Ddr2Ddr3)
.with_sdram(false)
.with_refresh_to_x32(u5::new(0x8))
.with_t_rp(u4::new(0x7))
.with_refresh_margin(u4::new(0x2))
.with_t_rrd(u3::new(0x6))
.with_t_ccd(u3::new(0x4))
.build(),
dram_param_4: DramParamReg4::builder()
.with_mr_rdata_valid(false)
.with_mr_type(ModeRegisterType::Write)
.with_mr_wr_busy(false)
.with_mr_data(0x0)
.with_mr_addr(u2::new(0x0))
.with_mr_wr(false)
.with_prefer_write(false)
.with_enable_2t_timing_mode(false)
.build(),
dram_init_param: DramInitParam::builder()
.with_t_mrd(u3::new(0x4))
.with_pre_ocd_x32(u4::new(0x0))
.with_final_wait_x32(u7::new(0x7))
.build(),
dram_emr: DramEmr::builder().with_emr3(0x0).with_emr2(0x8).build(),
dram_emr_mr: DramEmrMr::builder().with_emr(0x4).with_mr(0xb30).build(),
dram_burst8_rdwr: DramBurst8ReadWrite::builder()
.with_burst_rdwr(u4::new(0x4))
.with_pre_cke_x1024(u10::new(0x16d))
.with_post_cke_x1024(u10::new(0x1))
.with_burstchop(false)
.build(),
disable_dq: DisableDq::builder()
.with_dis_dq(false)
.with_force_low_pri_n(false)
.build(),
dram_addr_map_bank: DramAddrMapBank::builder()
.with_addrmap_bank_b6(u4::new(0))
.with_addrmap_bank_b5(u4::new(0))
.with_addrmap_bank_b2(u4::new(0x7))
.with_addrmap_bank_b1(u4::new(0x7))
.with_addrmap_bank_b0(u4::new(0x7))
.build(),
dram_addr_map_col: DramAddrMapColumn::builder()
.with_addrmap_col_b11(u4::new(0xf))
.with_addrmap_col_b10(u4::new(0xf))
.with_addrmap_col_b9(u4::new(0xf))
.with_addrmap_col_b8(u4::new(0x0))
.with_addrmap_col_b7(u4::new(0x0))
.with_addrmap_col_b4(u4::new(0x0))
.with_addrmap_col_b3(u4::new(0x0))
.with_addrmap_col_b2(u4::new(0x0))
.build(),
dram_addr_map_row: DramAddrMapRow::builder()
.with_addrmap_row_b15(u4::new(0xf))
.with_addrmap_row_b14(u4::new(0xf))
.with_addrmap_row_b13(u4::new(0x6))
.with_addrmap_row_b12(u4::new(0x6))
.with_addrmap_row_b2_11(u4::new(0x6))
.with_addrmap_row_b1(u4::new(0x6))
.with_addrmap_row_b0(u4::new(0x4))
.build(),
dram_odt: DramOdt::builder()
.with_phy_idle_local_odt(u2::new(0x0))
.with_phy_write_local_odt(u2::new(0x3))
.with_phy_read_local_odt(u2::new(0x0))
.with_rank0_wr_odt(u3::new(0x1))
.with_rank0_rd_odt(u3::new(0x0))
.build(),
phy_cmd_timeout_rddata_cpt: PhyCmdTimeoutRdDataCpt::builder()
.with_wrlvl_num_of_dq0(u4::new(0x7))
.with_gatelvl_num_of_dq0(u4::new(0x7))
.with_clk_stall_level(false)
.with_dis_phy_ctrl_rstn(false)
.with_rdc_fifo_rst_err_cnt_clr(false)
.with_use_fixed_re(true)
.with_rdc_we_to_re_delay(u4::new(0x8))
.with_wr_cmd_to_data(u4::new(0x0))
.with_rd_cmd_to_data(u4::new(0x0))
.build(),
dll_calib: DllCalib::builder().with_sel(DllCalibSel::Periodic).build(),
odt_delay_hold: OdtDelayHold::builder()
.with_wr_odt_hold(u4::new(0x5))
.with_rd_odt_hold(u4::new(0x0))
.with_wr_odt_delay(u4::new(0x0))
.with_rd_odt_delay(u4::new(0x3))
.build(),
ctrl_reg1: CtrlReg1::builder()
.with_selfref_enable(false)
.with_dis_collision_page_opt(false)
.with_dis_wc(false)
.with_refresh_update_level(false)
.with_auto_pre_en(false)
.with_lpr_num_entries(u6::new(0x1f))
.with_pageclose(false)
.build(),
ctrl_reg2: CtrlReg2::builder()
.with_go_2_critcal_enable(true)
.with_go_2_critical_hysteresis(0x0)
.build(),
ctrl_reg3: CtrlReg3::builder()
.with_dfi_t_wlmrd(u10::new(0x28))
.with_rdlvl_rr(0x41)
.with_wrlvl_ww(0x41)
.build(),
ctrl_reg4: CtrlReg4::builder()
.with_dfi_t_ctrlupd_interval_max_x1024(0x16)
.with_dfi_t_ctrlupd_interval_min_x1024(0x10)
.build(),
ctrl_reg5: CtrlReg5::builder()
.with_t_ckesr(u6::new(0x4))
.with_t_cksrx(u4::new(0x6))
.with_t_ckrse(u4::new(0x6))
.with_dfi_t_dram_clk_enable(u4::new(0x1))
.with_dfi_t_dram_clk_disable(u4::new(0x1))
.with_dfi_t_ctrl_delay(u4::new(0x1))
.build(),
ctrl_reg6: CtrlReg6::builder()
.with_t_cksx(u4::new(0x3))
.with_t_ckdpdx(u4::new(0x2))
.with_t_ckdpde(u4::new(0x2))
.with_t_ckpdx(u4::new(0x2))
.with_t_ckpde(u4::new(0x2))
.build(),
che_t_zq: CheTZq::builder()
.with_t_zq_short_nop(u10::new(0x40))
.with_t_zq_long_nop(u10::new(0x200))
.with_t_mode(u10::new(0x200))
.with_ddr3(true)
.with_dis_auto_zq(false)
.build(),
che_t_zq_short_interval_reg: CheTZqShortInterval::builder()
.with_dram_rstn_x1024(0x69)
.with_t_zq_short_interval(u20::new(0xcb73))
.build(),
deep_powerdown: DeepPowerdown::builder()
.with_deep_powerdown_to_x1024(0xff)
.with_enable(false)
.build(),
reg_2c: Reg2c::builder()
.with_dfi_rd_data_eye_train(true)
.with_dfi_rd_dqs_gate_level(true)
.with_dfi_wr_level_enable(true)
.with_trdlvl_max_error(false)
.with_twrlvl_max_error(false)
.with_dfi_rdlvl_max_x1024(u12::new(0xfff))
.with_dfi_wrlvl_max_x1024(u12::new(0xfff))
.build(),
reg_2d: Reg2d::builder().with_skip_ocd(true).build(),
dfi_timing: DfiTiming::builder()
.with_dfi_t_ctrlup_max(u10::new(0x40))
.with_dfi_t_ctrlup_min(u10::new(0x3))
.with_dfi_t_rddata_enable(u5::new(0x6))
.build(),
che_ecc_ctrl: CheEccControl::builder()
.with_clear_correctable_errors(false)
.with_clear_uncorrectable_errors(false)
.build(),
ecc_scrub: EccScrub::builder()
.with_disable_scrub(true)
.with_ecc_mode(EccMode::NoEcc)
.build(),
phy_receiver_enable: PhyReceiverEnable::builder()
.with_phy_dif_off(u4::new(0))
.with_phy_dif_on(u4::new(0))
.build(),
phy_config: [PhyConfig::builder()
.with_dq_offset(u7::new(0x40))
.with_wrlvl_inc_mode(false)
.with_gatelvl_inc_mode(false)
.with_rdlvl_inc_mode(false)
.with_data_slice_in_use(true)
.build(); 4],
phy_init_ratio: [
PhyInitRatio::builder()
.with_gatelvl_init_ratio(u10::new(0xcf))
.with_wrlvl_init_ratio(u10::new(0x3))
.build(),
PhyInitRatio::builder()
.with_gatelvl_init_ratio(u10::new(0xd0))
.with_wrlvl_init_ratio(u10::new(0x3))
.build(),
PhyInitRatio::builder()
.with_gatelvl_init_ratio(u10::new(0xbd))
.with_wrlvl_init_ratio(u10::new(0x0))
.build(),
PhyInitRatio::builder()
.with_gatelvl_init_ratio(u10::new(0xc1))
.with_wrlvl_init_ratio(u10::new(0x0))
.build(),
],
phy_rd_dqs_config: [
PhyDqsConfig::builder()
.with_dqs_slave_delay(u9::new(0x0))
.with_dqs_slave_force(false)
.with_dqs_slave_ratio(u10::new(0x35))
.build(),
PhyDqsConfig::builder()
.with_dqs_slave_delay(u9::new(0x0))
.with_dqs_slave_force(false)
.with_dqs_slave_ratio(u10::new(0x35))
.build(),
PhyDqsConfig::builder()
.with_dqs_slave_delay(u9::new(0x0))
.with_dqs_slave_force(false)
.with_dqs_slave_ratio(u10::new(0x35))
.build(),
PhyDqsConfig::builder()
.with_dqs_slave_delay(u9::new(0x0))
.with_dqs_slave_force(false)
.with_dqs_slave_ratio(u10::new(0x35))
.build(),
],
phy_wr_dqs_config: [
PhyDqsConfig::builder()
.with_dqs_slave_delay(u9::new(0x0))
.with_dqs_slave_force(false)
.with_dqs_slave_ratio(u10::new(0x83))
.build(),
PhyDqsConfig::builder()
.with_dqs_slave_delay(u9::new(0x0))
.with_dqs_slave_force(false)
.with_dqs_slave_ratio(u10::new(0x83))
.build(),
PhyDqsConfig::builder()
.with_dqs_slave_delay(u9::new(0x0))
.with_dqs_slave_force(false)
.with_dqs_slave_ratio(u10::new(0x7f))
.build(),
PhyDqsConfig::builder()
.with_dqs_slave_delay(u9::new(0x0))
.with_dqs_slave_force(false)
.with_dqs_slave_ratio(u10::new(0x78))
.build(),
],
phy_we_cfg: [
PhyWriteEnableConfig::builder()
.with_fifo_we_in_delay(u9::new(0x0))
.with_fifo_we_in_force(false)
.with_fifo_we_slave_ratio(u11::new(0x124))
.build(),
PhyWriteEnableConfig::builder()
.with_fifo_we_in_delay(u9::new(0x0))
.with_fifo_we_in_force(false)
.with_fifo_we_slave_ratio(u11::new(0x125))
.build(),
PhyWriteEnableConfig::builder()
.with_fifo_we_in_delay(u9::new(0x0))
.with_fifo_we_in_force(false)
.with_fifo_we_slave_ratio(u11::new(0x112))
.build(),
PhyWriteEnableConfig::builder()
.with_fifo_we_in_delay(u9::new(0x0))
.with_fifo_we_in_force(false)
.with_fifo_we_slave_ratio(u11::new(0x116))
.build(),
],
phy_wr_data_slv: [
PhyWriteDataSlaveConfig::builder()
.with_wr_data_slave_delay(u9::new(0x0))
.with_wr_data_slave_force(false)
.with_wr_data_slave_ratio(u10::new(0xc3))
.build(),
PhyWriteDataSlaveConfig::builder()
.with_wr_data_slave_delay(u9::new(0x0))
.with_wr_data_slave_force(false)
.with_wr_data_slave_ratio(u10::new(0xc3))
.build(),
PhyWriteDataSlaveConfig::builder()
.with_wr_data_slave_delay(u9::new(0x0))
.with_wr_data_slave_force(false)
.with_wr_data_slave_ratio(u10::new(0xbf))
.build(),
PhyWriteDataSlaveConfig::builder()
.with_wr_data_slave_delay(u9::new(0x0))
.with_wr_data_slave_force(false)
.with_wr_data_slave_ratio(u10::new(0xb8))
.build(),
],
reg64: Reg64::builder()
.with_cmd_latency(false)
.with_lpddr(false)
.with_ctrl_slave_delay(u7::new(0x0))
.with_ctrl_slave_force(false)
.with_ctrl_slave_ratio(u10::new(0x100))
.with_sel_logic(false)
.with_invert_clkout(true)
.with_bl2(false)
.build(),
reg65: Reg65::builder()
.with_ctrl_slave_delay(u2::new(0x0))
.with_dis_calib_rst(false)
.with_use_rd_data_eye_level(true)
.with_use_rd_dqs_gate_level(true)
.with_use_wr_level(true)
.with_dll_lock_diff(u4::new(0xf))
.with_rd_rl_delay(u5::new(0x4))
.with_wr_rl_delay(u5::new(0x2))
.build(),
page_mask: 0x0,
axi_priority_wr_port: [
AxiPriorityWritePort::builder()
.with_disable_page_match(false)
.with_disable_urgent(false)
.with_disable_aging(false)
.with_pri_wr_port(u10::new(0x3ff))
.build(),
AxiPriorityWritePort::builder()
.with_disable_page_match(false)
.with_disable_urgent(false)
.with_disable_aging(false)
.with_pri_wr_port(u10::new(0x3ff))
.build(),
AxiPriorityWritePort::builder()
.with_disable_page_match(false)
.with_disable_urgent(false)
.with_disable_aging(false)
.with_pri_wr_port(u10::new(0x3ff))
.build(),
AxiPriorityWritePort::builder()
.with_disable_page_match(false)
.with_disable_urgent(false)
.with_disable_aging(false)
.with_pri_wr_port(u10::new(0x3ff))
.build(),
],
axi_priority_rd_port: [
AxiPriorityReadPort::builder()
.with_enable_hpr(false)
.with_disable_page_match(false)
.with_disable_urgent(false)
.with_disable_aging(false)
.with_pri_rd_port_n(u10::new(0x3ff))
.build(),
AxiPriorityReadPort::builder()
.with_enable_hpr(false)
.with_disable_page_match(false)
.with_disable_urgent(false)
.with_disable_aging(false)
.with_pri_rd_port_n(u10::new(0x3ff))
.build(),
AxiPriorityReadPort::builder()
.with_enable_hpr(false)
.with_disable_page_match(false)
.with_disable_urgent(false)
.with_disable_aging(false)
.with_pri_rd_port_n(u10::new(0x3ff))
.build(),
AxiPriorityReadPort::builder()
.with_enable_hpr(false)
.with_disable_page_match(false)
.with_disable_urgent(false)
.with_disable_aging(false)
.with_pri_rd_port_n(u10::new(0x3ff))
.build(),
],
lpddr_ctrl_0: LpddrControl0::builder()
.with_mr4_margin(0x0)
.with_derate_enable(false)
.with_per_bank_refresh(false)
.with_lpddr2(LpddrBit::Ddr2Ddr3)
.build(),
lpddr_ctrl_1: LpddrControl1::builder().with_mr4_read_interval(0x0).build(),
lpddr_ctrl_2: LpddrControl2::builder()
.with_t_mrw(u10::new(0x5))
.with_idle_after_reset_x32(0x12)
.with_min_stable_clock_x1(u4::new(0x5))
.build(),
lpddr_ctrl_3: LpddrControl3::builder()
.with_dev_zqinit_x32(u10::new(0x12))
.with_max_auto_init_x1024(0xa8)
.build(),
};

View File

@@ -1,12 +0,0 @@
[package]
name = "zynq-mmu"
description = "Zynq MMU structures"
version = "0.1.0"
edition = "2024"
[dependencies]
thiserror = { version = "2", default-features = false }
cortex-ar = { version = "0.2", git = "https://github.com/rust-embedded/cortex-ar.git", branch = "bump-arbitrary-int" }
[features]
tools = []

20
zynq/.cargo/config.toml Normal file
View File

@@ -0,0 +1,20 @@
[target.armv7a-none-eabihf]
runner = "just run"
rustflags = [
"-Ctarget-cpu=cortex-a9",
"-Ctarget-feature=+vfp3",
"-Ctarget-feature=+neon",
"-Clink-arg=-Tlink.x",
# If this is not enabled, debugging / stepping can become problematic.
"-Cforce-frame-pointers=yes",
# Can be useful for debugging.
# "-Clink-args=-Map=app.map"
]
# Tier 3 target, so no pre-compiled artifacts included.
[unstable]
build-std = ["core", "alloc"]
[build]
target = "armv7a-none-eabihf"

1
zynq/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
Cargo.lock

21
zynq/Cargo.toml Normal file
View File

@@ -0,0 +1,21 @@
[workspace]
resolver = "3"
members = [
"zynq7000-rt",
"zynq7000-mmu",
"zynq7000",
"zynq7000-hal",
"zynq7000-embassy",
"examples/simple",
"examples/embassy",
"examples/zedboard",
"zedboard-bsp",
"zedboard-qspi-flasher",
]
exclude = [
# Exclude, can not be built with debug optimization level, too large.
"zedboard-fsbl",
]

View File

@@ -11,7 +11,7 @@ keywords = ["no-std", "arm", "cortex-a", "amd", "zynq7000"]
categories = ["embedded", "no-std", "hardware-support"]
[dependencies]
cortex-ar = { version = "0.2", git = "https://github.com/rust-embedded/cortex-ar.git", rev = "79dba7000d2090d13823bfb783d9d64be8b778d2", features = ["critical-section-single-core"] }
cortex-ar = { version = "0.3", features = ["critical-section-single-core"] }
zynq7000-rt = { path = "../../zynq7000-rt" }
zynq7000 = { path = "../../zynq7000" }
zynq7000-hal = { path = "../../zynq7000-hal" }
@@ -20,19 +20,35 @@ dht-sensor = { git = "https://github.com/michaelbeaumont/dht-sensor.git", rev =
static_cell = "2"
critical-section = "1"
heapless = "0.9"
embedded-io = "0.6"
embedded-io = "0.7"
embedded-hal = "1"
fugit = "0.3"
log = "0.4"
embassy-executor = { git = "https://github.com/us-irs/embassy.git", branch = "cortex-ar-update", features = [
embassy-executor = { git = "https://github.com/embassy-rs/embassy.git", features = [
"arch-cortex-ar",
"executor-thread",
]}
# TODO: Remove generic-queue-16 feature as soon as upstream executor is used again.
embassy-time = { version = "0.5", features = ["tick-hz-1_000_000", "generic-queue-16"] }
[profile.release]
# cargo build/run
[profile.dev]
# default is opt-level = '0', but that makes very
# verbose machine code
opt-level = 's'
# trade compile speed for slightly better optimisations
codegen-units = 1
debug = true
lto = true
# cargo build/run --release
[profile.release]
# default is opt-level = '3', but that makes quite
# verbose machine code
opt-level = 's'
# trade compile speed for slightly better optimisations
codegen-units = 1
# Use Link Time Optimisations to further inline things across
# crates
lto = 'fat'
# Leave the debug symbols in (default is no debug info)
debug = 2

View File

@@ -79,7 +79,7 @@ async fn main(spawner: Spawner) -> ! {
info!("Boot mode: {:?}", boot_mode);
let led = Output::new_for_mio(mio_pins.mio7, PinState::Low);
spawner.spawn(led_task(led)).unwrap();
spawner.spawn(led_task(led).unwrap());
let mut log_buf: [u8; 2048] = [0; 2048];
let frame_queue = zynq7000_hal::log::rb::get_frame_queue();
loop {

View File

@@ -8,7 +8,7 @@ use embassy_time::{Duration, Ticker};
use embedded_hal::digital::StatefulOutputPin;
use embedded_io::Write;
use log::{error, info};
use zynq7000_hal::{clocks, gic, gpio, gtc, time::Hertz, uart, BootMode, InteruptConfig};
use zynq7000_hal::{BootMode, InteruptConfig, clocks, gic, gpio, gtc, time::Hertz, uart};
use zynq7000_rt as _;

View File

@@ -9,11 +9,11 @@ repository = "https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs"
license = "MIT OR Apache-2.0"
[dependencies]
cortex-ar = { version = "0.2", git = "https://github.com/rust-embedded/cortex-ar.git", rev = "79dba7000d2090d13823bfb783d9d64be8b778d2", features = ["critical-section-single-core"] }
cortex-ar = "0.3"
zynq7000-rt = { path = "../../zynq7000-rt" }
zynq7000 = { path = "../../zynq7000" }
zynq7000-hal = { path = "../../zynq7000-hal" }
embedded-io = "0.6"
embedded-io = "0.7"
embedded-hal = "1"
fugit = "0.3"
log = "0.4"

View File

@@ -11,7 +11,7 @@ keywords = ["no-std", "arm", "cortex-a", "amd", "zynq7000"]
categories = ["embedded", "no-std", "hardware-support"]
[dependencies]
cortex-ar = { version = "0.2", git = "https://github.com/rust-embedded/cortex-ar.git", rev = "79dba7000d2090d13823bfb783d9d64be8b778d2", features = ["critical-section-single-core"] }
cortex-ar = "0.3"
zynq7000-rt = { path = "../../zynq7000-rt" }
zynq7000 = { path = "../../zynq7000" }
zynq7000-hal = { path = "../../zynq7000-hal" }
@@ -19,7 +19,7 @@ zynq7000-embassy = { path = "../../zynq7000-embassy" }
zedboard-bsp = { path = "../../zedboard-bsp" }
num_enum = { version = "0.7", default-features = false }
l3gd20 = { git = "https://github.com/us-irs/l3gd20.git", branch = "add-async-if" }
embedded-io = "0.6"
embedded-io = "0.7"
bitbybit = "1.4"
arbitrary-int = "2"
embedded-io-async = "0.6"

View File

@@ -10,7 +10,7 @@ use embedded_io::Write;
use log::{error, info};
use zedboard::PS_CLOCK_FREQUENCY;
use zedboard_bsp::qspi_spansion;
use zynq7000_hal::{clocks, gic, gpio, gtc, prelude::*, qspi, uart, BootMode};
use zynq7000_hal::{BootMode, clocks, gic, gpio, gtc, prelude::*, qspi, uart};
use zynq7000_rt as _;

View File

@@ -9,7 +9,7 @@ use embedded_hal::digital::StatefulOutputPin;
use embedded_io::Write;
use log::{error, info};
use zedboard::PS_CLOCK_FREQUENCY;
use zynq7000_hal::{clocks, gic, gpio, gtc, uart, BootMode};
use zynq7000_hal::{BootMode, clocks, gic, gpio, gtc, uart};
use zynq7000_rt as _;

View File

@@ -1,3 +1,2 @@
[toolchain]
# channel = "stable"
channel = "nightly"

View File

@@ -4,6 +4,7 @@ version = "0.1.0"
edition = "2024"
[dependencies]
zynq7000 = { path = "../zynq7000" }
zynq7000-hal = { path = "../zynq7000-hal" }
bitbybit = "1.4"
arbitrary-int = "2"

View File

@@ -0,0 +1,101 @@
#![doc = r"This file was auto-generated by the [zynq7000-ps7init-extract](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/tools/zynq7000-ps7init-extract) program."]
#![doc = r""]
#![doc = r"This configuration file contains static DDR configuration parameters extracted from the"]
#![doc = r"AMD ps7init.tcl file"]
use zynq7000::ddrc::regs;
use zynq7000_hal::ddr::DdrcConfigSet;
pub const DDRC_CONFIG_ZEDBOARD: DdrcConfigSet = DdrcConfigSet {
ctrl: regs::DdrcControl::new_with_raw_value(0x00000080),
two_rank: regs::TwoRankConfig::new_with_raw_value(0x00001082),
hpr: regs::LprHprQueueControl::new_with_raw_value(0x03c0780f),
lpr: regs::LprHprQueueControl::new_with_raw_value(0x02001001),
wr: regs::WriteQueueControl::new_with_raw_value(0x00014001),
dram_param_0: regs::DramParamReg0::new_with_raw_value(0x0004159b),
dram_param_1: regs::DramParamReg1::new_with_raw_value(0x44e458d3),
dram_param_2: regs::DramParamReg2::new_with_raw_value(0x7282bce5),
dram_param_3: regs::DramParamReg3::new_with_raw_value(0x270872d0),
dram_param_4: regs::DramParamReg4::new_with_raw_value(0x00000000),
dram_init_param: regs::DramInitParam::new_with_raw_value(0x00002007),
dram_emr: regs::DramEmr::new_with_raw_value(0x00000008),
dram_emr_mr: regs::DramEmrMr::new_with_raw_value(0x00040b30),
dram_burst8_rdwr: regs::DramBurst8ReadWrite::new_with_raw_value(0x000116d4),
disable_dq: regs::DisableDq::new_with_raw_value(0x00000000),
dram_addr_map_bank: regs::DramAddrMapBank::new_with_raw_value(0x00000777),
dram_addr_map_col: regs::DramAddrMapColumn::new_with_raw_value(0xfff00000),
dram_addr_map_row: regs::DramAddrMapRow::new_with_raw_value(0x0ff66666),
dram_odt: regs::DramOdt::new_with_raw_value(0x0003c008),
phy_cmd_timeout_rddata_cpt: regs::PhyCmdTimeoutRdDataCpt::new_with_raw_value(0x77010800),
dll_calib: regs::DllCalib::new_with_raw_value(0x00000000),
odt_delay_hold: regs::OdtDelayHold::new_with_raw_value(0x00005003),
ctrl_reg1: regs::CtrlReg1::new_with_raw_value(0x0000003e),
ctrl_reg2: regs::CtrlReg2::new_with_raw_value(0x00020000),
ctrl_reg3: regs::CtrlReg3::new_with_raw_value(0x00284141),
ctrl_reg4: regs::CtrlReg4::new_with_raw_value(0x00001610),
ctrl_reg5: regs::CtrlReg5::new_with_raw_value(0x00466111),
ctrl_reg6: regs::CtrlReg6::new_with_raw_value(0x00032222),
che_t_zq: regs::CheTZq::new_with_raw_value(0x10200802),
che_t_zq_short_interval_reg: regs::CheTZqShortInterval::new_with_raw_value(0x10200802),
deep_powerdown: regs::DeepPowerdown::new_with_raw_value(0x000001fe),
reg_2c: regs::Reg2c::new_with_raw_value(0x1cffffff),
reg_2d: regs::Reg2d::new_with_raw_value(0x00000200),
dfi_timing: regs::DfiTiming::new_with_raw_value(0x00200066),
che_ecc_ctrl: regs::CheEccControl::new_with_raw_value(0x00000000),
ecc_scrub: regs::EccScrub::new_with_raw_value(0x00000008),
phy_receiver_enable: regs::PhyReceiverEnable::new_with_raw_value(0x00000000),
phy_config: [
regs::PhyConfig::new_with_raw_value(0x40000001),
regs::PhyConfig::new_with_raw_value(0x40000001),
regs::PhyConfig::new_with_raw_value(0x40000001),
regs::PhyConfig::new_with_raw_value(0x40000001),
],
phy_init_ratio: [
regs::PhyInitRatio::new_with_raw_value(0x00033c03),
regs::PhyInitRatio::new_with_raw_value(0x00034003),
regs::PhyInitRatio::new_with_raw_value(0x0002f400),
regs::PhyInitRatio::new_with_raw_value(0x00030400),
],
phy_rd_dqs_config: [
regs::PhyDqsConfig::new_with_raw_value(0x00000035),
regs::PhyDqsConfig::new_with_raw_value(0x00000035),
regs::PhyDqsConfig::new_with_raw_value(0x00000035),
regs::PhyDqsConfig::new_with_raw_value(0x00000035),
],
phy_wr_dqs_config: [
regs::PhyDqsConfig::new_with_raw_value(0x00000083),
regs::PhyDqsConfig::new_with_raw_value(0x00000083),
regs::PhyDqsConfig::new_with_raw_value(0x0000007f),
regs::PhyDqsConfig::new_with_raw_value(0x00000078),
],
phy_we_cfg: [
regs::PhyWriteEnableConfig::new_with_raw_value(0x00000124),
regs::PhyWriteEnableConfig::new_with_raw_value(0x00000125),
regs::PhyWriteEnableConfig::new_with_raw_value(0x00000112),
regs::PhyWriteEnableConfig::new_with_raw_value(0x00000116),
],
phy_wr_data_slv: [
regs::PhyWriteDataSlaveConfig::new_with_raw_value(0x000000c3),
regs::PhyWriteDataSlaveConfig::new_with_raw_value(0x000000c3),
regs::PhyWriteDataSlaveConfig::new_with_raw_value(0x000000bf),
regs::PhyWriteDataSlaveConfig::new_with_raw_value(0x000000b8),
],
reg64: regs::Reg64::new_with_raw_value(0x00040080),
reg65: regs::Reg65::new_with_raw_value(0x0001fc82),
page_mask: 0x00000000,
axi_priority_wr_port: [
regs::AxiPriorityWritePort::new_with_raw_value(0x000003ff),
regs::AxiPriorityWritePort::new_with_raw_value(0x000003ff),
regs::AxiPriorityWritePort::new_with_raw_value(0x000003ff),
regs::AxiPriorityWritePort::new_with_raw_value(0x000003ff),
],
axi_priority_rd_port: [
regs::AxiPriorityReadPort::new_with_raw_value(0x000003ff),
regs::AxiPriorityReadPort::new_with_raw_value(0x000003ff),
regs::AxiPriorityReadPort::new_with_raw_value(0x000003ff),
regs::AxiPriorityReadPort::new_with_raw_value(0x000003ff),
],
lpddr_ctrl_0: regs::LpddrControl0::new_with_raw_value(0x00000000),
lpddr_ctrl_1: regs::LpddrControl1::new_with_raw_value(0x00000000),
lpddr_ctrl_2: regs::LpddrControl2::new_with_raw_value(0x00005125),
lpddr_ctrl_3: regs::LpddrControl3::new_with_raw_value(0x000012a8),
};

View File

@@ -0,0 +1,16 @@
#![doc = r"This file was auto-generated by the [zynq7000-ps7init-extract](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/tools/zynq7000-ps7init-extract) program."]
#![doc = r""]
#![doc = r"This configuration file contains static DDRIOB configuration parameters extracted from the"]
#![doc = r"AMD ps7init.tcl file"]
use zynq7000::ddrc::regs;
use zynq7000_hal::ddr::DdriobConfigSet;
pub const DDRIOB_CONFIG_SET_ZEDBOARD: DdriobConfigSet = DdriobConfigSet {
addr0: regs::DdriobConfig::new_with_raw_value(0x00000600),
addr1: regs::DdriobConfig::new_with_raw_value(0x00000600),
data0: regs::DdriobConfig::new_with_raw_value(0x00000672),
data1: regs::DdriobConfig::new_with_raw_value(0x00000672),
diff0: regs::DdriobConfig::new_with_raw_value(0x00000674),
diff1: regs::DdriobConfig::new_with_raw_value(0x00000674),
clock: regs::DdriobConfig::new_with_raw_value(0x00000600),
};

View File

@@ -0,0 +1,6 @@
#![no_std]
pub mod ddrc_config_autogen;
pub mod ddriob_config_autogen;
pub mod phy_marvell;
pub mod qspi_spansion;

View File

@@ -64,6 +64,8 @@ pub enum SectorArchictecture {
Hybrid = 0x01,
}
pub const PAGE_SIZE: usize = 256;
#[derive(Debug, Clone, Copy)]
pub struct BaseDeviceId {
manufacturer_id: u8,
@@ -221,6 +223,8 @@ pub enum ProgramPageError {
ProgrammingErrorBitSet,
#[error("address error: {0}")]
Addr(#[from] AddrError),
#[error("data is larger than page size {PAGE_SIZE}")]
DataLargerThanPage,
}
pub struct QspiSpansionS25Fl256SIoMode(RefCell<QspiIoMode>);
@@ -428,14 +432,17 @@ impl QspiSpansionS25Fl256SIoMode {
/// This function also takes care of enabling writes before programming the page.
/// This function will block until the operation has completed.
///
/// TODO: Allow smaller write size
pub fn program_page(&mut self, addr: u32, data: &[u8; 256]) -> Result<(), ProgramPageError> {
/// The data length max not exceed the page size [PAGE_SIZE].
pub fn program_page(&mut self, addr: u32, data: &[u8]) -> Result<(), ProgramPageError> {
if addr + data.len() as u32 > u24::MAX.as_u32() {
return Err(AddrError::OutOfRange.into());
}
if !addr.is_multiple_of(0x100) {
return Err(AddrError::Alignment.into());
}
if data.len() > PAGE_SIZE {
return Err(ProgramPageError::DataLargerThanPage);
}
self.write_enable();
let qspi = self.0.get_mut();
let mut transfer = qspi.transfer_guard();
@@ -448,8 +455,9 @@ impl QspiSpansionS25Fl256SIoMode {
transfer.write_word_txd_00(u32::from_ne_bytes(raw_word));
let mut read_index: u32 = 0;
let mut current_byte_index = 0;
let fifo_writes = data.len().div_ceil(4);
// Fill the FIFO until it is full.
for _ in 0..FIFO_DEPTH - 1 {
for _ in 0..core::cmp::min(fifo_writes, FIFO_DEPTH - 1) {
transfer.write_word_txd_00(u32::from_ne_bytes(
data[current_byte_index..current_byte_index + 4]
.try_into()
@@ -470,25 +478,38 @@ impl QspiSpansionS25Fl256SIoMode {
}
};
while current_byte_index < data.len() {
// Immediately fill the FIFO again with the remaining 8 bytes.
wait_for_tx_slot(&mut transfer);
transfer.write_word_txd_00(u32::from_ne_bytes(
let word = match core::cmp::min(4, data.len() - current_byte_index) {
1 => {
let mut bytes = [0; 4];
bytes[0] = data[current_byte_index];
u32::from_ne_bytes(bytes)
}
2 => {
let mut bytes = [0; 4];
bytes[0..2].copy_from_slice(&data[current_byte_index..current_byte_index + 2]);
u32::from_ne_bytes(bytes)
}
3 => {
let mut bytes = [0; 4];
bytes[0..3].copy_from_slice(&data[current_byte_index..current_byte_index + 3]);
u32::from_ne_bytes(bytes)
}
4 => u32::from_ne_bytes(
data[current_byte_index..current_byte_index + 4]
.try_into()
.unwrap(),
));
),
_ => unreachable!(),
};
transfer.write_word_txd_00(word);
current_byte_index += 4;
}
wait_for_tx_slot(&mut transfer);
transfer.write_word_txd_00(u32::from_ne_bytes(
data[current_byte_index..current_byte_index + 4]
.try_into()
.unwrap(),
));
while read_index < 256 {
while read_index < data.len() as u32 {
if transfer.read_status().rx_above_threshold() {
transfer.read_rx_data();
read_index = read_index.wrapping_add(4);
@@ -528,11 +549,7 @@ impl QspiSpansionS25Fl256SIoMode {
if dummy_byte {
bytes_to_write += 1;
}
let fifo_writes = if bytes_to_write.is_multiple_of(4) {
bytes_to_write / 4
} else {
(bytes_to_write / 4) + 1
};
let fifo_writes = bytes_to_write.div_ceil(4);
// Fill the FIFO until it is full or all 0 bytes have been written.
for _ in 0..core::cmp::min(fifo_writes, FIFO_DEPTH - 1) {
transfer.write_word_txd_00(0);

View File

@@ -9,13 +9,13 @@ repository = "https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs"
license = "MIT OR Apache-2.0"
[dependencies]
cortex-ar = { version = "0.2", git = "https://github.com/rust-embedded/cortex-ar.git", rev = "79dba7000d2090d13823bfb783d9d64be8b778d2", features = ["critical-section-single-core"] }
cortex-ar = { version = "0.3", features = ["critical-section-single-core"] }
zynq7000-rt = { path = "../zynq7000-rt" }
zynq7000 = { path = "../zynq7000" }
zynq7000-hal = { path = "../zynq7000-hal" }
zynq7000-boot-image = { path = "../../zynq7000-boot-image" }
zedboard-bsp = { path = "../zedboard-bsp" }
zynq-boot-image = { path = "../zynq-boot-image" }
embedded-io = "0.6"
embedded-io = "0.7"
embedded-hal = "1"
fugit = "0.3"
log = "0.4"

View File

@@ -8,7 +8,8 @@ use cortex_ar::asm::nop;
use embedded_io::Write as _;
use log::{error, info};
use zedboard_bsp::qspi_spansion::{self, QspiSpansionS25Fl256SLinearMode};
use zynq_boot_image::DestinationDevice;
use zynq7000_boot_image::DestinationDevice;
use zynq7000_hal::priv_tim;
use zynq7000_hal::{
BootMode,
clocks::{
@@ -16,18 +17,14 @@ use zynq7000_hal::{
pll::{PllConfig, configure_arm_pll, configure_io_pll},
},
ddr::{DdrClockSetupConfig, configure_ddr_for_ddr3, memtest},
gic, gpio, l2_cache,
devcfg, gic, gpio, l2_cache,
prelude::*,
qspi,
qspi::{self, QSPI_START_ADDRESS},
time::Hertz,
uart::{ClockConfig, Config, Uart},
};
use zynq7000_rt as _;
use crate::ddr_cfg::{DDRC_CONFIG_ZEDBOARD_FULL_BUILDERS, DDRIOB_CONFIG_SET_ZEDBOARD};
pub mod ddr_cfg;
// PS clock input frequency.
const PS_CLK: Hertz = Hertz::from_raw(33_333_333);
@@ -80,35 +77,37 @@ pub fn main() -> ! {
PllConfig::new_from_target_clock(PS_CLK, IO_CLK).unwrap(),
);
let mut dp = zynq7000::Peripherals::take().unwrap();
let mut periphs = zynq7000::Peripherals::take().unwrap();
// Clock was already initialized by PS7 Init TCL script or FSBL, we just read it.
let clocks = Clocks::new_from_regs(PS_CLK).unwrap();
let gpio_pins = gpio::GpioPins::new(dp.gpio);
let gpio_pins = gpio::GpioPins::new(periphs.gpio);
let mio_pins = gpio_pins.mio;
// Set up the UART, we are logging with it.
let uart_clk_config = ClockConfig::new_autocalc_with_error(clocks.io_clocks(), 115200)
.unwrap()
.0;
let mut uart = Uart::new_with_mio(
dp.uart_1,
let mut logger_uart = Uart::new_with_mio(
periphs.uart_1,
Config::new_with_clk_config(uart_clk_config),
(mio_pins.mio48, mio_pins.mio49),
)
.unwrap();
uart.write_all(b"-- Zedboard Rust FSBL --\n\r").unwrap();
logger_uart
.write_all(b"-- Zedboard Rust FSBL --\n\r")
.unwrap();
// Safety: We are not multi-threaded yet.
unsafe {
zynq7000_hal::log::uart_blocking::init_unsafe_single_core(
uart,
logger_uart,
log::LevelFilter::Trace,
false,
)
};
// Set up the global interrupt controller.
let mut gic = gic::GicConfigurator::new_with_init(dp.gicc, dp.gicd);
let mut gic = gic::GicConfigurator::new_with_init(periphs.gicc, periphs.gicd);
gic.enable_all_interrupts();
gic.set_all_spi_interrupt_targets_cpu0();
gic.enable();
@@ -117,7 +116,7 @@ pub fn main() -> ! {
info!("Configuring DDR..");
configure_ddr_for_ddr3(
dp.ddrc,
periphs.ddrc,
boot_mode,
DdrClockSetupConfig {
ps_clk: PS_CLK,
@@ -125,16 +124,18 @@ pub fn main() -> ! {
ddr_3x_div: u6::new(2),
ddr_2x_div: u6::new(3),
},
&DDRIOB_CONFIG_SET_ZEDBOARD,
&DDRC_CONFIG_ZEDBOARD_FULL_BUILDERS,
&zedboard_bsp::ddriob_config_autogen::DDRIOB_CONFIG_SET_ZEDBOARD,
&zedboard_bsp::ddrc_config_autogen::DDRC_CONFIG_ZEDBOARD,
);
info!("DDR init done.");
info!("L2 cache init..");
// Set up the L2 cache now that the DDR is in normal operation mode.
l2_cache::init_with_defaults(&mut dp.l2c);
l2_cache::init_with_defaults(&mut periphs.l2c);
info!("L2 cache init done.");
let priv_tim = priv_tim::CpuPrivateTimer::take(clocks.arm_clocks()).unwrap();
if PERFORM_DDR_MEMTEST {
let ddr_base_addr = 0x100000;
info!("performing DDR memory test..");
@@ -154,7 +155,7 @@ pub fn main() -> ! {
)
.expect("QSPI clock calculation failed");
let qspi = qspi::Qspi::new_single_qspi_with_feedback(
dp.qspi,
periphs.qspi,
qspi_clock_config,
embedded_hal::spi::MODE_0,
qspi::IoType::LvCmos33,
@@ -168,19 +169,19 @@ pub fn main() -> ! {
let spansion_qspi = qspi_spansion::QspiSpansionS25Fl256SIoMode::new(qspi_io_mode, true);
let spansion_lqspi =
spansion_qspi.into_linear_addressed(qspi_spansion::QSPI_DEV_COMBINATION_REV_F.into());
qspi_boot(spansion_lqspi);
qspi_boot(spansion_lqspi, priv_tim);
}
loop {
cortex_ar::asm::nop();
}
}
fn qspi_boot(mut qspi: QspiSpansionS25Fl256SLinearMode) -> ! {
fn qspi_boot(mut qspi: QspiSpansionS25Fl256SLinearMode, _priv_tim: priv_tim::CpuPrivateTimer) -> ! {
let boot_bin_base_addr = ELF_BASE_ADDR + BOOT_BIN_STAGING_OFFSET;
let mut boot_header_slice = unsafe {
core::slice::from_raw_parts_mut(
boot_bin_base_addr as *mut u8,
zynq_boot_image::FIXED_BOOT_HEADER_SIZE,
zynq7000_boot_image::FIXED_BOOT_HEADER_SIZE,
)
};
let read_guard = qspi.read_guard();
@@ -189,12 +190,12 @@ fn qspi_boot(mut qspi: QspiSpansionS25Fl256SLinearMode) -> ! {
core::ptr::copy_nonoverlapping(
QspiSpansionS25Fl256SLinearMode::BASE_ADDR as *mut u8,
boot_header_slice.as_mut_ptr(),
zynq_boot_image::FIXED_BOOT_HEADER_SIZE,
zynq7000_boot_image::FIXED_BOOT_HEADER_SIZE,
);
}
drop(read_guard);
let boot_header = zynq_boot_image::BootHeader::new(boot_header_slice).unwrap();
let boot_header = zynq7000_boot_image::BootHeader::new(boot_header_slice).unwrap();
let fsbl_offset = boot_header.source_offset();
boot_header_slice =
unsafe { core::slice::from_raw_parts_mut(boot_bin_base_addr as *mut u8, fsbl_offset) };
@@ -203,33 +204,101 @@ fn qspi_boot(mut qspi: QspiSpansionS25Fl256SLinearMode) -> ! {
let read_guard = qspi.read_guard();
unsafe {
core::ptr::copy_nonoverlapping(
(QspiSpansionS25Fl256SLinearMode::BASE_ADDR + zynq_boot_image::FIXED_BOOT_HEADER_SIZE)
as *mut u8,
boot_header_slice[zynq_boot_image::FIXED_BOOT_HEADER_SIZE..].as_mut_ptr(),
fsbl_offset - zynq_boot_image::FIXED_BOOT_HEADER_SIZE,
(QspiSpansionS25Fl256SLinearMode::BASE_ADDR
+ zynq7000_boot_image::FIXED_BOOT_HEADER_SIZE) as *mut u8,
boot_header_slice[zynq7000_boot_image::FIXED_BOOT_HEADER_SIZE..].as_mut_ptr(),
fsbl_offset - zynq7000_boot_image::FIXED_BOOT_HEADER_SIZE,
);
}
drop(read_guard);
let boot_header = zynq_boot_image::BootHeader::new_unchecked(boot_header_slice);
let boot_header = zynq7000_boot_image::BootHeader::new_unchecked(boot_header_slice);
let mut name_buf: [u8; 256] = [0; 256];
for image_header in boot_header.image_header_iterator().unwrap() {
let mut opt_jump_addr = None;
for (index, image_header) in boot_header.image_header_iterator().unwrap().enumerate() {
let name = image_header.image_name(&mut name_buf).unwrap();
for partition in image_header
if index == 0 {
if !name.contains("fsbl") {
log::warn!("first image name did not contain FSBL string");
}
// Skip the FSBL. It is probably currently running, and we do not want to re-flash it,
// which would also lead to a self-overwrite.
log::info!("skipping FSBL image");
continue;
}
let _read_guard = qspi.read_guard();
for (partition_index, partition) in image_header
.partition_header_iterator(boot_header_slice)
.unwrap()
.enumerate()
{
let section_attrs = partition.section_attributes();
if let Ok(dest_dev) = section_attrs.destination_device() {
if section_attrs.destination_device().is_err() {
log::error!(
"invalid destination device ID {}",
section_attrs.destination_device().unwrap_err()
);
continue;
}
let dest_dev = section_attrs.destination_device().unwrap();
match dest_dev {
DestinationDevice::Pl => {
info!("Loading image '{name}' to PL (FPGA)..");
// TODO: Load the bitstream.
// Load the bitstream directly from linear mapped QSPI memory.
let boot_bin_slice = unsafe {
core::slice::from_raw_parts(
(QSPI_START_ADDRESS
+ partition
.data_offset()
.expect("invalid PL partition data offset"))
as *const _,
partition.total_partition_length().unwrap(),
)
};
// The DMA will read from the linear mapped QSPI directly, so it
// has to be configured for reads using the guard!
devcfg::configure_bitstream_non_secure(true, boot_bin_slice)
.expect("unexpected unaligned address");
log::info!("loaded bitstream successfully");
}
DestinationDevice::Ps => {
// TODO: Load the binary into DDR. Jump at lowest load address after all
// partitions were parsed.
// Load the bitstream directly from linear mapped QSPI memory.
let load_addr = partition.destination_load_address();
if load_addr < 0x10_0000 {
panic!("invalid load address which is not located in DDR memory");
}
log::info!(
"Loading partition {partition_index} for '{name}' to PS with load address {load_addr}.."
);
let source_slice = unsafe {
core::slice::from_raw_parts(
(QSPI_START_ADDRESS
+ partition
.data_offset()
.expect("invalid PS partition data offset"))
as *const _,
partition.total_partition_length().unwrap(),
)
};
let target_slice = unsafe {
core::slice::from_raw_parts_mut(
load_addr as *mut u8,
partition.total_partition_length().unwrap(),
)
};
// Copy from the linear mapped QSPI to DDR,
target_slice.copy_from_slice(source_slice);
match &mut opt_jump_addr {
Some(current) => *current = core::cmp::min(*current, load_addr),
None => opt_jump_addr = Some(load_addr),
}
log::info!("load success");
}
_ => {
error!("Unsupported destination device {dest_dev:?}");
@@ -238,10 +307,23 @@ fn qspi_boot(mut qspi: QspiSpansionS25Fl256SLinearMode) -> ! {
}
}
}
}
loop {
cortex_ar::asm::nop();
match opt_jump_addr {
Some(jump_addr) => {
log::info!("jumping to address {}", jump_addr);
zynq7000_hal::log::uart_blocking::flush();
// Some clean up and preparation for jumping to the user application.
zynq7000_hal::cache::clean_and_invalidate_data_cache();
cortex_ar::register::TlbIAll::write();
cortex_ar::register::BpIAll::write();
cortex_ar::asm::dsb();
cortex_ar::asm::isb();
let jump_func: extern "C" fn() -> ! = unsafe { core::mem::transmute(jump_addr) };
jump_func();
}
None => panic!("did not find application elf to boot inside boot binary!"),
}
}

View File

@@ -4,11 +4,13 @@ version = "0.1.0"
edition = "2024"
[dependencies]
cortex-ar = { version = "0.2", git = "https://github.com/rust-embedded/cortex-ar.git", branch = "main" }
cortex-ar = { version = "0.3" }
zynq7000-rt = { path = "../zynq7000-rt" }
zynq7000 = { path = "../zynq7000" }
zynq7000-hal = { path = "../zynq7000-hal" }
zynq7000-boot-image = { path = "../../zynq7000-boot-image" }
zedboard-bsp = { path = "../zedboard-bsp" }
embedded-io = "0.6"
embedded-io = "0.7"
embedded-hal = "1"
log = "0.4"
libm = "0.2"

View File

@@ -0,0 +1,31 @@
//! This build script copies the `memory.x` file from the crate root into
//! a directory where the linker can always find it at build time.
//! For many projects this is optional, as the linker always searches the
//! project root directory -- wherever `Cargo.toml` is. However, if you
//! are using a workspace or have a more complicated build setup, this
//! build script becomes required. Additionally, by requesting that
//! Cargo re-run the build script whenever `memory.x` is changed,
//! updating `memory.x` ensures a rebuild of the application with the
//! new memory settings.
use std::env;
use std::fs::File;
use std::io::Write;
use std::path::PathBuf;
fn main() {
// Put `memory.x` in our output directory and ensure it's
// on the linker search path.
let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
File::create(out.join("memory.x"))
.unwrap()
.write_all(include_bytes!("memory.x"))
.unwrap();
println!("cargo:rustc-link-search={}", out.display());
// By default, Cargo will re-run a build script whenever
// any file in the project changes. By specifying `memory.x`
// here, we ensure the build script is only re-run when
// `memory.x` is changed.
println!("cargo:rerun-if-changed=memory.x");
}

View 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
}

View File

@@ -0,0 +1,151 @@
if {[info exists env(ip_address_hw_server)]} {
set ip $env(ip_address_hw_server)
} else {
set ip "localhost"
}
# absolute directory that contains *this* script
set script_dir [file dirname [info script]]
# Defaults
set boot_bin_addr 0x10000000
set boot_bin_size_addr 0x900000
set init_tcl ""
set bin ""
set bitstream ""
# Usage helper
proc usage {} {
puts "Usage: xsct qspi-flasher.tcl <init.tcl> \[-b|--bin <boot.bin>\]"
puts "Options:"
puts " -b, --bin Path to boot binary to flash"
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 "-b" || $arg eq "--bin"} { set expecting bin; 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
}
}
# Check that QSPI flasher app exists.
set flasher_app [file join $script_dir .. target armv7a-none-eabihf release zedboard-qspi-flasher]
if {![file exists $flasher_app]} {
error "QSPI flasher application not found at path: $flasher_app"
}
set flasher_app [file normalize $flasher_app]
# 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 {$bin ne ""} {
if {![file exists $bin]} {
puts "error: the boot binary file '$bin' does not exist"
exit 1
}
} elseif {[info exists env(BOOTBIN)]} {
if {[file exists $env(BOOTBIN)]} {
set bin $env(BOOTBIN)
} else {
puts "warning: BOOTBIN environment variable is set but file does not exist: $env(BOOTBIN)"
}
}
if {$bin eq ""} {
puts "error: boot.bin binary required"
usage
exit 1
}
# 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
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
puts "Download boot.bin $bin to target DDR at address $boot_bin_addr"
dow -data $bin $boot_bin_addr
# Write boot.bin binary size to specific address.
set boot_bin_size [file size $bin]
puts "Writing boot.bin size $boot_bin_size to target DDR at address $boot_bin_size_addr"
mwr ${boot_bin_size_addr} ${boot_bin_size}
puts "Flashing QSPI flasher app"
dow $flasher_app
puts "Starting QSPI flasher app"
con
puts "Success"

View File

@@ -7,10 +7,11 @@ use core::panic::PanicInfo;
use cortex_ar::asm::nop;
use embedded_hal::{delay::DelayNs as _, digital::StatefulOutputPin as _};
use embedded_io::Write as _;
use log::info;
use log::{error, info};
use zedboard_bsp::qspi_spansion;
use zynq7000_boot_image::BootHeader;
use zynq7000_hal::{
clocks, gpio, prelude::*, priv_tim, qspi, time::Hertz, uart, BootMode, LevelShifterConfig,
BootMode, LevelShifterConfig, clocks, gpio, prelude::*, priv_tim, qspi, time::Hertz, uart,
};
use zynq7000_rt as _;
@@ -19,6 +20,15 @@ use zynq7000_rt as _;
// Not required for the PAC mode, is required for clean delays in HAL mode.
const PS_CLOCK_FREQUENCY: Hertz = Hertz::from_raw(33_333_333);
// TODO: Make this configurable somehow?
const BOOT_BIN_BASE_ADDR: usize = 0x1000_0000;
const BOOT_BIN_SIZE_ADDR: usize = 0x900_000;
// Maximum of 16 MB is allowed for now.
const MAX_BOOT_BIN_SIZE: usize = 16 * 1024 * 1024;
const VERIFY_PROGRAMMING: bool = true;
#[allow(dead_code)]
const QSPI_DEV_COMBINATION: qspi::QspiDeviceCombination = qspi::QspiDeviceCombination {
vendor: qspi::QspiVendor::WinbondAndSpansion,
@@ -67,7 +77,7 @@ pub fn main() -> ! {
unsafe {
zynq7000_hal::log::uart_blocking::init_unsafe_single_core(
uart,
log::LevelFilter::Trace,
log::LevelFilter::Info,
false,
)
};
@@ -96,7 +106,83 @@ pub fn main() -> ! {
let qspi_io_mode = qspi.into_io_mode(false);
let _spansion_qspi = qspi_spansion::QspiSpansionS25Fl256SIoMode::new(qspi_io_mode, true);
let mut spansion_qspi = qspi_spansion::QspiSpansionS25Fl256SIoMode::new(qspi_io_mode, true);
let mut boot_bin_slice = unsafe {
core::slice::from_raw_parts(BOOT_BIN_BASE_ADDR as *const _, BootHeader::FIXED_SIZED_PART)
};
// This perform some basic validity checks.
let _boot_header = BootHeader::new(&boot_bin_slice[0..BootHeader::FIXED_SIZED_PART])
.expect("failed to parse boot header");
let boot_bin_size =
unsafe { core::ptr::read_volatile(BOOT_BIN_SIZE_ADDR as *const u32) as usize };
if boot_bin_size == 0 || boot_bin_size > MAX_BOOT_BIN_SIZE {
panic!(
"boot binary size read at address {:#x} is invalid: found {}, must be in range [0, {}]",
BOOT_BIN_SIZE_ADDR, boot_bin_size, MAX_BOOT_BIN_SIZE
);
}
boot_bin_slice =
unsafe { core::slice::from_raw_parts(BOOT_BIN_BASE_ADDR as *const _, boot_bin_size) };
info!(
"flashing boot binary with {} bytes to QSPI address 0x0",
boot_bin_size
);
let mut current_addr = 0;
let mut read_buf = [0u8; 256];
let mut next_checkpoint = 0.05;
while current_addr < boot_bin_size {
if current_addr % 0x10000 == 0 {
log::debug!("Erasing sector at address {:#x}", current_addr);
match spansion_qspi.erase_sector(current_addr as u32) {
Ok(()) => {}
Err(e) => {
error!(
"failed to erase sector at address {:#x}: {:?}",
current_addr, e
);
panic!("QSPI erase failed");
}
}
}
let write_size = core::cmp::min(256, boot_bin_size - current_addr);
let write_slice = &boot_bin_slice[current_addr..current_addr + write_size];
log::debug!("Programming address {:#x}", current_addr);
match spansion_qspi.program_page(current_addr as u32, write_slice) {
Ok(()) => {}
Err(e) => {
log::error!(
"failed to write data to QSPI at address {:#x}: {:?}",
current_addr,
e
);
panic!("QSPI write failed");
}
}
if VERIFY_PROGRAMMING {
spansion_qspi.read_page_fast_read(
current_addr as u32,
&mut read_buf[0..write_size],
true,
);
if &read_buf[0..write_size] != write_slice {
error!(
"data verification failed at address {:#x}: wrote {:x?}, read {:x?}",
current_addr,
&write_slice[0..core::cmp::min(16, write_size)],
&read_buf[0..core::cmp::min(16, write_size)]
);
panic!("QSPI data verification failed");
}
}
current_addr += write_size;
if current_addr as f32 / boot_bin_size as f32 >= next_checkpoint {
log::info!("Write progress {} %", libm::roundf(next_checkpoint * 100.0));
next_checkpoint += 0.05;
}
}
info!("flashing done");
let mut mio_led = gpio::Output::new_for_mio(gpio_pins.mio.mio7, gpio::PinState::Low);
loop {

View File

@@ -11,9 +11,9 @@ keywords = ["no-std", "hal", "amd", "zynq7000", "xilinx", "bare-metal"]
categories = ["embedded", "no-std", "hardware-support"]
[dependencies]
cortex-ar = { version = "0.2", git = "https://github.com/rust-embedded/cortex-ar.git", branch = "bump-arbitrary-int" }
cortex-ar = { version = "0.3" }
zynq7000 = { path = "../zynq7000" }
zynq-mmu = { path = "../zynq-mmu", version = "0.1.0" }
zynq7000-mmu = { path = "../zynq7000-mmu", version = "0.1.0" }
static_assertions = "1.1"
bitbybit = "1.4"
@@ -22,7 +22,7 @@ thiserror = { version = "2", default-features = false }
num_enum = { version = "0.7", default-features = false }
ringbuf = { version = "0.4.8", default-features = false }
embedded-hal-nb = "1"
embedded-io = "0.6"
embedded-io = "0.7"
embedded-hal = "1"
embedded-hal-async = "1"
heapless = "0.9"
@@ -39,7 +39,7 @@ embassy-net-driver = "0.2"
smoltcp = { version = "0.12", default-features = false, features = ["proto-ipv4", "medium-ethernet", "socket-raw"] }
vcell = "0.1"
raw-slicee = "0.1"
embedded-io-async = "0.6"
embedded-io-async = "0.7"
[features]
std = ["thiserror/std", "alloc"]

View File

@@ -212,6 +212,7 @@ pub unsafe fn configure_iob(cfg_set: &DdriobConfigSet) {
}
/// Full static DDRC configuration set.
#[derive(Debug)]
pub struct DdrcConfigSet {
pub ctrl: DdrcControl,
pub two_rank: TwoRankConfig,

Some files were not shown because too many files have changed in this diff Show More