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
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:
@@ -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.
|
||||
|
||||
|
||||
50
.github/workflows/ci.yml
vendored
50
.github/workflows/ci.yml
vendored
@@ -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
3
.gitignore
vendored
@@ -1,4 +1,5 @@
|
||||
/target
|
||||
target
|
||||
|
||||
/app.map
|
||||
/xsct-output.log
|
||||
/.vscode
|
||||
|
||||
33
Cargo.toml
33
Cargo.toml
@@ -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"
|
||||
28
README.md
28
README.md
@@ -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.
|
||||
The folder contains a README with all the steps required to load this project from a TCL script.
|
||||
## 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
|
||||
|
||||
32
justfile
32
justfile
@@ -1,3 +1,35 @@
|
||||
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:
|
||||
|
||||
312
tools/Cargo.lock
generated
Normal file
312
tools/Cargo.lock
generated
Normal file
@@ -0,0 +1,312 @@
|
||||
# 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 = "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 = "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 = "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 = "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 = "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-boot-image"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"arbitrary-int 2.0.0",
|
||||
"bitbybit",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zynq7000-ps7init-extract"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"clap",
|
||||
]
|
||||
6
tools/Cargo.toml
Normal file
6
tools/Cargo.toml
Normal file
@@ -0,0 +1,6 @@
|
||||
[workspace]
|
||||
resolver = "3"
|
||||
members = [
|
||||
"boot-image-test",
|
||||
"zynq7000-ps7init-extract",
|
||||
]
|
||||
8
tools/boot-image-test/Cargo.toml
Normal file
8
tools/boot-image-test/Cargo.toml
Normal file
@@ -0,0 +1,8 @@
|
||||
[package]
|
||||
name = "boot-image-test"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
zynq7000-boot-image= { path = "../../zynq7000-boot-image" }
|
||||
clap = { version = "4", features = ["derive"] }
|
||||
@@ -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)]
|
||||
251
tools/zynq7000-ps7init-extract/Cargo.lock
generated
Normal file
251
tools/zynq7000-ps7init-extract/Cargo.lock
generated
Normal 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",
|
||||
]
|
||||
@@ -1,10 +1,7 @@
|
||||
[workspace]
|
||||
|
||||
[package]
|
||||
name = "tester"
|
||||
name = "zynq7000-ps7init-extract"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
zynq-boot-image= { path = ".." }
|
||||
clap = { version = "4", features = ["derive"] }
|
||||
20
tools/zynq7000-ps7init-extract/src/main.rs
Normal file
20
tools/zynq7000-ps7init-extract/src/main.rs
Normal file
@@ -0,0 +1,20 @@
|
||||
use std::path::Path;
|
||||
|
||||
use clap::Parser as _;
|
||||
|
||||
#[derive(clap::Parser, Debug)]
|
||||
#[command(version, about)]
|
||||
pub struct Cli {
|
||||
/// Path to ps7init.tcl file.
|
||||
#[arg(short, long)]
|
||||
path: String,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let cli = Cli::parse();
|
||||
let ps7init_tcl = Path::new(&cli.path);
|
||||
if !ps7init_tcl.exists() {
|
||||
eprintln!("File not found: {}", ps7init_tcl.display());
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
|
||||
@@ -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 = []
|
||||
18
zynq/.cargo/config.toml
Normal file
18
zynq/.cargo/config.toml
Normal file
@@ -0,0 +1,18 @@
|
||||
[target.armv7a-none-eabihf]
|
||||
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
1
zynq/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
Cargo.lock
|
||||
21
zynq/Cargo.toml
Normal file
21
zynq/Cargo.toml
Normal 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",
|
||||
]
|
||||
@@ -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
|
||||
@@ -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 {
|
||||
@@ -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 _;
|
||||
|
||||
@@ -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"
|
||||
@@ -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"
|
||||
@@ -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 _;
|
||||
|
||||
@@ -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 _;
|
||||
|
||||
@@ -1,3 +1,2 @@
|
||||
[toolchain]
|
||||
# channel = "stable"
|
||||
channel = "nightly"
|
||||
@@ -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 {
|
||||
}
|
||||
};
|
||||
|
||||
// Immediately fill the FIFO again with the remaining 8 bytes.
|
||||
wait_for_tx_slot(&mut transfer);
|
||||
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(
|
||||
data[current_byte_index..current_byte_index + 4]
|
||||
.try_into()
|
||||
.unwrap(),
|
||||
));
|
||||
current_byte_index += 4;
|
||||
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);
|
||||
@@ -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"
|
||||
@@ -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,9 +17,9 @@ 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},
|
||||
};
|
||||
@@ -80,35 +81,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 +120,7 @@ pub fn main() -> ! {
|
||||
|
||||
info!("Configuring DDR..");
|
||||
configure_ddr_for_ddr3(
|
||||
dp.ddrc,
|
||||
periphs.ddrc,
|
||||
boot_mode,
|
||||
DdrClockSetupConfig {
|
||||
ps_clk: PS_CLK,
|
||||
@@ -132,9 +135,11 @@ pub fn main() -> ! {
|
||||
|
||||
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 +159,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 +173,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 +194,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,45 +208,126 @@ 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() {
|
||||
match dest_dev {
|
||||
DestinationDevice::Pl => {
|
||||
info!("Loading image '{name}' to PL (FPGA)..");
|
||||
// TODO: Load the bitstream.
|
||||
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)..");
|
||||
// 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 => {
|
||||
// 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");
|
||||
}
|
||||
DestinationDevice::Ps => {
|
||||
// TODO: Load the binary into DDR. Jump at lowest load address after all
|
||||
// partitions were parsed.
|
||||
}
|
||||
_ => {
|
||||
error!("Unsupported destination device {dest_dev:?}");
|
||||
continue;
|
||||
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:?}");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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!"),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
31
zynq/zedboard-qspi-flasher/build.rs
Normal file
31
zynq/zedboard-qspi-flasher/build.rs
Normal 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");
|
||||
}
|
||||
22
zynq/zedboard-qspi-flasher/memory.x
Normal file
22
zynq/zedboard-qspi-flasher/memory.x
Normal file
@@ -0,0 +1,22 @@
|
||||
MEMORY
|
||||
{
|
||||
/* Zedboard: 512 MB DDR3. Only use 63 MB for now, should be plenty for a bare-metal app.
|
||||
Leave 1 MB of memory which will be configured as uncached device memory by the MMU. This is
|
||||
recommended for something like DMA descriptors. */
|
||||
CODE(rx) : ORIGIN = 0x00100000, LENGTH = 63M
|
||||
UNCACHED(rx): ORIGIN = 0x4000000, LENGTH = 1M
|
||||
}
|
||||
|
||||
REGION_ALIAS("DATA", CODE);
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
/* Uncached memory */
|
||||
.uncached (NOLOAD) : ALIGN(4) {
|
||||
. = ALIGN(4);
|
||||
_sbss_uncached = .;
|
||||
*(.uncached .uncached.*);
|
||||
. = ALIGN(4);
|
||||
_ebss_uncached = .;
|
||||
} > UNCACHED
|
||||
}
|
||||
151
zynq/zedboard-qspi-flasher/qspi-flasher.tcl
Normal file
151
zynq/zedboard-qspi-flasher/qspi-flasher.tcl
Normal 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"
|
||||
@@ -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 {
|
||||
@@ -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"]
|
||||
@@ -14,8 +14,8 @@ extern crate alloc;
|
||||
|
||||
use slcr::Slcr;
|
||||
use zynq7000::{
|
||||
slcr::{BootModeRegister, BootPllConfig, LevelShifterRegister},
|
||||
SpiClockPhase, SpiClockPolarity,
|
||||
slcr::{BootModeRegister, BootPllConfig, LevelShifterRegister},
|
||||
};
|
||||
|
||||
pub mod cache;
|
||||
@@ -1,13 +1,23 @@
|
||||
//! # Simple logging providers.
|
||||
|
||||
use core::sync::atomic::{AtomicBool, AtomicU8};
|
||||
|
||||
static LOGGER_INIT_DONE: AtomicBool = AtomicBool::new(false);
|
||||
|
||||
const LOG_SEL_LOCKED: u8 = 1;
|
||||
const LOG_SEL_UNSAFE_SINGLE_CORE: u8 = 2;
|
||||
|
||||
static LOG_SEL: AtomicU8 = AtomicU8::new(0);
|
||||
|
||||
/// Blocking UART loggers.
|
||||
pub mod uart_blocking {
|
||||
use super::*;
|
||||
use core::cell::{Cell, RefCell, UnsafeCell};
|
||||
use embedded_io::Write as _;
|
||||
|
||||
use cortex_ar::register::Cpsr;
|
||||
use critical_section::Mutex;
|
||||
use log::{LevelFilter, set_logger, set_max_level};
|
||||
use log::{LevelFilter, Log, set_logger, set_max_level};
|
||||
|
||||
use crate::uart::Uart;
|
||||
|
||||
@@ -27,7 +37,10 @@ pub mod uart_blocking {
|
||||
/// For async applications, it is strongly recommended to use the asynchronous ring buffer
|
||||
/// logger instead.
|
||||
pub fn init_with_locks(uart: Uart, level: LevelFilter) {
|
||||
// TODO: Impl debug for Uart
|
||||
if LOGGER_INIT_DONE.swap(true, core::sync::atomic::Ordering::Relaxed) {
|
||||
return;
|
||||
}
|
||||
LOG_SEL.swap(LOG_SEL_LOCKED, core::sync::atomic::Ordering::Relaxed);
|
||||
critical_section::with(|cs| {
|
||||
let inner = UART_LOGGER_BLOCKING.0.borrow(cs);
|
||||
inner.replace(Some(uart));
|
||||
@@ -53,7 +66,16 @@ pub mod uart_blocking {
|
||||
})
|
||||
}
|
||||
|
||||
fn flush(&self) {}
|
||||
fn flush(&self) {
|
||||
critical_section::with(|cs| {
|
||||
let mut opt_logger = self.0.borrow(cs).borrow_mut();
|
||||
if opt_logger.is_none() {
|
||||
return;
|
||||
}
|
||||
let logger = opt_logger.as_mut().unwrap();
|
||||
logger.flush().unwrap();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
pub struct UartLoggerUnsafeSingleThread {
|
||||
@@ -70,23 +92,6 @@ pub mod uart_blocking {
|
||||
uart: UnsafeCell::new(None),
|
||||
};
|
||||
|
||||
/// Initialize the logger with a blocking UART instance.
|
||||
///
|
||||
/// For async applications, it is strongly recommended to use the asynchronous ring buffer
|
||||
/// logger instead.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This is a blocking logger which performs a write WITHOUT a critical section. This logger is
|
||||
/// NOT thread-safe. Users must ensure that this logger is not used inside a pre-emptive
|
||||
/// multi-threading context and interrupt handlers.
|
||||
pub unsafe fn create_unsafe_single_thread_logger(uart: Uart) -> UartLoggerUnsafeSingleThread {
|
||||
UartLoggerUnsafeSingleThread {
|
||||
skip_in_isr: Cell::new(false),
|
||||
uart: UnsafeCell::new(Some(uart)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Initialize the logger with a blocking UART instance which does not use locks.
|
||||
///
|
||||
/// # Safety
|
||||
@@ -95,6 +100,13 @@ pub mod uart_blocking {
|
||||
/// NOT thread-safe, which might lead to garbled output. Log output in ISRs can optionally be
|
||||
/// surpressed.
|
||||
pub unsafe fn init_unsafe_single_core(uart: Uart, level: LevelFilter, skip_in_isr: bool) {
|
||||
if LOGGER_INIT_DONE.swap(true, core::sync::atomic::Ordering::Relaxed) {
|
||||
return;
|
||||
}
|
||||
LOG_SEL.swap(
|
||||
LOG_SEL_UNSAFE_SINGLE_CORE,
|
||||
core::sync::atomic::Ordering::Relaxed,
|
||||
);
|
||||
let opt_uart = unsafe { &mut *UART_LOGGER_UNSAFE_SINGLE_THREAD.uart.get() };
|
||||
opt_uart.replace(uart);
|
||||
UART_LOGGER_UNSAFE_SINGLE_THREAD
|
||||
@@ -134,7 +146,22 @@ pub mod uart_blocking {
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
fn flush(&self) {}
|
||||
fn flush(&self) {
|
||||
let uart_mut = unsafe { &mut *self.uart.get() }.as_mut();
|
||||
if uart_mut.is_none() {
|
||||
return;
|
||||
}
|
||||
uart_mut.unwrap().flush().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
// Flush the selected logger instance.
|
||||
pub fn flush() {
|
||||
match LOG_SEL.load(core::sync::atomic::Ordering::Relaxed) {
|
||||
val if val == LOG_SEL_LOCKED => UART_LOGGER_BLOCKING.flush(),
|
||||
val if val == LOG_SEL_UNSAFE_SINGLE_CORE => UART_LOGGER_UNSAFE_SINGLE_THREAD.flush(),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -205,6 +232,9 @@ pub mod rb {
|
||||
}
|
||||
|
||||
pub fn init(level: LevelFilter) {
|
||||
if super::LOGGER_INIT_DONE.swap(true, core::sync::atomic::Ordering::Relaxed) {
|
||||
return;
|
||||
}
|
||||
critical_section::with(|cs| {
|
||||
let rb = StaticRb::<u8, 4096>::default();
|
||||
let rb_ref = LOGGER_RB.ring_buf.borrow(cs);
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user