Compare commits
8 Commits
Author | SHA1 | Date |
---|---|---|
Astro | cd8abae839 | |
Astro | 77c3998dbd | |
Astro | 5c0953d869 | |
Astro | 1121c67a4e | |
Astro | fb4022f04d | |
Astro | c72402b966 | |
Astro | f76e9321d7 | |
Astro | 875bc74df9 |
|
@ -1,4 +1,5 @@
|
||||||
[target.armv7-none-eabihf]
|
[target.armv7-none-eabihf]
|
||||||
|
runner = "./runner.sh"
|
||||||
rustflags = [
|
rustflags = [
|
||||||
"-C", "link-arg=-Tlink.x",
|
"-C", "link-arg=-Tlink.x",
|
||||||
"-C", "target-feature=a9,armv7-a,neon",
|
"-C", "target-feature=a9,armv7-a,neon",
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bit_field"
|
name = "bit_field"
|
||||||
version = "0.10.1"
|
version = "0.10.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -22,22 +22,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "compiler_builtins"
|
name = "compiler_builtins"
|
||||||
version = "0.1.35"
|
version = "0.1.27"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "core_io"
|
|
||||||
version = "0.1.20200410"
|
|
||||||
dependencies = [
|
|
||||||
"memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "embedded-hal"
|
name = "embedded-hal"
|
||||||
version = "0.2.4"
|
version = "0.2.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"nb 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"nb 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -45,33 +38,22 @@ dependencies = [
|
||||||
name = "experiments"
|
name = "experiments"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"embedded-hal 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"embedded-hal 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libasync 0.0.0",
|
"libasync 0.0.0",
|
||||||
"libboard_zynq 0.0.0",
|
"libboard_zynq 0.0.0",
|
||||||
"libcortex_a9 0.0.0",
|
"libcortex_a9 0.0.0",
|
||||||
"libregister 0.0.0",
|
"libregister 0.0.0",
|
||||||
"libsupport_zynq 0.0.0",
|
"libsupport_zynq 0.0.0",
|
||||||
"log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "fatfs"
|
|
||||||
version = "0.3.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"core_io 0.1.20200410",
|
|
||||||
"log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libasync"
|
name = "libasync"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"embedded-hal 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"embedded-hal 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libcortex_a9 0.0.0",
|
"libcortex_a9 0.0.0",
|
||||||
"nb 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"nb 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"pin-utils 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"pin-utils 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"smoltcp 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"smoltcp 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
@ -80,32 +62,22 @@ dependencies = [
|
||||||
name = "libboard_zynq"
|
name = "libboard_zynq"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bit_field 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bit_field 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"embedded-hal 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"embedded-hal 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libcortex_a9 0.0.0",
|
"libcortex_a9 0.0.0",
|
||||||
"libregister 0.0.0",
|
"libregister 0.0.0",
|
||||||
"log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"nb 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"nb 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"smoltcp 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"smoltcp 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"volatile-register 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"volatile-register 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "libconfig"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"core_io 0.1.20200410",
|
|
||||||
"fatfs 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"libboard_zynq 0.0.0",
|
|
||||||
"log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libcortex_a9"
|
name = "libcortex_a9"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bit_field 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bit_field 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libregister 0.0.0",
|
"libregister 0.0.0",
|
||||||
"volatile-register 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"volatile-register 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
@ -114,7 +86,7 @@ dependencies = [
|
||||||
name = "libregister"
|
name = "libregister"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bit_field 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bit_field 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"vcell 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"vcell 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"volatile-register 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"volatile-register 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
@ -123,22 +95,22 @@ dependencies = [
|
||||||
name = "libsupport_zynq"
|
name = "libsupport_zynq"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"compiler_builtins 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
"compiler_builtins 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libboard_zynq 0.0.0",
|
"libboard_zynq 0.0.0",
|
||||||
"libcortex_a9 0.0.0",
|
"libcortex_a9 0.0.0",
|
||||||
"libregister 0.0.0",
|
"libregister 0.0.0",
|
||||||
"linked_list_allocator 0.8.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"linked_list_allocator 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"r0 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"r0 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "linked_list_allocator"
|
name = "linked_list_allocator"
|
||||||
version = "0.8.5"
|
version = "0.8.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "log"
|
name = "log"
|
||||||
version = "0.4.11"
|
version = "0.4.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -146,25 +118,12 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "managed"
|
name = "managed"
|
||||||
version = "0.7.2"
|
version = "0.7.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "memchr"
|
|
||||||
version = "2.3.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nb"
|
name = "nb"
|
||||||
version = "0.1.3"
|
version = "0.1.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
dependencies = [
|
|
||||||
"nb 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "nb"
|
|
||||||
version = "1.0.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -184,21 +143,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"managed 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"managed 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "szl"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"core_io 0.1.20200410",
|
|
||||||
"libboard_zynq 0.0.0",
|
|
||||||
"libconfig 0.1.0",
|
|
||||||
"libcortex_a9 0.0.0",
|
|
||||||
"libregister 0.0.0",
|
|
||||||
"libsupport_zynq 0.0.0",
|
|
||||||
"log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -220,19 +165,16 @@ dependencies = [
|
||||||
]
|
]
|
||||||
|
|
||||||
[metadata]
|
[metadata]
|
||||||
"checksum bit_field 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dcb6dd1c2376d2e096796e234a70e17e94cc2d5d54ff8ce42b28cef1d0d359a4"
|
"checksum bit_field 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a165d606cf084741d4ac3a28fb6e9b1eb0bd31f6cd999098cfddb0b2ab381dc0"
|
||||||
"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
||||||
"checksum byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
|
"checksum byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
|
||||||
"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
||||||
"checksum compiler_builtins 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "e3fcd8aba10d17504c87ef12d4f62ef404c6a4703d16682a9eb5543e6cf24455"
|
"checksum compiler_builtins 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)" = "38f18416546abfbf8d801c555a0e99524453e7214f9cc9107ad49de3d5948ccc"
|
||||||
"checksum embedded-hal 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "fa998ce59ec9765d15216393af37a58961ddcefb14c753b4816ba2191d865fcb"
|
"checksum embedded-hal 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ee4908a155094da7723c2d60d617b820061e3b4efcc3d9e293d206a5a76c170b"
|
||||||
"checksum fatfs 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "93079df23039e52059e1f03b4c29fb0c72da2c792aad91bb2236c9fb81d3592e"
|
"checksum linked_list_allocator 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d6b60501dd4c850950bb43f970d544f6ce04e0ca021da2db2538fbe9d923f19e"
|
||||||
"checksum linked_list_allocator 0.8.5 (registry+https://github.com/rust-lang/crates.io-index)" = "660b26e6156a7d00eefb19052fe1943cf5ab2f353a723a577fad6ba2f99d1f90"
|
"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
|
||||||
"checksum log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b"
|
"checksum managed 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fdcec5e97041c7f0f1c5b7d93f12e57293c831c646f4cc7a5db59460c7ea8de6"
|
||||||
"checksum managed 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c75de51135344a4f8ed3cfe2720dc27736f7711989703a0b43aadf3753c55577"
|
"checksum nb 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b1411551beb3c11dedfb0a90a0fa256b47d28b9ec2cdff34c25a2fa59e45dbdc"
|
||||||
"checksum memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400"
|
|
||||||
"checksum nb 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f"
|
|
||||||
"checksum nb 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "546c37ac5d9e56f55e73b677106873d9d9f5190605e41a856503623648488cae"
|
|
||||||
"checksum pin-utils 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
"checksum pin-utils 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||||
"checksum r0 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bd7a31eed1591dcbc95d92ad7161908e72f4677f8fabf2a32ca49b4237cbf211"
|
"checksum r0 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bd7a31eed1591dcbc95d92ad7161908e72f4677f8fabf2a32ca49b4237cbf211"
|
||||||
"checksum smoltcp 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0fe46639fd2ec79eadf8fe719f237a7a0bd4dac5d957f1ca5bbdbc1c3c39e53a"
|
"checksum smoltcp 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0fe46639fd2ec79eadf8fe719f237a7a0bd4dac5d957f1ca5bbdbc1c3c39e53a"
|
||||||
|
|
23
Cargo.toml
23
Cargo.toml
|
@ -1,24 +1,19 @@
|
||||||
[workspace]
|
[workspace]
|
||||||
members = [
|
members = [
|
||||||
"libregister",
|
"libregister", "libcortex_a9",
|
||||||
"libcortex_a9",
|
"libboard_zynq", "libsupport_zynq",
|
||||||
"libboard_zynq",
|
|
||||||
"libsupport_zynq",
|
|
||||||
"libasync",
|
"libasync",
|
||||||
"libconfig",
|
|
||||||
"libcoreio",
|
|
||||||
"experiments",
|
"experiments",
|
||||||
"szl",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[profile.dev]
|
||||||
|
panic = "abort"
|
||||||
|
lto = false
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
panic = "abort"
|
panic = "abort"
|
||||||
debug = true
|
debug = true
|
||||||
codegen-units = 1
|
# Link-Time Optimization:
|
||||||
opt-level = 'z'
|
# turn off if you get unusable debug symbols.
|
||||||
lto = true
|
lto = true
|
||||||
debug-assertions = false
|
opt-level = 'z' # Optimize for size.
|
||||||
overflow-checks = false
|
|
||||||
|
|
||||||
[patch.crates-io]
|
|
||||||
core_io = { path = "./libcoreio" }
|
|
||||||
|
|
80
README.md
80
README.md
|
@ -1,22 +1,52 @@
|
||||||
# Build
|
# Build
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
nix-shell --command "cargo xbuild --release -p experiments"
|
nix-shell --command "cargo xbuild --release"
|
||||||
```
|
```
|
||||||
|
|
||||||
Currently the ELF output is placed at `target/armv7-none-eabihf/release/experiments`
|
Currently the ELF output is placed at `target/armv7-none-eabihf/release/experiments`
|
||||||
|
|
||||||
# Debug
|
# Debug
|
||||||
|
|
||||||
## Running on the ZC706
|
## Using the Xilinx toolchain
|
||||||
|
|
||||||
|
Tested with the ZC706 board.
|
||||||
|
|
||||||
|
Run the Xilinx Microprocessor Debugger:
|
||||||
|
```shell
|
||||||
|
/opt/Xilinx/14.7/ISE_DS/EDK/bin/lin64/xmd
|
||||||
|
```
|
||||||
|
|
||||||
|
Connect to target (given it is connected and you have permissions):
|
||||||
|
```tcl
|
||||||
|
connect arm hw
|
||||||
|
```
|
||||||
|
|
||||||
|
Leave xmd running.
|
||||||
|
|
||||||
|
Start the Xilinx version of the GNU debugger with your latest build:
|
||||||
|
```shell
|
||||||
|
/opt/Xilinx/14.7/ISE_DS/EDK/gnu/arm/lin/bin/arm-xilinx-linux-gnueabi-gdb zc706
|
||||||
|
```
|
||||||
|
|
||||||
|
Connect the debugger to xmd over TCP on localhost:
|
||||||
|
```gdb
|
||||||
|
target remote :1234
|
||||||
|
```
|
||||||
|
|
||||||
|
Proceed using gdb with `load`, `c`
|
||||||
|
|
||||||
|
## Using OpenOCD
|
||||||
|
|
||||||
|
### Running on the ZC706
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
nix-shell --command "cargo xbuild --release -p experiments"
|
nix-shell --command "cargo xbuild --release"
|
||||||
cd openocd
|
cd openocd
|
||||||
openocd -f zc706.cfg
|
openocd -f zc706.cfg
|
||||||
```
|
```
|
||||||
|
|
||||||
## Running on the Cora Z7-10
|
### Running on the Cora Z7-10
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
nix-shell --command "cd experiments && cargo xbuild --release --no-default-features --features=target_cora_z7_10"
|
nix-shell --command "cd experiments && cargo xbuild --release --no-default-features --features=target_cora_z7_10"
|
||||||
|
@ -24,8 +54,46 @@ cd openocd
|
||||||
openocd -f cora-z7-10.cfg
|
openocd -f cora-z7-10.cfg
|
||||||
```
|
```
|
||||||
|
|
||||||
## Loading a bitstream into volatile memory
|
### Loading a bitstream into volatile memory
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
openocd -f zc706.cfg -c "pld load 0 blinker_migen.bit; exit"
|
openocd -f zc706.cfg -c "pld load 0 blinker_migen.bit; exit"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Development Process
|
||||||
|
|
||||||
|
Clone this repo onto your development/build machine and the raspberry pi that controls the Xilinx 7000 board
|
||||||
|
|
||||||
|
On the dev machine, the below script builds zc706 and secure copies it to the target pi (in your pi $HOME directory)
|
||||||
|
```shell
|
||||||
|
cd ~/zc706
|
||||||
|
./build.sh $your_user/ssh_id
|
||||||
|
```
|
||||||
|
|
||||||
|
On the pi, we need an information rich environment that includes a relatively reliable `gdb` experience (that includes `ctrl-p` and `ctrl-n` command history that persists across `cgdb` executions), run:
|
||||||
|
```shell
|
||||||
|
ssh pi4
|
||||||
|
cd zc706
|
||||||
|
./tmux.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Time to run your code with:
|
||||||
|
```shell
|
||||||
|
zynq-connect
|
||||||
|
zynq-restart
|
||||||
|
c
|
||||||
|
```
|
||||||
|
or, for a more succinct experience, (identical to above)
|
||||||
|
```shell
|
||||||
|
dc
|
||||||
|
dr
|
||||||
|
c
|
||||||
|
```
|
||||||
|
|
||||||
|
After every build on your dev machine, simply run:
|
||||||
|
```shell
|
||||||
|
dr
|
||||||
|
c
|
||||||
|
```
|
||||||
|
Sometimes you might need to type `load` after `dr`.
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
"emit-debug-gdb-scripts": false,
|
"emit-debug-gdb-scripts": false,
|
||||||
"env": "",
|
"env": "",
|
||||||
"executables": true,
|
"executables": true,
|
||||||
"features": "+v7,+vfp3,-d32,+thumb2,-neon",
|
"features": "+v7,+vfp3,-d32,+thumb2,-neon,+strict-align",
|
||||||
"is-builtin": false,
|
"is-builtin": false,
|
||||||
"linker": "rust-lld",
|
"linker": "rust-lld",
|
||||||
"linker-flavor": "ld.lld",
|
"linker-flavor": "ld.lld",
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
nix-shell --command "cargo xbuild --release" && scp -P 2204 -C target/armv7-none-eabihf/release/zc706-experiments $1@nixbld.m-labs.hk:/home/$1/zc706/zc706.elf
|
File diff suppressed because it is too large
Load Diff
83
default.nix
83
default.nix
|
@ -1,38 +1,63 @@
|
||||||
|
{ # Use master branch of the overlay by default
|
||||||
|
mozillaOverlay ? import (builtins.fetchTarball https://github.com/mozilla/nixpkgs-mozilla/archive/master.tar.gz),
|
||||||
|
rustManifest ? ./channel-rust-nightly.toml,
|
||||||
|
}:
|
||||||
|
|
||||||
let
|
let
|
||||||
pkgs = import <nixpkgs> { overlays = [ (import ./nix/mozilla-overlay.nix) ]; };
|
pkgs = import <nixpkgs> { overlays = [ mozillaOverlay ]; };
|
||||||
rustPlatform = (import ./nix/rust-platform.nix { inherit pkgs; });
|
rustcSrc = pkgs.fetchgit {
|
||||||
build-crate = name: crate: features:
|
url = https://github.com/rust-lang/rust.git;
|
||||||
rustPlatform.buildRustPackage rec {
|
# master of 2020-04-25
|
||||||
name = "${crate}";
|
rev = "14b15521c52549ebbb113173b4abecd124b5a823";
|
||||||
|
sha256 = "0a6bi8g636cajpdrpcfkpza95b7ss7041m9cs6hxcd7h8bf6xhwi";
|
||||||
src = ./.;
|
fetchSubmodules = true;
|
||||||
cargoSha256 = "1f2psa1g41pl2j8n60hhik2s2pqdfjhr5capimvajf81kxrnn2ck";
|
};
|
||||||
|
targets = [];
|
||||||
nativeBuildInputs = [ pkgs.cargo-xbuild ];
|
rustChannelOfTargets = _channel: _date: targets:
|
||||||
|
(pkgs.lib.rustLib.fromManifestFile rustManifest {
|
||||||
|
inherit (pkgs) stdenv fetchurl patchelf;
|
||||||
|
}).rust.override { inherit targets; };
|
||||||
|
rust =
|
||||||
|
rustChannelOfTargets "nightly" null targets;
|
||||||
|
rustPlatform = pkgs.recurseIntoAttrs (pkgs.makeRustPlatform {
|
||||||
|
rustc = rust // { src = rustcSrc; };
|
||||||
|
cargo = rust;
|
||||||
|
});
|
||||||
|
gcc = pkgs.pkgsCross.armv7l-hf-multiplatform.buildPackages.gcc;
|
||||||
|
xbuildRustPackage = { cargoFeatures, crateSubdir, ... } @ attrs:
|
||||||
|
let
|
||||||
|
buildPkg = rustPlatform.buildRustPackage attrs;
|
||||||
|
in
|
||||||
|
buildPkg.overrideAttrs ({ name, nativeBuildInputs, ... }: {
|
||||||
|
nativeBuildInputs =
|
||||||
|
nativeBuildInputs ++ [ pkgs.cargo-xbuild ];
|
||||||
buildPhase = ''
|
buildPhase = ''
|
||||||
export XARGO_RUST_SRC="${rustPlatform.rust.rustc.src}/src"
|
pushd ${crateSubdir}
|
||||||
export CARGO_HOME=$(mktemp -d cargo-home.XXX)
|
|
||||||
pushd ${crate}
|
|
||||||
cargo xbuild --release --frozen \
|
cargo xbuild --release --frozen \
|
||||||
--no-default-features \
|
--no-default-features \
|
||||||
--features=${features}
|
--features=${cargoFeatures}
|
||||||
popd
|
popd
|
||||||
'';
|
'';
|
||||||
|
XARGO_RUST_SRC = "${rustcSrc}/src";
|
||||||
installPhase = ''
|
installPhase = ''
|
||||||
mkdir -p $out $out/nix-support
|
mkdir $out
|
||||||
|
ls -la target/armv7-none-eabihf/release/
|
||||||
cp target/armv7-none-eabihf/release/${name} $out/${name}.elf
|
cp target/armv7-none-eabihf/release/${name} $out/${name}.elf
|
||||||
echo file binary-dist $out/${name}.elf >> $out/nix-support/hydra-build-products
|
|
||||||
'';
|
'';
|
||||||
|
});
|
||||||
doCheck = false;
|
xbuildCrate = name: crate: features: xbuildRustPackage rec {
|
||||||
dontFixup = true;
|
name = "${crate}";
|
||||||
};
|
src = ./.;
|
||||||
in
|
crateSubdir = crate;
|
||||||
{
|
cargoSha256 = "0xlynsr94dyv0g41qwk5490w3wnzd5g70msaih6mcbgr3v4s2q34";
|
||||||
zc706-experiments = build-crate "zc706-experiments" "experiments" "target_zc706";
|
cargoFeatures = features;
|
||||||
cora-experiments = build-crate "cora-experiments" "experiments" "target_cora_z7_10";
|
doCheck = false;
|
||||||
redpitaya-experiments = build-crate "redpitaya-experiments" "experiments" "target_redpitaya";
|
dontFixup = true;
|
||||||
zc706-fsbl = (import ./nix/fsbl.nix { inherit pkgs; });
|
};
|
||||||
zc706-szl = build-crate "zc706-szl" "szl" "target_zc706";
|
in {
|
||||||
}
|
inherit pkgs rustPlatform rustcSrc gcc;
|
||||||
|
zc706 = {
|
||||||
|
experiments-zc706 = xbuildCrate "experiments-zc706" "experiments" "target_zc706";
|
||||||
|
experiments-cora = xbuildCrate "experiments-cora" "experiments" "target_cora_z7_10";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
@ -2,13 +2,12 @@
|
||||||
name = "experiments"
|
name = "experiments"
|
||||||
description = "Developing bare-metal Rust on Zynq"
|
description = "Developing bare-metal Rust on Zynq"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
authors = ["M-Labs"]
|
authors = ["Astro <astro@spaceboyz.net>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
target_zc706 = ["libboard_zynq/target_zc706", "libsupport_zynq/target_zc706"]
|
target_zc706 = ["libboard_zynq/target_zc706", "libsupport_zynq/target_zc706"]
|
||||||
target_cora_z7_10 = ["libboard_zynq/target_cora_z7_10", "libsupport_zynq/target_cora_z7_10"]
|
target_cora_z7_10 = ["libboard_zynq/target_cora_z7_10", "libsupport_zynq/target_cora_z7_10"]
|
||||||
target_redpitaya = ["libboard_zynq/target_redpitaya", "libsupport_zynq/target_redpitaya"]
|
|
||||||
default = ["target_zc706"]
|
default = ["target_zc706"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
@ -17,5 +16,5 @@ embedded-hal = "0.2"
|
||||||
libregister = { path = "../libregister" }
|
libregister = { path = "../libregister" }
|
||||||
libcortex_a9 = { path = "../libcortex_a9" }
|
libcortex_a9 = { path = "../libcortex_a9" }
|
||||||
libboard_zynq = { path = "../libboard_zynq" }
|
libboard_zynq = { path = "../libboard_zynq" }
|
||||||
libsupport_zynq = { path = "../libsupport_zynq", default-features = false, features = ["panic_handler"]}
|
libsupport_zynq = { path = "../libsupport_zynq" }
|
||||||
libasync = { path = "../libasync" }
|
libasync = { path = "../libasync" }
|
||||||
|
|
|
@ -1,4 +1,14 @@
|
||||||
ENTRY(Reset);
|
ENTRY(_boot_cores);
|
||||||
|
|
||||||
|
/* Provide some defaults */
|
||||||
|
PROVIDE(Reset = _boot_cores);
|
||||||
|
PROVIDE(UndefinedInstruction = Reset);
|
||||||
|
PROVIDE(SoftwareInterrupt = Reset);
|
||||||
|
PROVIDE(PrefetchAbort = Reset);
|
||||||
|
PROVIDE(DataAbort = Reset);
|
||||||
|
PROVIDE(ReservedException = Reset);
|
||||||
|
PROVIDE(IRQ = Reset);
|
||||||
|
PROVIDE(FIQ = Reset);
|
||||||
|
|
||||||
MEMORY
|
MEMORY
|
||||||
{
|
{
|
||||||
|
@ -32,23 +42,19 @@ SECTIONS
|
||||||
*(.bss .bss.*);
|
*(.bss .bss.*);
|
||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
__bss_end = .;
|
__bss_end = .;
|
||||||
} > OCM3
|
} > OCM
|
||||||
|
|
||||||
.stack1 (NOLOAD) : ALIGN(8) {
|
.stack1 (NOLOAD) : ALIGN(8) {
|
||||||
__stack1_end = .;
|
__stack1_end = .;
|
||||||
. += 0x200;
|
. += 0x200;
|
||||||
__stack1_start = .;
|
__stack1_start = .;
|
||||||
} > OCM3
|
} > OCM
|
||||||
|
|
||||||
.stack0 (NOLOAD) : ALIGN(8) {
|
.stack0 (NOLOAD) : ALIGN(8) {
|
||||||
__stack0_end = .;
|
__stack0_end = .;
|
||||||
. = ORIGIN(OCM3) + LENGTH(OCM3) - 8;
|
. = ORIGIN(OCM) + LENGTH(OCM) - 8;
|
||||||
__stack0_start = .;
|
__stack0_start = .;
|
||||||
|
} > OCM
|
||||||
/* unused heap0 to prevent the linker from complaining*/
|
|
||||||
__heap0_start = .;
|
|
||||||
__heap0_end = .;
|
|
||||||
} > OCM3
|
|
||||||
|
|
||||||
/DISCARD/ :
|
/DISCARD/ :
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![feature(const_in_array_repeat_expressions)]
|
|
||||||
#![feature(naked_functions)]
|
|
||||||
|
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
use alloc::collections::BTreeMap;
|
use alloc::{borrow::ToOwned, collections::BTreeMap, format};
|
||||||
|
use core::task::Poll;
|
||||||
use libasync::{
|
use libasync::{
|
||||||
delay,
|
delay,
|
||||||
smoltcp::{Sockets, TcpStream},
|
smoltcp::{Sockets, TcpStream},
|
||||||
|
@ -15,93 +14,42 @@ use libboard_zynq::{
|
||||||
self as zynq,
|
self as zynq,
|
||||||
clocks::source::{ArmPll, ClockSource, IoPll},
|
clocks::source::{ArmPll, ClockSource, IoPll},
|
||||||
clocks::Clocks,
|
clocks::Clocks,
|
||||||
println, stdio,
|
print, println,
|
||||||
mpcore,
|
setup_l2cache,
|
||||||
gic,
|
sdio::sd_card::SdCard,
|
||||||
smoltcp::{
|
smoltcp::{
|
||||||
|
self,
|
||||||
iface::{EthernetInterfaceBuilder, NeighborCache, Routes},
|
iface::{EthernetInterfaceBuilder, NeighborCache, Routes},
|
||||||
time::Instant,
|
time::Instant,
|
||||||
wire::{EthernetAddress, IpAddress, IpCidr},
|
wire::{EthernetAddress, IpAddress, IpCidr},
|
||||||
},
|
},
|
||||||
time::Milliseconds,
|
time::Milliseconds,
|
||||||
};
|
};
|
||||||
#[cfg(feature = "target_zc706")]
|
|
||||||
use libboard_zynq::print;
|
|
||||||
use libcortex_a9::{
|
use libcortex_a9::{
|
||||||
mutex::Mutex,
|
mutex::Mutex,
|
||||||
l2c::enable_l2_cache,
|
sync_channel::{self, sync_channel},
|
||||||
sync_channel::{Sender, Receiver},
|
|
||||||
sync_channel,
|
|
||||||
regs::{MPIDR, SP},
|
|
||||||
spin_lock_yield, notify_spin_lock,
|
|
||||||
asm
|
|
||||||
};
|
};
|
||||||
use libregister::{RegisterR, RegisterW};
|
use libregister::RegisterR;
|
||||||
use libsupport_zynq::{
|
use libsupport_zynq::{
|
||||||
boot, ram,
|
boot, ram,
|
||||||
};
|
};
|
||||||
use log::{info, warn};
|
use log::{info, warn};
|
||||||
use core::sync::atomic::{AtomicBool, Ordering};
|
|
||||||
|
mod ps7_init;
|
||||||
|
|
||||||
const HWADDR: [u8; 6] = [0, 0x23, 0xde, 0xea, 0xbe, 0xef];
|
const HWADDR: [u8; 6] = [0, 0x23, 0xde, 0xea, 0xbe, 0xef];
|
||||||
|
|
||||||
static mut CORE1_REQ: (Sender<usize>, Receiver<usize>) = sync_channel!(usize, 10);
|
|
||||||
static mut CORE1_RES: (Sender<usize>, Receiver<usize>) = sync_channel!(usize, 10);
|
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
static mut __stack1_start: u32;
|
|
||||||
}
|
|
||||||
|
|
||||||
static CORE1_RESTART: AtomicBool = AtomicBool::new(false);
|
|
||||||
|
|
||||||
#[link_section = ".text.boot"]
|
|
||||||
#[no_mangle]
|
|
||||||
#[naked]
|
|
||||||
pub unsafe extern "C" fn IRQ() {
|
|
||||||
if MPIDR.read().cpu_id() == 1{
|
|
||||||
let mpcore = mpcore::RegisterBlock::mpcore();
|
|
||||||
let mut gic = gic::InterruptController::gic(mpcore);
|
|
||||||
let id = gic.get_interrupt_id();
|
|
||||||
if id.0 == 0 {
|
|
||||||
gic.end_interrupt(id);
|
|
||||||
asm::exit_irq();
|
|
||||||
SP.write(&mut __stack1_start as *mut _ as u32);
|
|
||||||
asm::enable_irq();
|
|
||||||
CORE1_RESTART.store(false, Ordering::Relaxed);
|
|
||||||
notify_spin_lock();
|
|
||||||
main_core1();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stdio::drop_uart();
|
|
||||||
println!("IRQ");
|
|
||||||
loop {}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn restart_core1() {
|
|
||||||
let mut interrupt_controller = gic::InterruptController::gic(mpcore::RegisterBlock::mpcore());
|
|
||||||
CORE1_RESTART.store(true, Ordering::Relaxed);
|
|
||||||
interrupt_controller.send_sgi(gic::InterruptId(0), gic::CPUCore::Core1.into());
|
|
||||||
while CORE1_RESTART.load(Ordering::Relaxed) {
|
|
||||||
spin_lock_yield();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub fn main_core0() {
|
pub fn main_core0() {
|
||||||
// zynq::clocks::CpuClocks::enable_io(1_250_000_000);
|
// zynq::clocks::CpuClocks::enable_io(1_250_000_000);
|
||||||
enable_l2_cache();
|
println!("\nzc706 main");
|
||||||
println!("\nZynq experiments");
|
|
||||||
let mut interrupt_controller = gic::InterruptController::gic(mpcore::RegisterBlock::mpcore());
|
|
||||||
interrupt_controller.enable_interrupts();
|
|
||||||
// ps7_init::apply();
|
|
||||||
libboard_zynq::stdio::drop_uart();
|
|
||||||
|
|
||||||
libboard_zynq::logger::init().unwrap();
|
libboard_zynq::logger::init().unwrap();
|
||||||
log::set_max_level(log::LevelFilter::Trace);
|
log::set_max_level(log::LevelFilter::Trace);
|
||||||
|
|
||||||
info!(
|
info!(
|
||||||
"Boot mode: {:?}",
|
"Boot mode: {:?}",
|
||||||
zynq::slcr::RegisterBlock::slcr()
|
zynq::slcr::RegisterBlock::new()
|
||||||
.boot_mode
|
.boot_mode
|
||||||
.read()
|
.read()
|
||||||
.boot_mode_pins()
|
.boot_mode_pins()
|
||||||
|
@ -111,8 +59,6 @@ pub fn main_core0() {
|
||||||
const CPU_FREQ: u32 = 800_000_000;
|
const CPU_FREQ: u32 = 800_000_000;
|
||||||
#[cfg(feature = "target_cora_z7_10")]
|
#[cfg(feature = "target_cora_z7_10")]
|
||||||
const CPU_FREQ: u32 = 650_000_000;
|
const CPU_FREQ: u32 = 650_000_000;
|
||||||
#[cfg(feature = "target_redpitaya")]
|
|
||||||
const CPU_FREQ: u32 = 800_000_000;
|
|
||||||
|
|
||||||
info!("Setup clock sources...");
|
info!("Setup clock sources...");
|
||||||
ArmPll::setup(2 * CPU_FREQ);
|
ArmPll::setup(2 * CPU_FREQ);
|
||||||
|
@ -127,11 +73,6 @@ pub fn main_core0() {
|
||||||
IoPll::setup(1_000_000_000);
|
IoPll::setup(1_000_000_000);
|
||||||
libboard_zynq::stdio::drop_uart();
|
libboard_zynq::stdio::drop_uart();
|
||||||
}
|
}
|
||||||
#[cfg(feature = "target_redpitaya")]
|
|
||||||
{
|
|
||||||
IoPll::setup(1_000_000_000);
|
|
||||||
libboard_zynq::stdio::drop_uart();
|
|
||||||
}
|
|
||||||
info!("PLLs set up");
|
info!("PLLs set up");
|
||||||
let clocks = zynq::clocks::Clocks::get();
|
let clocks = zynq::clocks::Clocks::get();
|
||||||
info!(
|
info!(
|
||||||
|
@ -141,64 +82,109 @@ pub fn main_core0() {
|
||||||
clocks.cpu_2x(),
|
clocks.cpu_2x(),
|
||||||
clocks.cpu_1x()
|
clocks.cpu_1x()
|
||||||
);
|
);
|
||||||
|
info!("Setup L2Cache");
|
||||||
|
setup_l2cache();
|
||||||
|
info!("L2Cache done");
|
||||||
|
|
||||||
|
if false {
|
||||||
|
let sd = libboard_zynq::sdio::SDIO::sdio0(true);
|
||||||
|
// only test SD card if it is inserted
|
||||||
|
if sd.is_card_inserted() {
|
||||||
|
let result = SdCard::from_sdio(sd);
|
||||||
|
match &result {
|
||||||
|
Ok(_) => info!("OK!"),
|
||||||
|
Err(a) => info!("{}", a),
|
||||||
|
};
|
||||||
|
const SIZE: usize = 512 * 2 + 1;
|
||||||
|
let mut sd_card = result.unwrap();
|
||||||
|
{
|
||||||
|
let buffer: [u8; SIZE] = [5; SIZE];
|
||||||
|
sd_card.write_block(0x0, 2, &buffer).unwrap();
|
||||||
|
}
|
||||||
|
let mut buffer: [u8; SIZE] = [0; SIZE];
|
||||||
|
sd_card.read_block(0x1, 2, &mut buffer[1..]).unwrap();
|
||||||
|
for i in 0..buffer.len() {
|
||||||
|
info!("buffer[{}] = {}", i, buffer[i]);
|
||||||
|
}
|
||||||
|
info!("End");
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut flash = zynq::flash::Flash::new(200_000_000).linear_addressing_mode();
|
||||||
|
let flash_ram: &[u8] = unsafe { core::slice::from_raw_parts(flash.ptr(), flash.size()) };
|
||||||
|
for i in 0..=1 {
|
||||||
|
print!("Flash {}:", i);
|
||||||
|
for b in &flash_ram[(i * 16 * 1024 * 1024)..][..128] {
|
||||||
|
print!(" {:02X}", *b);
|
||||||
|
}
|
||||||
|
println!("");
|
||||||
|
}
|
||||||
|
let mut flash = flash.stop();
|
||||||
|
}
|
||||||
|
|
||||||
let timer = libboard_zynq::timer::GlobalTimer::start();
|
let timer = libboard_zynq::timer::GlobalTimer::start();
|
||||||
|
|
||||||
let mut ddr = zynq::ddr::DdrRam::ddrram();
|
let mut ddr = zynq::ddr::DdrRam::new();
|
||||||
#[cfg(not(feature = "target_zc706"))]
|
#[cfg(not(feature = "target_zc706"))]
|
||||||
ddr.memtest();
|
ddr.memtest();
|
||||||
ram::init_alloc_ddr(&mut ddr);
|
ram::init_alloc_ddr(&mut ddr);
|
||||||
|
|
||||||
boot::Core1::start(false);
|
if false {
|
||||||
|
#[cfg(dev)]
|
||||||
|
for i in 0..=1 {
|
||||||
|
let mut flash_io = flash.manual_mode(i);
|
||||||
|
// println!("rdcr={:02X}", flash_io.rdcr());
|
||||||
|
print!("Flash {} ID:", i);
|
||||||
|
for b in flash_io.rdid() {
|
||||||
|
print!(" {:02X}", b);
|
||||||
|
}
|
||||||
|
println!("");
|
||||||
|
print!("Flash {} I/O:", i);
|
||||||
|
for o in 0..8 {
|
||||||
|
const CHUNK: u32 = 8;
|
||||||
|
for b in flash_io.read(CHUNK * o, CHUNK as usize) {
|
||||||
|
print!(" {:02X}", b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println!("");
|
||||||
|
|
||||||
let core1_req = unsafe { &mut CORE1_REQ.0 };
|
flash_io.dump("Read cr1", 0x35);
|
||||||
let core1_res = unsafe { &mut CORE1_RES.1 };
|
flash_io.dump("Read Autoboot", 0x14);
|
||||||
|
flash_io.dump("Read Bank", 0x16);
|
||||||
|
flash_io.dump("DLP Bank", 0x16);
|
||||||
|
flash_io.dump("Read ESig", 0xAB);
|
||||||
|
flash_io.dump("OTP Read", 0x4B);
|
||||||
|
flash_io.dump("DYB Read", 0xE0);
|
||||||
|
flash_io.dump("PPB Read", 0xE2);
|
||||||
|
flash_io.dump("ASP Read", 0x2B);
|
||||||
|
flash_io.dump("Password Read", 0xE7);
|
||||||
|
|
||||||
|
flash_io.write_enabled(|flash_io| {
|
||||||
|
flash_io.erase(0);
|
||||||
|
});
|
||||||
|
flash_io.write_enabled(|flash_io| {
|
||||||
|
flash_io.program(0, [0x23054223; 0x100 >> 2].iter().cloned());
|
||||||
|
});
|
||||||
|
|
||||||
|
flash = flash_io.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
let core1 = boot::Core1::start(false);
|
||||||
|
|
||||||
|
let (mut core1_req, rx) = sync_channel(10);
|
||||||
|
*CORE1_REQ.lock() = Some(rx);
|
||||||
|
let (tx, mut core1_res) = sync_channel(10);
|
||||||
|
*CORE1_RES.lock() = Some(tx);
|
||||||
task::block_on(async {
|
task::block_on(async {
|
||||||
for i in 0..10 {
|
for i in 0..10 {
|
||||||
restart_core1();
|
|
||||||
core1_req.async_send(i).await;
|
core1_req.async_send(i).await;
|
||||||
let j = core1_res.async_recv().await;
|
let j = core1_res.async_recv().await;
|
||||||
println!("{} -> {}", i, j);
|
println!("{} -> {}", i, j);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
unsafe {
|
core1.disable();
|
||||||
core1_req.drop_elements();
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Test I2C
|
let eth = zynq::eth::Eth::default(HWADDR.clone());
|
||||||
#[cfg(feature = "target_zc706")]
|
|
||||||
{
|
|
||||||
let mut i2c = zynq::i2c::I2c::i2c0();
|
|
||||||
i2c.init().unwrap();
|
|
||||||
println!("I2C bit-banging enabled");
|
|
||||||
let mut eeprom = zynq::i2c::eeprom::EEPROM::new(&mut i2c, 16);
|
|
||||||
// Write to 0x00 and 0x08
|
|
||||||
let eeprom_buffer: [u8; 22] = [
|
|
||||||
0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb,
|
|
||||||
0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee,
|
|
||||||
0xef, 0xcd, 0xab, 0x89, 0x67, 0x45, 0x23, 0x01,
|
|
||||||
];
|
|
||||||
eeprom.write(0x00, &eeprom_buffer[0..6]).unwrap();
|
|
||||||
eeprom.write(0x08, &eeprom_buffer[6..22]).unwrap();
|
|
||||||
println!("Data written to EEPROM");
|
|
||||||
let mut eeprom_buffer = [0u8; 24];
|
|
||||||
// Read from 0x00
|
|
||||||
eeprom.read(0x00, &mut eeprom_buffer).unwrap();
|
|
||||||
print!("Data read from EEPROM @ 0x00: (hex) ");
|
|
||||||
for i in 0..6 {
|
|
||||||
print!("{:02x} ", eeprom_buffer[i]);
|
|
||||||
}
|
|
||||||
println!("");
|
|
||||||
// Read from 0x08
|
|
||||||
eeprom.read(0x08, &mut eeprom_buffer).unwrap();
|
|
||||||
print!("Data read from EEPROM @ 0x08: (hex) ");
|
|
||||||
for i in 0..16 {
|
|
||||||
print!("{:02x} ", eeprom_buffer[i]);
|
|
||||||
}
|
|
||||||
println!("");
|
|
||||||
}
|
|
||||||
|
|
||||||
let eth = zynq::eth::Eth::eth0(HWADDR.clone());
|
|
||||||
println!("Eth on");
|
println!("Eth on");
|
||||||
|
|
||||||
const RX_LEN: usize = 4096;
|
const RX_LEN: usize = 4096;
|
||||||
|
@ -221,9 +207,44 @@ pub fn main_core0() {
|
||||||
.neighbor_cache(neighbor_cache)
|
.neighbor_cache(neighbor_cache)
|
||||||
.finalize();
|
.finalize();
|
||||||
|
|
||||||
Sockets::init(32);
|
#[cfg(feature = "target_zc706")]
|
||||||
|
ps7_init::report_differences();
|
||||||
|
|
||||||
|
Sockets::init(32);
|
||||||
|
/// `chargen`
|
||||||
const TCP_PORT: u16 = 19;
|
const TCP_PORT: u16 = 19;
|
||||||
|
async fn handle_connection(stream: TcpStream) -> smoltcp::Result<()> {
|
||||||
|
stream.send("Enter your name: ".bytes()).await?;
|
||||||
|
let name = stream
|
||||||
|
.recv(|buf| {
|
||||||
|
for (i, b) in buf.iter().enumerate() {
|
||||||
|
if *b == '\n' as u8 {
|
||||||
|
return match core::str::from_utf8(&buf[0..i]) {
|
||||||
|
Ok(name) => Poll::Ready((i + 1, Some(name.to_owned()))),
|
||||||
|
Err(_) => Poll::Ready((i + 1, None)),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if buf.len() > 100 {
|
||||||
|
// Too much input, consume all
|
||||||
|
Poll::Ready((buf.len(), None))
|
||||||
|
} else {
|
||||||
|
Poll::Pending
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.await?;
|
||||||
|
match name {
|
||||||
|
Some(name) => stream.send(format!("Hello {}!\n", name).bytes()).await?,
|
||||||
|
None => {
|
||||||
|
stream
|
||||||
|
.send("I had trouble reading your name.\n".bytes())
|
||||||
|
.await?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let _ = stream.close().await;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
// (rx, tx)
|
// (rx, tx)
|
||||||
let stats = alloc::rc::Rc::new(core::cell::RefCell::new((0, 0)));
|
let stats = alloc::rc::Rc::new(core::cell::RefCell::new((0, 0)));
|
||||||
let stats_tx = stats.clone();
|
let stats_tx = stats.clone();
|
||||||
|
@ -231,7 +252,7 @@ pub fn main_core0() {
|
||||||
while let Ok(stream) = TcpStream::accept(TCP_PORT, 0x10_0000, 0x10_0000).await {
|
while let Ok(stream) = TcpStream::accept(TCP_PORT, 0x10_0000, 0x10_0000).await {
|
||||||
let stats_tx = stats_tx.clone();
|
let stats_tx = stats_tx.clone();
|
||||||
task::spawn(async move {
|
task::spawn(async move {
|
||||||
let tx_data = (0..=255).take(4096).collect::<alloc::vec::Vec<u8>>();
|
let tx_data = (0..=255).take(65536).collect::<alloc::vec::Vec<u8>>();
|
||||||
loop {
|
loop {
|
||||||
// const CHUNK_SIZE: usize = 65536;
|
// const CHUNK_SIZE: usize = 65536;
|
||||||
// match stream.send((0..=255).cycle().take(CHUNK_SIZE)).await {
|
// match stream.send((0..=255).cycle().take(CHUNK_SIZE)).await {
|
||||||
|
@ -252,7 +273,7 @@ pub fn main_core0() {
|
||||||
let stats_rx = stats_rx.clone();
|
let stats_rx = stats_rx.clone();
|
||||||
task::spawn(async move {
|
task::spawn(async move {
|
||||||
loop {
|
loop {
|
||||||
match stream.recv(|buf| (buf.len(), buf.len())).await {
|
match stream.recv(|buf| Poll::Ready((buf.len(), buf.len()))).await {
|
||||||
Ok(len) => stats_rx.borrow_mut().0 += len,
|
Ok(len) => stats_rx.borrow_mut().0 += len,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
warn!("rx: {:?}", e);
|
warn!("rx: {:?}", e);
|
||||||
|
@ -269,7 +290,7 @@ pub fn main_core0() {
|
||||||
loop {
|
loop {
|
||||||
delay(&mut countdown, Milliseconds(1000)).await;
|
delay(&mut countdown, Milliseconds(1000)).await;
|
||||||
|
|
||||||
let timestamp = timer.get_us().0;
|
let timestamp = timer.get_us();
|
||||||
let seconds = timestamp / 1_000_000;
|
let seconds = timestamp / 1_000_000;
|
||||||
let micros = timestamp % 1_000_000;
|
let micros = timestamp % 1_000_000;
|
||||||
let (rx, tx) = {
|
let (rx, tx) = {
|
||||||
|
@ -287,18 +308,27 @@ pub fn main_core0() {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static CORE1_REQ: Mutex<Option<sync_channel::Receiver<usize>>> = Mutex::new(None);
|
||||||
|
static CORE1_RES: Mutex<Option<sync_channel::Sender<usize>>> = Mutex::new(None);
|
||||||
static DONE: Mutex<bool> = Mutex::new(false);
|
static DONE: Mutex<bool> = Mutex::new(false);
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub fn main_core1() {
|
pub fn main_core1() {
|
||||||
println!("Hello from core1!");
|
println!("Hello from core1!");
|
||||||
let mut interrupt_controller = gic::InterruptController::gic(mpcore::RegisterBlock::mpcore());
|
|
||||||
interrupt_controller.enable_interrupts();
|
let mut req = None;
|
||||||
let req = unsafe { &mut CORE1_REQ.1 };
|
while req.is_none() {
|
||||||
let res = unsafe { &mut CORE1_RES.0 };
|
req = CORE1_REQ.lock().take();
|
||||||
|
}
|
||||||
|
let req = req.unwrap();
|
||||||
|
let mut res = None;
|
||||||
|
while res.is_none() {
|
||||||
|
res = CORE1_RES.lock().take();
|
||||||
|
}
|
||||||
|
let mut res = res.unwrap();
|
||||||
|
|
||||||
for i in req {
|
for i in req {
|
||||||
res.send(i * i);
|
res.send(*i * *i);
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("core1 done!");
|
println!("core1 done!");
|
||||||
|
|
|
@ -0,0 +1,68 @@
|
||||||
|
#![cfg(feature = "target_zc706")]
|
||||||
|
|
||||||
|
use libboard_zynq::println;
|
||||||
|
|
||||||
|
mod zc706;
|
||||||
|
// mod cora_z7_10;
|
||||||
|
|
||||||
|
#[cfg(feature = "target_zc706")]
|
||||||
|
use zc706 as target;
|
||||||
|
// #[cfg(feature = "target_cora_z7_10")]
|
||||||
|
// use cora_z7_10 as target;
|
||||||
|
|
||||||
|
pub fn report_differences() {
|
||||||
|
for (i, op) in target::INIT_DATA.iter().enumerate() {
|
||||||
|
let address = op.address();
|
||||||
|
let overwritten_later = target::INIT_DATA[(i + 1)..].iter()
|
||||||
|
.any(|later_op| later_op.address() == address);
|
||||||
|
|
||||||
|
if !overwritten_later {
|
||||||
|
op.report_difference();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum InitOp {
|
||||||
|
MaskWrite(usize, usize, usize),
|
||||||
|
MaskPoll(usize, usize),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InitOp {
|
||||||
|
fn address(&self) -> usize {
|
||||||
|
match self {
|
||||||
|
InitOp::MaskWrite(address, _, _) => *address,
|
||||||
|
InitOp::MaskPoll(address, _) => *address,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read(&self) -> usize {
|
||||||
|
unsafe { *(self.address() as *const usize) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn difference(&self) -> Option<(usize, usize)> {
|
||||||
|
let (mask, expected) = match self {
|
||||||
|
InitOp::MaskWrite(_, mask, expected) =>
|
||||||
|
(*mask, *expected),
|
||||||
|
InitOp::MaskPoll(_, mask) =>
|
||||||
|
(*mask, *mask),
|
||||||
|
};
|
||||||
|
let actual = self.read();
|
||||||
|
if actual & mask == expected {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some((actual & mask, expected))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn report_difference(&self) {
|
||||||
|
if let Some((actual, expected)) = self.difference() {
|
||||||
|
println!(
|
||||||
|
"Register {:08X} is {:08X}&={:08X} != {:08X} expected",
|
||||||
|
self.address(),
|
||||||
|
self.read(),
|
||||||
|
actual,
|
||||||
|
expected
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,203 @@
|
||||||
|
use super::InitOp::{self, *};
|
||||||
|
|
||||||
|
pub const INIT_DATA: &'static [InitOp] = &[
|
||||||
|
// ps7_mio_init_data_1_0
|
||||||
|
MaskWrite(0xF8000B40, 0x00000FFF, 0x00000600),
|
||||||
|
MaskWrite(0xF8000B44, 0x00000FFF, 0x00000600),
|
||||||
|
MaskWrite(0xF8000B48, 0x00000FFF, 0x00000672),
|
||||||
|
MaskWrite(0xF8000B4C, 0x00000FFF, 0x00000672),
|
||||||
|
MaskWrite(0xF8000B50, 0x00000FFF, 0x00000674),
|
||||||
|
MaskWrite(0xF8000B54, 0x00000FFF, 0x00000674),
|
||||||
|
MaskWrite(0xF8000B58, 0x00000FFF, 0x00000600),
|
||||||
|
MaskWrite(0xF8000B5C, 0xFFFFFFFF, 0x0018C61C),
|
||||||
|
MaskWrite(0xF8000B60, 0xFFFFFFFF, 0x00F9861C),
|
||||||
|
MaskWrite(0xF8000B64, 0xFFFFFFFF, 0x00F9861C),
|
||||||
|
MaskWrite(0xF8000B68, 0xFFFFFFFF, 0x00F9861C),
|
||||||
|
MaskWrite(0xF8000B6C, 0x000073FF, 0x00000209),
|
||||||
|
MaskWrite(0xF8000B70, 0x00000021, 0x00000021),
|
||||||
|
MaskWrite(0xF8000B70, 0x00000021, 0x00000020),
|
||||||
|
MaskWrite(0xF8000B70, 0x07FFFFFF, 0x00000823),
|
||||||
|
MaskWrite(0xF8000700, 0x00003FFF, 0x00000600),
|
||||||
|
MaskWrite(0xF8000704, 0x00003FFF, 0x00000702),
|
||||||
|
MaskWrite(0xF8000708, 0x00003FFF, 0x00000702),
|
||||||
|
MaskWrite(0xF800070C, 0x00003FFF, 0x00000702),
|
||||||
|
MaskWrite(0xF8000710, 0x00003FFF, 0x00000702),
|
||||||
|
MaskWrite(0xF8000714, 0x00003FFF, 0x00000702),
|
||||||
|
MaskWrite(0xF8000718, 0x00003FFF, 0x00000702),
|
||||||
|
MaskWrite(0xF800071C, 0x00003FFF, 0x00000600),
|
||||||
|
MaskWrite(0xF8000720, 0x00003FFF, 0x00000700),
|
||||||
|
MaskWrite(0xF8000724, 0x00003FFF, 0x00000600),
|
||||||
|
MaskWrite(0xF8000728, 0x00003FFF, 0x00000600),
|
||||||
|
MaskWrite(0xF800072C, 0x00003FFF, 0x00000600),
|
||||||
|
MaskWrite(0xF8000730, 0x00003FFF, 0x00000600),
|
||||||
|
MaskWrite(0xF8000734, 0x00003FFF, 0x00000600),
|
||||||
|
MaskWrite(0xF8000738, 0x00003FFF, 0x00000600),
|
||||||
|
MaskWrite(0xF800073C, 0x00003FFF, 0x00000600),
|
||||||
|
MaskWrite(0xF8000740, 0x00003FFF, 0x00000302),
|
||||||
|
MaskWrite(0xF8000744, 0x00003FFF, 0x00000302),
|
||||||
|
MaskWrite(0xF8000748, 0x00003FFF, 0x00000302),
|
||||||
|
MaskWrite(0xF800074C, 0x00003FFF, 0x00000302),
|
||||||
|
MaskWrite(0xF8000750, 0x00003FFF, 0x00000302),
|
||||||
|
MaskWrite(0xF8000754, 0x00003FFF, 0x00000302),
|
||||||
|
MaskWrite(0xF8000758, 0x00003FFF, 0x00000303),
|
||||||
|
MaskWrite(0xF800075C, 0x00003FFF, 0x00000303),
|
||||||
|
MaskWrite(0xF8000760, 0x00003FFF, 0x00000303),
|
||||||
|
MaskWrite(0xF8000764, 0x00003FFF, 0x00000303),
|
||||||
|
MaskWrite(0xF8000768, 0x00003FFF, 0x00000303),
|
||||||
|
MaskWrite(0xF800076C, 0x00003FFF, 0x00000303),
|
||||||
|
MaskWrite(0xF8000770, 0x00003FFF, 0x00000304),
|
||||||
|
MaskWrite(0xF8000774, 0x00003FFF, 0x00000305),
|
||||||
|
MaskWrite(0xF8000778, 0x00003FFF, 0x00000304),
|
||||||
|
MaskWrite(0xF800077C, 0x00003FFF, 0x00000305),
|
||||||
|
MaskWrite(0xF8000780, 0x00003FFF, 0x00000304),
|
||||||
|
MaskWrite(0xF8000784, 0x00003FFF, 0x00000304),
|
||||||
|
MaskWrite(0xF8000788, 0x00003FFF, 0x00000304),
|
||||||
|
MaskWrite(0xF800078C, 0x00003FFF, 0x00000304),
|
||||||
|
MaskWrite(0xF8000790, 0x00003FFF, 0x00000305),
|
||||||
|
MaskWrite(0xF8000794, 0x00003FFF, 0x00000304),
|
||||||
|
MaskWrite(0xF8000798, 0x00003FFF, 0x00000304),
|
||||||
|
MaskWrite(0xF800079C, 0x00003FFF, 0x00000304),
|
||||||
|
MaskWrite(0xF80007A0, 0x00003FFF, 0x00000380),
|
||||||
|
MaskWrite(0xF80007A4, 0x00003FFF, 0x00000380),
|
||||||
|
MaskWrite(0xF80007A8, 0x00003FFF, 0x00000380),
|
||||||
|
MaskWrite(0xF80007AC, 0x00003FFF, 0x00000380),
|
||||||
|
MaskWrite(0xF80007B0, 0x00003FFF, 0x00000380),
|
||||||
|
MaskWrite(0xF80007B4, 0x00003FFF, 0x00000380),
|
||||||
|
MaskWrite(0xF80007B8, 0x00003F01, 0x00000201),
|
||||||
|
MaskWrite(0xF80007BC, 0x00003F01, 0x00000201),
|
||||||
|
MaskWrite(0xF80007C0, 0x00003FFF, 0x000002E0),
|
||||||
|
MaskWrite(0xF80007C4, 0x00003FFF, 0x000002E1),
|
||||||
|
MaskWrite(0xF80007C8, 0x00003FFF, 0x00000200),
|
||||||
|
MaskWrite(0xF80007CC, 0x00003FFF, 0x00000200),
|
||||||
|
MaskWrite(0xF80007D0, 0x00003FFF, 0x00000280),
|
||||||
|
MaskWrite(0xF80007D4, 0x00003FFF, 0x00000280),
|
||||||
|
MaskWrite(0xF8000830, 0x003F003F, 0x002F002E),
|
||||||
|
// ps7_pll_init_data_1_0
|
||||||
|
MaskWrite(0xF8000110, 0x003FFFF0, 0x000FA220),
|
||||||
|
MaskWrite(0xF8000100, 0x0007F000, 0x00028000),
|
||||||
|
MaskWrite(0xF8000100, 0x00000010, 0x00000010),
|
||||||
|
MaskWrite(0xF8000100, 0x00000001, 0x00000001),
|
||||||
|
MaskWrite(0xF8000100, 0x00000001, 0x00000000),
|
||||||
|
MaskPoll(0xF800010C, 0x00000001),
|
||||||
|
MaskWrite(0xF8000100, 0x00000010, 0x00000000),
|
||||||
|
MaskWrite(0xF8000120, 0x1F003F30, 0x1F000200),
|
||||||
|
MaskWrite(0xF8000114, 0x003FFFF0, 0x0012C220),
|
||||||
|
MaskWrite(0xF8000104, 0x0007F000, 0x00020000),
|
||||||
|
MaskWrite(0xF8000104, 0x00000010, 0x00000010),
|
||||||
|
MaskWrite(0xF8000104, 0x00000001, 0x00000001),
|
||||||
|
MaskWrite(0xF8000104, 0x00000001, 0x00000000),
|
||||||
|
MaskPoll(0xF800010C, 0x00000002),
|
||||||
|
MaskWrite(0xF8000104, 0x00000010, 0x00000000),
|
||||||
|
MaskWrite(0xF8000124, 0xFFF00003, 0x0C200003),
|
||||||
|
MaskWrite(0xF8000118, 0x003FFFF0, 0x001452C0),
|
||||||
|
MaskWrite(0xF8000108, 0x0007F000, 0x0001E000),
|
||||||
|
MaskWrite(0xF8000108, 0x00000010, 0x00000010),
|
||||||
|
MaskWrite(0xF8000108, 0x00000001, 0x00000001),
|
||||||
|
MaskWrite(0xF8000108, 0x00000001, 0x00000000),
|
||||||
|
MaskPoll(0xF800010C, 0x00000004),
|
||||||
|
MaskWrite(0xF8000108, 0x00000010, 0x00000000),
|
||||||
|
// ps7_clock_init_data_1_0
|
||||||
|
MaskWrite(0xF8000128, 0x03F03F01, 0x00700F01),
|
||||||
|
MaskWrite(0xF8000138, 0x00000011, 0x00000001),
|
||||||
|
MaskWrite(0xF8000140, 0x03F03F71, 0x00100801),
|
||||||
|
MaskWrite(0xF800014C, 0x00003F31, 0x00000501),
|
||||||
|
MaskWrite(0xF8000150, 0x00003F33, 0x00001401),
|
||||||
|
MaskWrite(0xF8000154, 0x00003F33, 0x00001402),
|
||||||
|
MaskWrite(0xF8000168, 0x00003F31, 0x00000501),
|
||||||
|
MaskWrite(0xF8000170, 0x03F03F30, 0x00200400),
|
||||||
|
MaskWrite(0xF80001C4, 0x00000001, 0x00000001),
|
||||||
|
MaskWrite(0xF800012C, 0x01FFCCCD, 0x01EC044D),
|
||||||
|
// ps7_ddr_init_data_1_0
|
||||||
|
MaskWrite(0xF8006000, 0x0001FFFF, 0x00000080),
|
||||||
|
MaskWrite(0xF8006004, 0x1FFFFFFF, 0x00081081),
|
||||||
|
MaskWrite(0xF8006008, 0x03FFFFFF, 0x03C0780F),
|
||||||
|
MaskWrite(0xF800600C, 0x03FFFFFF, 0x02001001),
|
||||||
|
MaskWrite(0xF8006010, 0x03FFFFFF, 0x00014001),
|
||||||
|
MaskWrite(0xF8006014, 0x001FFFFF, 0x0004159B),
|
||||||
|
MaskWrite(0xF8006018, 0xF7FFFFFF, 0x452460D2),
|
||||||
|
MaskWrite(0xF800601C, 0xFFFFFFFF, 0x720238E5),
|
||||||
|
MaskWrite(0xF8006020, 0xFFFFFFFC, 0x272872D0),
|
||||||
|
MaskWrite(0xF8006024, 0x0FFFFFFF, 0x0000003C),
|
||||||
|
MaskWrite(0xF8006028, 0x00003FFF, 0x00002007),
|
||||||
|
MaskWrite(0xF800602C, 0xFFFFFFFF, 0x00000008),
|
||||||
|
MaskWrite(0xF8006030, 0xFFFFFFFF, 0x00040930),
|
||||||
|
MaskWrite(0xF8006034, 0x13FF3FFF, 0x000116D4),
|
||||||
|
MaskWrite(0xF8006038, 0x00001FC3, 0x00000000),
|
||||||
|
MaskWrite(0xF800603C, 0x000FFFFF, 0x00000777),
|
||||||
|
MaskWrite(0xF8006040, 0xFFFFFFFF, 0xFFF00000),
|
||||||
|
MaskWrite(0xF8006044, 0x0FFFFFFF, 0x0FF66666),
|
||||||
|
MaskWrite(0xF8006048, 0x3FFFFFFF, 0x0003C248),
|
||||||
|
MaskWrite(0xF8006050, 0xFF0F8FFF, 0x77010800),
|
||||||
|
MaskWrite(0xF8006058, 0x0001FFFF, 0x00000101),
|
||||||
|
MaskWrite(0xF800605C, 0x0000FFFF, 0x00005003),
|
||||||
|
MaskWrite(0xF8006060, 0x000017FF, 0x0000003E),
|
||||||
|
MaskWrite(0xF8006064, 0x00021FE0, 0x00020000),
|
||||||
|
MaskWrite(0xF8006068, 0x03FFFFFF, 0x00284141),
|
||||||
|
MaskWrite(0xF800606C, 0x0000FFFF, 0x00001610),
|
||||||
|
MaskWrite(0xF80060A0, 0x00FFFFFF, 0x00008000),
|
||||||
|
MaskWrite(0xF80060A4, 0xFFFFFFFF, 0x10200802),
|
||||||
|
MaskWrite(0xF80060A8, 0x0FFFFFFF, 0x0690CB73),
|
||||||
|
MaskWrite(0xF80060AC, 0x000001FF, 0x000001FE),
|
||||||
|
MaskWrite(0xF80060B0, 0x1FFFFFFF, 0x1CFFFFFF),
|
||||||
|
MaskWrite(0xF80060B4, 0x000007FF, 0x00000200),
|
||||||
|
MaskWrite(0xF80060B8, 0x01FFFFFF, 0x00200066),
|
||||||
|
MaskWrite(0xF80060C4, 0x00000003, 0x00000000),
|
||||||
|
MaskWrite(0xF80060C8, 0x000000FF, 0x00000000),
|
||||||
|
MaskWrite(0xF80060DC, 0x00000001, 0x00000000),
|
||||||
|
MaskWrite(0xF80060F0, 0x0000FFFF, 0x00000000),
|
||||||
|
MaskWrite(0xF80060F4, 0x0000000F, 0x00000008),
|
||||||
|
MaskWrite(0xF8006114, 0x000000FF, 0x00000000),
|
||||||
|
MaskWrite(0xF8006118, 0x7FFFFFFF, 0x40000001),
|
||||||
|
MaskWrite(0xF800611C, 0x7FFFFFFF, 0x40000001),
|
||||||
|
MaskWrite(0xF8006120, 0x7FFFFFFF, 0x40000001),
|
||||||
|
MaskWrite(0xF8006124, 0x7FFFFFFF, 0x40000001),
|
||||||
|
MaskWrite(0xF800612C, 0x000FFFFF, 0x00033C03),
|
||||||
|
MaskWrite(0xF8006130, 0x000FFFFF, 0x00034003),
|
||||||
|
MaskWrite(0xF8006134, 0x000FFFFF, 0x0002F400),
|
||||||
|
MaskWrite(0xF8006138, 0x000FFFFF, 0x00030400),
|
||||||
|
MaskWrite(0xF8006140, 0x000FFFFF, 0x00000035),
|
||||||
|
MaskWrite(0xF8006144, 0x000FFFFF, 0x00000035),
|
||||||
|
MaskWrite(0xF8006148, 0x000FFFFF, 0x00000035),
|
||||||
|
MaskWrite(0xF800614C, 0x000FFFFF, 0x00000035),
|
||||||
|
MaskWrite(0xF8006154, 0x000FFFFF, 0x00000083),
|
||||||
|
MaskWrite(0xF8006158, 0x000FFFFF, 0x00000083),
|
||||||
|
MaskWrite(0xF800615C, 0x000FFFFF, 0x00000080),
|
||||||
|
MaskWrite(0xF8006160, 0x000FFFFF, 0x00000080),
|
||||||
|
MaskWrite(0xF8006168, 0x001FFFFF, 0x00000124),
|
||||||
|
MaskWrite(0xF800616C, 0x001FFFFF, 0x00000125),
|
||||||
|
MaskWrite(0xF8006170, 0x001FFFFF, 0x00000112),
|
||||||
|
MaskWrite(0xF8006174, 0x001FFFFF, 0x00000116),
|
||||||
|
MaskWrite(0xF800617C, 0x000FFFFF, 0x000000C3),
|
||||||
|
MaskWrite(0xF8006180, 0x000FFFFF, 0x000000C3),
|
||||||
|
MaskWrite(0xF8006184, 0x000FFFFF, 0x000000C0),
|
||||||
|
MaskWrite(0xF8006188, 0x000FFFFF, 0x000000C0),
|
||||||
|
MaskWrite(0xF8006190, 0xFFFFFFFF, 0x10040080),
|
||||||
|
MaskWrite(0xF8006194, 0x000FFFFF, 0x0001FC82),
|
||||||
|
MaskWrite(0xF8006204, 0xFFFFFFFF, 0x00000000),
|
||||||
|
MaskWrite(0xF8006208, 0x000F03FF, 0x000803FF),
|
||||||
|
MaskWrite(0xF800620C, 0x000F03FF, 0x000803FF),
|
||||||
|
MaskWrite(0xF8006210, 0x000F03FF, 0x000803FF),
|
||||||
|
MaskWrite(0xF8006214, 0x000F03FF, 0x000803FF),
|
||||||
|
MaskWrite(0xF8006218, 0x000F03FF, 0x000003FF),
|
||||||
|
MaskWrite(0xF800621C, 0x000F03FF, 0x000003FF),
|
||||||
|
MaskWrite(0xF8006220, 0x000F03FF, 0x000003FF),
|
||||||
|
MaskWrite(0xF8006224, 0x000F03FF, 0x000003FF),
|
||||||
|
MaskWrite(0xF80062A8, 0x00000FF7, 0x00000000),
|
||||||
|
MaskWrite(0xF80062AC, 0xFFFFFFFF, 0x00000000),
|
||||||
|
MaskWrite(0xF80062B0, 0x003FFFFF, 0x00005125),
|
||||||
|
MaskWrite(0xF80062B4, 0x0003FFFF, 0x000012A8),
|
||||||
|
MaskPoll(0xF8000B74, 0x00002000),
|
||||||
|
MaskWrite(0xF8006000, 0x0001FFFF, 0x00000081),
|
||||||
|
MaskPoll(0xF8006054, 0x00000007),
|
||||||
|
// ps7_peripherals_init_data_1_0
|
||||||
|
MaskWrite(0xF8000B48, 0x00000180, 0x00000180),
|
||||||
|
MaskWrite(0xF8000B4C, 0x00000180, 0x00000180),
|
||||||
|
MaskWrite(0xF8000B50, 0x00000180, 0x00000180),
|
||||||
|
MaskWrite(0xF8000B54, 0x00000180, 0x00000180),
|
||||||
|
MaskWrite(0xE0001034, 0x000000FF, 0x00000006),
|
||||||
|
MaskWrite(0xE0001018, 0x0000FFFF, 0x0000003E),
|
||||||
|
MaskWrite(0xE0001000, 0x000001FF, 0x00000017),
|
||||||
|
MaskWrite(0xE0001004, 0x00000FFF, 0x00000020),
|
||||||
|
MaskWrite(0xE000D000, 0x00080000, 0x00080000),
|
||||||
|
MaskWrite(0xF8007000, 0x20000000, 0x00000000),
|
||||||
|
];
|
|
@ -2,7 +2,7 @@
|
||||||
name = "libasync"
|
name = "libasync"
|
||||||
description = "low-level async support"
|
description = "low-level async support"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
authors = ["M-Labs"]
|
authors = ["Astro <astro@spaceboyz.net>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
|
|
@ -6,7 +6,7 @@ use core::{
|
||||||
sync::atomic::{AtomicBool, Ordering},
|
sync::atomic::{AtomicBool, Ordering},
|
||||||
task::{Context, Poll, RawWaker, RawWakerVTable, Waker},
|
task::{Context, Poll, RawWaker, RawWakerVTable, Waker},
|
||||||
};
|
};
|
||||||
use alloc::{boxed::Box, vec::Vec};
|
use alloc::{boxed::Box, collections::VecDeque as Deque};
|
||||||
//use futures::future::FutureExt;
|
//use futures::future::FutureExt;
|
||||||
use pin_utils::pin_mut;
|
use pin_utils::pin_mut;
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ static VTABLE: RawWakerVTable = {
|
||||||
/// ready should not move as long as this waker references it. That is
|
/// ready should not move as long as this waker references it. That is
|
||||||
/// the reason for keeping Tasks in a pinned box.
|
/// the reason for keeping Tasks in a pinned box.
|
||||||
fn wrap_waker(ready: &AtomicBool) -> Waker {
|
fn wrap_waker(ready: &AtomicBool) -> Waker {
|
||||||
unsafe { Waker::from_raw(RawWaker::new(ready as *const _ as *const (), &VTABLE)) }
|
unsafe { Waker::from_raw(RawWaker::new(ready as *const _ as *const _, &VTABLE)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A single-threaded executor
|
/// A single-threaded executor
|
||||||
|
@ -44,7 +44,7 @@ pub struct Executor {
|
||||||
/// Tasks reside on the heap, so that we just queue pointers. They
|
/// Tasks reside on the heap, so that we just queue pointers. They
|
||||||
/// must also be pinned in memory because our RawWaker is a pointer
|
/// must also be pinned in memory because our RawWaker is a pointer
|
||||||
/// to their `ready` field.
|
/// to their `ready` field.
|
||||||
tasks: RefCell<Vec<Pin<Box<Task>>>>,
|
tasks: RefCell<Deque<Pin<Box<Task>>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Executor {
|
impl Executor {
|
||||||
|
@ -52,7 +52,7 @@ impl Executor {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
in_block_on: RefCell::new(false),
|
in_block_on: RefCell::new(false),
|
||||||
tasks: RefCell::new(Vec::new()),
|
tasks: RefCell::new(Deque::new()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,7 +72,6 @@ impl Executor {
|
||||||
pin_mut!(f);
|
pin_mut!(f);
|
||||||
let ready = AtomicBool::new(true);
|
let ready = AtomicBool::new(true);
|
||||||
let waker = wrap_waker(&ready);
|
let waker = wrap_waker(&ready);
|
||||||
let mut backup = Vec::new();
|
|
||||||
let val = loop {
|
let val = loop {
|
||||||
// advance the main task
|
// advance the main task
|
||||||
if ready.load(Ordering::Relaxed) {
|
if ready.load(Ordering::Relaxed) {
|
||||||
|
@ -86,9 +85,10 @@ impl Executor {
|
||||||
// println!("ran block_on");
|
// println!("ran block_on");
|
||||||
}
|
}
|
||||||
|
|
||||||
// advance all tasks
|
// println!("tasks: {}", self.tasks.borrow().len());
|
||||||
core::mem::swap(&mut *self.tasks.borrow_mut(), &mut backup);
|
// advance other tasks
|
||||||
for mut task in backup.drain(..) {
|
let next_task = self.tasks.borrow_mut().pop_front();
|
||||||
|
if let Some(mut task) = next_task {
|
||||||
// NOTE we don't need a CAS operation here because `wake` invocations that come from
|
// NOTE we don't need a CAS operation here because `wake` invocations that come from
|
||||||
// interrupt handlers (the only source of 'race conditions' (!= data races)) are
|
// interrupt handlers (the only source of 'race conditions' (!= data races)) are
|
||||||
// "oneshot": they'll issue a `wake` and then disable themselves to not run again
|
// "oneshot": they'll issue a `wake` and then disable themselves to not run again
|
||||||
|
@ -106,7 +106,7 @@ impl Executor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Requeue
|
// Requeue
|
||||||
self.tasks.borrow_mut().push(task);
|
self.tasks.borrow_mut().push_back(task);
|
||||||
}
|
}
|
||||||
|
|
||||||
// // try to sleep; this will be a no-op if any of the previous tasks generated a SEV or an
|
// // try to sleep; this will be a no-op if any of the previous tasks generated a SEV or an
|
||||||
|
@ -119,7 +119,7 @@ impl Executor {
|
||||||
|
|
||||||
pub fn spawn(&self, f: impl Future + 'static) {
|
pub fn spawn(&self, f: impl Future + 'static) {
|
||||||
let task = Box::pin(Task::new(f));
|
let task = Box::pin(Task::new(f));
|
||||||
self.tasks.borrow_mut().push(task);
|
self.tasks.borrow_mut().push_back(task);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -81,14 +81,7 @@ impl Sockets {
|
||||||
/// TODO: this was called through eg. TcpStream, another poll()
|
/// TODO: this was called through eg. TcpStream, another poll()
|
||||||
/// might want to send packets before sleeping for an interrupt.
|
/// might want to send packets before sleeping for an interrupt.
|
||||||
pub(crate) fn register_waker(waker: Waker) {
|
pub(crate) fn register_waker(waker: Waker) {
|
||||||
let mut wakers = Self::instance().wakers.borrow_mut();
|
Self::instance().wakers.borrow_mut()
|
||||||
for (i, w) in wakers.iter().enumerate() {
|
.push(waker);
|
||||||
if w.will_wake(&waker) {
|
|
||||||
let last = wakers.len() - 1;
|
|
||||||
wakers.swap(i, last);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
wakers.push(waker);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -103,19 +103,21 @@ impl TcpStream {
|
||||||
|
|
||||||
/// Probe the receive buffer
|
/// Probe the receive buffer
|
||||||
///
|
///
|
||||||
/// Your callback will only be called when there is some data available,
|
/// Instead of handing you the data on the heap all at once,
|
||||||
/// and it must consume at least one byte. It returns a tuple with the
|
/// smoltcp's read interface is wrapped so that your callback can
|
||||||
/// number of bytes it consumed, and a user-defined return value of type R.
|
/// just return `Poll::Pending` if there is not enough data
|
||||||
|
/// yet. Likewise, return the amount of bytes consumed from the
|
||||||
|
/// buffer in the `Poll::Ready` result.
|
||||||
pub async fn recv<F, R>(&self, f: F) -> Result<R>
|
pub async fn recv<F, R>(&self, f: F) -> Result<R>
|
||||||
where
|
where
|
||||||
F: Fn(&[u8]) -> (usize, R),
|
F: Fn(&[u8]) -> Poll<(usize, R)>,
|
||||||
{
|
{
|
||||||
struct Recv<'a, F: FnOnce(&[u8]) -> (usize, R), R> {
|
struct Recv<'a, F: FnOnce(&[u8]) -> Poll<(usize, R)>, R> {
|
||||||
stream: &'a TcpStream,
|
stream: &'a TcpStream,
|
||||||
f: F,
|
f: F,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, F: Fn(&[u8]) -> (usize, R), R> Future for Recv<'a, F, R> {
|
impl<'a, F: Fn(&[u8]) -> Poll<(usize, R)>, R> Future for Recv<'a, F, R> {
|
||||||
type Output = Result<R>;
|
type Output = Result<R>;
|
||||||
|
|
||||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||||
|
@ -126,9 +128,13 @@ impl TcpStream {
|
||||||
|
|
||||||
socket.recv(|buf| {
|
socket.recv(|buf| {
|
||||||
if buf.len() > 0 {
|
if buf.len() > 0 {
|
||||||
let (amount, result) = (self.f)(buf);
|
match (self.f)(buf) {
|
||||||
assert!(amount > 0);
|
Poll::Ready((amount, result)) =>
|
||||||
(amount, Poll::Ready(Ok(result)))
|
(amount, Poll::Ready(Ok(result))),
|
||||||
|
Poll::Pending =>
|
||||||
|
// 0 bytes consumed
|
||||||
|
(0, Poll::Pending),
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
(0, Poll::Pending)
|
(0, Poll::Pending)
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,14 +2,12 @@
|
||||||
name = "libboard_zynq"
|
name = "libboard_zynq"
|
||||||
description = "Drivers for peripherals in the Zynq PS"
|
description = "Drivers for peripherals in the Zynq PS"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
authors = ["M-Labs"]
|
authors = ["Astro <astro@spaceboyz.net>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
target_zc706 = []
|
target_zc706 = []
|
||||||
target_cora_z7_10 = []
|
target_cora_z7_10 = []
|
||||||
target_redpitaya = []
|
|
||||||
ipv6 = [ "smoltcp/proto-ipv6" ]
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
volatile-register = "0.2"
|
volatile-register = "0.2"
|
||||||
|
@ -23,5 +21,6 @@ libcortex_a9 = { path = "../libcortex_a9" }
|
||||||
|
|
||||||
[dependencies.smoltcp]
|
[dependencies.smoltcp]
|
||||||
version = "0.6"
|
version = "0.6"
|
||||||
|
# features = ["ethernet", "proto-ipv4", "socket-tcp", "log"]
|
||||||
features = ["ethernet", "proto-ipv4", "socket-tcp"]
|
features = ["ethernet", "proto-ipv4", "socket-tcp"]
|
||||||
default-features = false
|
default-features = false
|
||||||
|
|
|
@ -14,7 +14,7 @@ enum CpuClockMode {
|
||||||
|
|
||||||
impl CpuClockMode {
|
impl CpuClockMode {
|
||||||
pub fn get() -> Self {
|
pub fn get() -> Self {
|
||||||
let regs = slcr::RegisterBlock::slcr();
|
let regs = slcr::RegisterBlock::new();
|
||||||
if regs.clk_621_true.read().clk_621_true() {
|
if regs.clk_621_true.read().clk_621_true() {
|
||||||
CpuClockMode::C621
|
CpuClockMode::C621
|
||||||
} else {
|
} else {
|
||||||
|
@ -59,7 +59,7 @@ impl Clocks {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cpu_6x4x(&self) -> u32 {
|
pub fn cpu_6x4x(&self) -> u32 {
|
||||||
let slcr = slcr::RegisterBlock::slcr();
|
let slcr = slcr::RegisterBlock::new();
|
||||||
let arm_clk_ctrl = slcr.arm_clk_ctrl.read();
|
let arm_clk_ctrl = slcr.arm_clk_ctrl.read();
|
||||||
let pll = match arm_clk_ctrl.srcsel() {
|
let pll = match arm_clk_ctrl.srcsel() {
|
||||||
ArmPllSource::ArmPll => self.arm,
|
ArmPllSource::ArmPll => self.arm,
|
||||||
|
@ -92,7 +92,7 @@ impl Clocks {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn uart_ref_clk(&self) -> u32 {
|
pub fn uart_ref_clk(&self) -> u32 {
|
||||||
let regs = slcr::RegisterBlock::slcr();
|
let regs = slcr::RegisterBlock::new();
|
||||||
let uart_clk_ctrl = regs.uart_clk_ctrl.read();
|
let uart_clk_ctrl = regs.uart_clk_ctrl.read();
|
||||||
let pll = match uart_clk_ctrl.srcsel() {
|
let pll = match uart_clk_ctrl.srcsel() {
|
||||||
slcr::PllSource::ArmPll =>
|
slcr::PllSource::ArmPll =>
|
||||||
|
@ -106,7 +106,7 @@ impl Clocks {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sdio_ref_clk(&self) -> u32 {
|
pub fn sdio_ref_clk(&self) -> u32 {
|
||||||
let regs = slcr::RegisterBlock::slcr();
|
let regs = slcr::RegisterBlock::new();
|
||||||
let sdio_clk_ctrl = regs.sdio_clk_ctrl.read();
|
let sdio_clk_ctrl = regs.sdio_clk_ctrl.read();
|
||||||
let pll = match sdio_clk_ctrl.srcsel() {
|
let pll = match sdio_clk_ctrl.srcsel() {
|
||||||
slcr::PllSource::ArmPll =>
|
slcr::PllSource::ArmPll =>
|
||||||
|
|
|
@ -6,8 +6,6 @@ use super::slcr;
|
||||||
pub const PS_CLK: u32 = 33_333_333;
|
pub const PS_CLK: u32 = 33_333_333;
|
||||||
#[cfg(feature = "target_cora_z7_10")]
|
#[cfg(feature = "target_cora_z7_10")]
|
||||||
pub const PS_CLK: u32 = 50_000_000;
|
pub const PS_CLK: u32 = 50_000_000;
|
||||||
#[cfg(feature = "target_redpitaya")]
|
|
||||||
pub const PS_CLK: u32 = 33_333_333;
|
|
||||||
|
|
||||||
/// (pll_fdiv_max, (pll_cp, pll_res, lock_cnt))
|
/// (pll_fdiv_max, (pll_cp, pll_res, lock_cnt))
|
||||||
const PLL_FDIV_LOCK_PARAM: &[(u16, (u8, u8, u16))] = &[
|
const PLL_FDIV_LOCK_PARAM: &[(u16, (u8, u8, u16))] = &[
|
||||||
|
@ -46,7 +44,7 @@ pub trait ClockSource {
|
||||||
|
|
||||||
/// get configured frequency
|
/// get configured frequency
|
||||||
fn freq() -> u32 {
|
fn freq() -> u32 {
|
||||||
let mut slcr = slcr::RegisterBlock::slcr();
|
let mut slcr = slcr::RegisterBlock::new();
|
||||||
let (pll_ctrl, _, _) = Self::pll_regs(&mut slcr);
|
let (pll_ctrl, _, _) = Self::pll_regs(&mut slcr);
|
||||||
u32::from(pll_ctrl.read().pll_fdiv()) * PS_CLK
|
u32::from(pll_ctrl.read().pll_fdiv()) * PS_CLK
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,10 +14,6 @@ const DDR_FREQ: u32 = 666_666_666;
|
||||||
/// Micron MT41K256M16HA-125: 800 MHz DDR3L, max supported 533 MHz
|
/// Micron MT41K256M16HA-125: 800 MHz DDR3L, max supported 533 MHz
|
||||||
const DDR_FREQ: u32 = 525_000_000;
|
const DDR_FREQ: u32 = 525_000_000;
|
||||||
|
|
||||||
#[cfg(feature = "target_redpitaya")]
|
|
||||||
/// Alliance Memory AS4C256M16D3B: 800 MHz DDR3
|
|
||||||
const DDR_FREQ: u32 = 800_000_000;
|
|
||||||
|
|
||||||
/// MT41K256M16HA-125
|
/// MT41K256M16HA-125
|
||||||
const DCI_FREQ: u32 = 10_000_000;
|
const DCI_FREQ: u32 = 10_000_000;
|
||||||
|
|
||||||
|
@ -26,14 +22,13 @@ pub struct DdrRam {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DdrRam {
|
impl DdrRam {
|
||||||
pub fn ddrram() -> Self {
|
pub fn new() -> Self {
|
||||||
let clocks = Self::clock_setup();
|
let clocks = Self::clock_setup();
|
||||||
Self::calibrate_iob_impedance(&clocks);
|
Self::calibrate_iob_impedance(&clocks);
|
||||||
Self::configure_iob();
|
Self::configure_iob();
|
||||||
|
|
||||||
let regs = regs::RegisterBlock::ddrc();
|
let regs = unsafe { regs::RegisterBlock::new() };
|
||||||
let mut ddr = DdrRam { regs };
|
let mut ddr = DdrRam { regs };
|
||||||
ddr.configure();
|
|
||||||
ddr.reset_ddrc();
|
ddr.reset_ddrc();
|
||||||
ddr
|
ddr
|
||||||
}
|
}
|
||||||
|
@ -60,35 +55,14 @@ impl DdrRam {
|
||||||
clocks
|
clocks
|
||||||
}
|
}
|
||||||
|
|
||||||
fn calculate_dci_divisors(clocks: &Clocks) -> (u8, u8) {
|
|
||||||
let target = (DCI_FREQ - 1 + clocks.ddr) / DCI_FREQ;
|
|
||||||
|
|
||||||
let mut best = None;
|
|
||||||
let mut best_error = 0;
|
|
||||||
for divisor0 in 1..63 {
|
|
||||||
for divisor1 in 1..63 {
|
|
||||||
let current = (divisor0 as u32) * (divisor1 as u32);
|
|
||||||
let error = if current > target {
|
|
||||||
current - target
|
|
||||||
} else {
|
|
||||||
target - current
|
|
||||||
};
|
|
||||||
if best.is_none() || best_error > error {
|
|
||||||
best = Some((divisor0, divisor1));
|
|
||||||
best_error = error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
best.unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Zynq-7000 AP SoC Technical Reference Manual:
|
/// Zynq-7000 AP SoC Technical Reference Manual:
|
||||||
/// 10.6.2 DDR IOB Impedance Calibration
|
/// 10.6.2 DDR IOB Impedance Calibration
|
||||||
fn calibrate_iob_impedance(clocks: &Clocks) {
|
fn calibrate_iob_impedance(clocks: &Clocks) {
|
||||||
let (divisor0, divisor1) = Self::calculate_dci_divisors(clocks);
|
let divisor0 = ((DCI_FREQ - 1 + clocks.ddr) / DCI_FREQ)
|
||||||
debug!("DDR DCI clock: {} Hz (divisors={}*{})",
|
.max(1).min(63) as u8;
|
||||||
clocks.ddr / u32::from(divisor0) / u32::from(divisor1),
|
let divisor1 = ((DCI_FREQ - 1 + clocks.ddr) / DCI_FREQ / u32::from(divisor0))
|
||||||
divisor0, divisor1);
|
.max(1).min(63) as u8;
|
||||||
|
debug!("DDR DCI clock: {} Hz", clocks.ddr / u32::from(divisor0) / u32::from(divisor1));
|
||||||
|
|
||||||
slcr::RegisterBlock::unlocked(|slcr| {
|
slcr::RegisterBlock::unlocked(|slcr| {
|
||||||
// Step 1.
|
// Step 1.
|
||||||
|
@ -151,15 +125,6 @@ impl DdrRam {
|
||||||
.dci_type(slcr::DdriobDciType::Termination)
|
.dci_type(slcr::DdriobDciType::Termination)
|
||||||
.output_en(slcr::DdriobOutputEn::Obuf);
|
.output_en(slcr::DdriobOutputEn::Obuf);
|
||||||
#[cfg(feature = "target_cora_z7_10")]
|
#[cfg(feature = "target_cora_z7_10")]
|
||||||
let data1_config = slcr::DdriobConfig::zeroed()
|
|
||||||
.pullup_en(true);
|
|
||||||
#[cfg(feature = "target_redpitaya")]
|
|
||||||
let data0_config = slcr::DdriobConfig::zeroed()
|
|
||||||
.inp_type(slcr::DdriobInputType::VrefDifferential)
|
|
||||||
.term_en(true)
|
|
||||||
.dci_type(slcr::DdriobDciType::Termination)
|
|
||||||
.output_en(slcr::DdriobOutputEn::Obuf);
|
|
||||||
#[cfg(feature = "target_redpitaya")]
|
|
||||||
let data1_config = slcr::DdriobConfig::zeroed()
|
let data1_config = slcr::DdriobConfig::zeroed()
|
||||||
.pullup_en(true);
|
.pullup_en(true);
|
||||||
slcr.ddriob_data0.write(data0_config);
|
slcr.ddriob_data0.write(data0_config);
|
||||||
|
@ -182,15 +147,7 @@ impl DdrRam {
|
||||||
#[cfg(feature = "target_cora_z7_10")]
|
#[cfg(feature = "target_cora_z7_10")]
|
||||||
let diff1_config = slcr::DdriobConfig::zeroed()
|
let diff1_config = slcr::DdriobConfig::zeroed()
|
||||||
.pullup_en(true);
|
.pullup_en(true);
|
||||||
#[cfg(feature = "target_redpitaya")]
|
|
||||||
let diff0_config = slcr::DdriobConfig::zeroed()
|
|
||||||
.inp_type(slcr::DdriobInputType::Differential)
|
|
||||||
.term_en(true)
|
|
||||||
.dci_type(slcr::DdriobDciType::Termination)
|
|
||||||
.output_en(slcr::DdriobOutputEn::Obuf);
|
|
||||||
#[cfg(feature = "target_redpitaya")]
|
|
||||||
let diff1_config = slcr::DdriobConfig::zeroed()
|
|
||||||
.pullup_en(true);
|
|
||||||
slcr.ddriob_diff0.write(diff0_config);
|
slcr.ddriob_diff0.write(diff0_config);
|
||||||
slcr.ddriob_diff1.write(diff1_config);
|
slcr.ddriob_diff1.write(diff1_config);
|
||||||
|
|
||||||
|
@ -221,91 +178,9 @@ impl DdrRam {
|
||||||
.vref_ext_en_lower(false)
|
.vref_ext_en_lower(false)
|
||||||
.vref_ext_en_upper(false)
|
.vref_ext_en_upper(false)
|
||||||
);
|
);
|
||||||
#[cfg(feature = "target_redpitaya")]
|
|
||||||
slcr.ddriob_ddr_ctrl.modify(|_, w| w
|
|
||||||
.vref_int_en(false)
|
|
||||||
.vref_ext_en_lower(true)
|
|
||||||
.vref_ext_en_upper(false)
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn configure(&mut self) {
|
|
||||||
self.regs.dram_param0.write(
|
|
||||||
regs::DramParam0::zeroed()
|
|
||||||
.t_rc(0x1b)
|
|
||||||
.t_rfc_min(0x56)
|
|
||||||
.post_selfref_gap_x32(0x10)
|
|
||||||
);
|
|
||||||
|
|
||||||
self.regs.dram_param2.write(
|
|
||||||
regs::DramParam2::zeroed()
|
|
||||||
.write_latency(0x5)
|
|
||||||
.rd2wr(0x7)
|
|
||||||
.wr2rd(0xe)
|
|
||||||
.t_xp(0x4)
|
|
||||||
.pad_pd(0x0)
|
|
||||||
.rd2pre(0x4)
|
|
||||||
.t_rcd(0x7)
|
|
||||||
);
|
|
||||||
|
|
||||||
self.regs.dram_emr_mr.write(
|
|
||||||
regs::DramEmrMr::zeroed()
|
|
||||||
.mr(0x930)
|
|
||||||
.emr(0x4)
|
|
||||||
);
|
|
||||||
|
|
||||||
self.regs.phy_cmd_timeout_rddata_cpt.modify(
|
|
||||||
|_, w| w
|
|
||||||
.rd_cmd_to_data(0x0)
|
|
||||||
.wr_cmd_to_data(0x0)
|
|
||||||
.we_to_re_delay(0x8)
|
|
||||||
.rdc_fifo_rst_disable(false)
|
|
||||||
.use_fixed_re(true)
|
|
||||||
.rdc_fifo_rst_err_cnt_clr(false)
|
|
||||||
.dis_phy_ctrl_rstn(false)
|
|
||||||
.clk_stall_level(false)
|
|
||||||
.gatelvl_num_of_dq0(0x7)
|
|
||||||
.wrlvl_num_of_dq0(0x7)
|
|
||||||
);
|
|
||||||
|
|
||||||
self.regs.reg_2c.write(
|
|
||||||
regs::Reg2C::zeroed()
|
|
||||||
.wrlvl_max_x1024(0xfff)
|
|
||||||
.rdlvl_max_x1024(0xfff)
|
|
||||||
.twrlvl_max_error(false)
|
|
||||||
.trdlvl_max_error(false)
|
|
||||||
.dfi_wr_level_en(true)
|
|
||||||
.dfi_rd_dqs_gate_level(true)
|
|
||||||
.dfi_rd_data_eye_train(true)
|
|
||||||
);
|
|
||||||
|
|
||||||
self.regs.dfi_timing.write(
|
|
||||||
regs::DfiTiming::zeroed()
|
|
||||||
.rddata_en(0x6)
|
|
||||||
.ctrlup_min(0x3)
|
|
||||||
.ctrlup_max(0x40)
|
|
||||||
);
|
|
||||||
|
|
||||||
self.regs.phy_init_ratio3.write(
|
|
||||||
regs::PhyInitRatio::zeroed()
|
|
||||||
.wrlvl_init_ratio(0x21)
|
|
||||||
.gatelvl_init_ratio(0xee)
|
|
||||||
);
|
|
||||||
|
|
||||||
self.regs.reg_65.write(
|
|
||||||
regs::Reg65::zeroed()
|
|
||||||
.wr_rl_delay(0x2)
|
|
||||||
.rd_rl_delay(0x4)
|
|
||||||
.dll_lock_diff(0xf)
|
|
||||||
.use_wr_level(true)
|
|
||||||
.use_rd_dqs_gate_level(true)
|
|
||||||
.use_rd_data_eye_level(true)
|
|
||||||
.dis_calib_rst(false)
|
|
||||||
.ctrl_slave_delay(0x0)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Reset DDR controller
|
/// Reset DDR controller
|
||||||
fn reset_ddrc(&mut self) {
|
fn reset_ddrc(&mut self) {
|
||||||
#[cfg(feature = "target_zc706")]
|
#[cfg(feature = "target_zc706")]
|
||||||
|
@ -320,8 +195,6 @@ impl DdrRam {
|
||||||
let width = regs::DataBusWidth::Width32bit;
|
let width = regs::DataBusWidth::Width32bit;
|
||||||
#[cfg(feature = "target_cora_z7_10")]
|
#[cfg(feature = "target_cora_z7_10")]
|
||||||
let width = regs::DataBusWidth::Width16bit;
|
let width = regs::DataBusWidth::Width16bit;
|
||||||
#[cfg(feature = "target_redpitaya")]
|
|
||||||
let width = regs::DataBusWidth::Width16bit;
|
|
||||||
self.regs.ddrc_ctrl.modify(|_, w| w
|
self.regs.ddrc_ctrl.modify(|_, w| w
|
||||||
.soft_rstb(false)
|
.soft_rstb(false)
|
||||||
.powerdown_en(false)
|
.powerdown_en(false)
|
||||||
|
@ -337,7 +210,7 @@ impl DdrRam {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn status(&self) -> regs::ControllerStatus {
|
pub fn status(&self) -> regs::ControllerStatus {
|
||||||
self.regs.mode_sts.read().operating_mode()
|
self.regs.mode_sts_reg.read().operating_mode()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ptr<T>(&mut self) -> *mut T {
|
pub fn ptr<T>(&mut self) -> *mut T {
|
||||||
|
@ -351,8 +224,6 @@ impl DdrRam {
|
||||||
let megabytes = 1023;
|
let megabytes = 1023;
|
||||||
#[cfg(feature = "target_cora_z7_10")]
|
#[cfg(feature = "target_cora_z7_10")]
|
||||||
let megabytes = 511;
|
let megabytes = 511;
|
||||||
#[cfg(feature = "target_redpitaya")]
|
|
||||||
let megabytes = 511;
|
|
||||||
|
|
||||||
megabytes * 1024 * 1024
|
megabytes * 1024 * 1024
|
||||||
}
|
}
|
||||||
|
@ -368,7 +239,7 @@ impl DdrRam {
|
||||||
|
|
||||||
for megabyte in 0..slice.len() / (1024 * 1024) {
|
for megabyte in 0..slice.len() / (1024 * 1024) {
|
||||||
let start = megabyte * 1024 * 1024 / 4;
|
let start = megabyte * 1024 * 1024 / 4;
|
||||||
let end = (megabyte + 1) * 1024 * 1024 / 4;
|
let end = ((megabyte + 1) * 1024 * 1024 / 4);
|
||||||
for b in slice[start..end].iter_mut() {
|
for b in slice[start..end].iter_mut() {
|
||||||
expected.map(|expected| {
|
expected.map(|expected| {
|
||||||
let read: u32 = *b;
|
let read: u32 = *b;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use volatile_register::{RO, RW};
|
use volatile_register::{RO, RW};
|
||||||
|
|
||||||
use libregister::{register, register_at, register_bit, register_bits, register_bits_typed};
|
use libregister::{register, register_bit, register_bits_typed};
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
|
@ -29,59 +29,59 @@ pub enum ControllerStatus {
|
||||||
pub struct RegisterBlock {
|
pub struct RegisterBlock {
|
||||||
pub ddrc_ctrl: DdrcCtrl,
|
pub ddrc_ctrl: DdrcCtrl,
|
||||||
pub two_rank_cfg: RW<u32>,
|
pub two_rank_cfg: RW<u32>,
|
||||||
pub hpr: RW<u32>,
|
pub hpr_reg: RW<u32>,
|
||||||
pub lpr: RW<u32>,
|
pub lpr_reg: RW<u32>,
|
||||||
pub wr: RW<u32>,
|
pub wr_reg: RW<u32>,
|
||||||
pub dram_param0: DramParam0,
|
pub dram_param_reg0: RW<u32>,
|
||||||
pub dram_param1: RW<u32>,
|
pub dram_param_reg1: RW<u32>,
|
||||||
pub dram_param2: DramParam2,
|
pub dram_param_reg2: RW<u32>,
|
||||||
pub dram_param3: RW<u32>,
|
pub dram_param_reg3: RW<u32>,
|
||||||
pub dram_param4: RW<u32>,
|
pub dram_param_reg4: RW<u32>,
|
||||||
pub dram_init_param: RW<u32>,
|
pub dram_init_param: RW<u32>,
|
||||||
pub dram_emr: RW<u32>,
|
pub dram_emr_reg: RW<u32>,
|
||||||
pub dram_emr_mr: DramEmrMr,
|
pub dram_emr_mr_reg: RW<u32>,
|
||||||
pub dram_burst8_rdwr: RW<u32>,
|
pub dram_burst8_rdwr: RW<u32>,
|
||||||
pub dram_disable_dq: RW<u32>,
|
pub dram_disable_dq: RW<u32>,
|
||||||
pub dram_addr_map_bank: RW<u32>,
|
pub dram_addr_map_bank: RW<u32>,
|
||||||
pub dram_addr_map_col: RW<u32>,
|
pub dram_addr_map_col: RW<u32>,
|
||||||
pub dram_addr_map_row: RW<u32>,
|
pub dram_addr_map_row: RW<u32>,
|
||||||
pub dram_odt: RW<u32>,
|
pub dram_odt_reg: RW<u32>,
|
||||||
pub phy_dbg: RW<u32>,
|
pub phy_dbg_reg: RW<u32>,
|
||||||
pub phy_cmd_timeout_rddata_cpt: PhyCmdTimeoutRddataCpt,
|
pub phy_cmd_timeout_rddata_cpt: RW<u32>,
|
||||||
pub mode_sts: ModeStsReg,
|
pub mode_sts_reg: ModeStsReg,
|
||||||
pub dll_calib: RW<u32>,
|
pub dll_calib: RW<u32>,
|
||||||
pub odt_delay_hold: RW<u32>,
|
pub odt_delay_hold: RW<u32>,
|
||||||
pub ctrl1: RW<u32>,
|
pub ctrl_reg1: RW<u32>,
|
||||||
pub ctrl2: RW<u32>,
|
pub ctrl_reg2: RW<u32>,
|
||||||
pub ctrl3: RW<u32>,
|
pub ctrl_reg3: RW<u32>,
|
||||||
pub ctrl4: RW<u32>,
|
pub ctrl_reg4: RW<u32>,
|
||||||
_unused0: [RO<u32>; 2],
|
_unused0: [RO<u32>; 2],
|
||||||
pub ctrl5: RW<u32>,
|
pub ctrl_reg5: RW<u32>,
|
||||||
pub ctrl6: RW<u32>,
|
pub ctrl_reg6: RW<u32>,
|
||||||
_unused1: [RO<u32>; 8],
|
_unused1: [RO<u32>; 8],
|
||||||
pub che_refresh_timer01: RW<u32>,
|
pub che_refresh_timer01: RW<u32>,
|
||||||
pub che_t_zq: RW<u32>,
|
pub che_t_zq: RW<u32>,
|
||||||
pub che_t_zq_short_interval: RW<u32>,
|
pub che_t_zq_short_interval_reg: RW<u32>,
|
||||||
pub deep_pwrdwn: RW<u32>,
|
pub deep_pwrdwn_reg: RW<u32>,
|
||||||
pub reg_2c: Reg2C,
|
pub reg_2c: RW<u32>,
|
||||||
pub reg_2d: RW<u32>,
|
pub reg_2d: RW<u32>,
|
||||||
pub dfi_timing: DfiTiming,
|
pub dfi_timing: RW<u32>,
|
||||||
_unused2: [RO<u32>; 2],
|
_unused2: [RO<u32>; 2],
|
||||||
pub che_ecc_control_offset: RW<u32>,
|
pub che_ecc_control_reg_offset: RW<u32>,
|
||||||
pub che_corr_ecc_log_offset: RW<u32>,
|
pub che_corr_ecc_log_reg_offset: RW<u32>,
|
||||||
pub che_corr_ecc_addr_offset: RW<u32>,
|
pub che_corr_ecc_addr_reg_offset: RW<u32>,
|
||||||
pub che_corr_ecc_data_31_0_offset: RW<u32>,
|
pub che_corr_ecc_data_31_0_reg_offset: RW<u32>,
|
||||||
pub che_corr_ecc_data_63_32_offset: RW<u32>,
|
pub che_corr_ecc_data_63_32_reg_offset: RW<u32>,
|
||||||
pub che_corr_ecc_data_71_64_offset: RW<u32>,
|
pub che_corr_ecc_data_71_64_reg_offset: RW<u32>,
|
||||||
pub che_uncorr_ecc_log_offset: RW<u32>,
|
pub che_uncorr_ecc_log_reg_offset: RW<u32>,
|
||||||
pub che_uncorr_ecc_addr_offset: RW<u32>,
|
pub che_uncorr_ecc_addr_reg_offset: RW<u32>,
|
||||||
pub che_uncorr_ecc_data_31_0_offset: RW<u32>,
|
pub che_uncorr_ecc_data_31_0_reg_offset: RW<u32>,
|
||||||
pub che_uncorr_ecc_data_63_32_offset: RW<u32>,
|
pub che_uncorr_ecc_data_63_32_reg_offset: RW<u32>,
|
||||||
pub che_uncorr_ecc_data_71_64_offset: RW<u32>,
|
pub che_uncorr_ecc_data_71_64_reg_offset: RW<u32>,
|
||||||
pub che_ecc_stats_offset: RW<u32>,
|
pub che_ecc_stats_reg_offset: RW<u32>,
|
||||||
pub ecc_scrub: RW<u32>,
|
pub ecc_scrub: RW<u32>,
|
||||||
pub che_ecc_corr_bit_mask_31_0_offset: RW<u32>,
|
pub che_ecc_corr_bit_mask_31_0_reg_offset: RW<u32>,
|
||||||
pub che_ecc_corr_bit_mask_63_32_offset: RW<u32>,
|
pub che_ecc_corr_bit_mask_63_32_reg_offset: RW<u32>,
|
||||||
_unused3: [RO<u32>; 5],
|
_unused3: [RO<u32>; 5],
|
||||||
pub phy_rcvr_enable: RW<u32>,
|
pub phy_rcvr_enable: RW<u32>,
|
||||||
pub phy_config0: RW<u32>,
|
pub phy_config0: RW<u32>,
|
||||||
|
@ -89,10 +89,10 @@ pub struct RegisterBlock {
|
||||||
pub phy_config2: RW<u32>,
|
pub phy_config2: RW<u32>,
|
||||||
pub phy_config3: RW<u32>,
|
pub phy_config3: RW<u32>,
|
||||||
_unused4: RO<u32>,
|
_unused4: RO<u32>,
|
||||||
pub phy_init_ratio0: PhyInitRatio,
|
pub phy_init_ratio0: RW<u32>,
|
||||||
pub phy_init_ratio1: PhyInitRatio,
|
pub phy_init_ratio1: RW<u32>,
|
||||||
pub phy_init_ratio2: PhyInitRatio,
|
pub phy_init_ratio2: RW<u32>,
|
||||||
pub phy_init_ratio3: PhyInitRatio,
|
pub phy_init_ratio3: RW<u32>,
|
||||||
_unused5: RO<u32>,
|
_unused5: RO<u32>,
|
||||||
pub phy_rd_dqs_cfg0: RW<u32>,
|
pub phy_rd_dqs_cfg0: RW<u32>,
|
||||||
pub phy_rd_dqs_cfg1: RW<u32>,
|
pub phy_rd_dqs_cfg1: RW<u32>,
|
||||||
|
@ -115,7 +115,7 @@ pub struct RegisterBlock {
|
||||||
pub wr_data_slv3: RW<u32>,
|
pub wr_data_slv3: RW<u32>,
|
||||||
_unused9: RO<u32>,
|
_unused9: RO<u32>,
|
||||||
pub reg_64: RW<u32>,
|
pub reg_64: RW<u32>,
|
||||||
pub reg_65: Reg65,
|
pub reg_65: RW<u32>,
|
||||||
_unused10: [RO<u32>; 3],
|
_unused10: [RO<u32>; 3],
|
||||||
pub reg69_6a0: RW<u32>,
|
pub reg69_6a0: RW<u32>,
|
||||||
pub reg69_6a1: RW<u32>,
|
pub reg69_6a1: RW<u32>,
|
||||||
|
@ -134,7 +134,7 @@ pub struct RegisterBlock {
|
||||||
_unused13: RO<u32>,
|
_unused13: RO<u32>,
|
||||||
pub dll_lock_sts: RW<u32>,
|
pub dll_lock_sts: RW<u32>,
|
||||||
pub phy_ctrl_sts: RW<u32>,
|
pub phy_ctrl_sts: RW<u32>,
|
||||||
pub phy_ctrl_sts2: RW<u32>,
|
pub phy_ctrl_sts_reg2: RW<u32>,
|
||||||
_unused14: [RO<u32>; 5],
|
_unused14: [RO<u32>; 5],
|
||||||
pub axi_id: RW<u32>,
|
pub axi_id: RW<u32>,
|
||||||
pub page_mask: RW<u32>,
|
pub page_mask: RW<u32>,
|
||||||
|
@ -158,7 +158,11 @@ pub struct RegisterBlock {
|
||||||
pub lpddr_ctrl3: RW<u32>,
|
pub lpddr_ctrl3: RW<u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
register_at!(RegisterBlock, 0xF8006000, ddrc);
|
impl RegisterBlock {
|
||||||
|
pub unsafe fn new() -> &'static mut Self {
|
||||||
|
&mut *(0xF8006000 as *mut _)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
register!(ddrc_ctrl, DdrcCtrl, RW, u32);
|
register!(ddrc_ctrl, DdrcCtrl, RW, u32);
|
||||||
register_bit!(ddrc_ctrl,
|
register_bit!(ddrc_ctrl,
|
||||||
|
@ -168,64 +172,6 @@ register_bit!(ddrc_ctrl, powerdown_en, 1);
|
||||||
register_bits_typed!(ddrc_ctrl, data_bus_width, u8, DataBusWidth, 2, 3);
|
register_bits_typed!(ddrc_ctrl, data_bus_width, u8, DataBusWidth, 2, 3);
|
||||||
// (ddrc_ctrl) ...
|
// (ddrc_ctrl) ...
|
||||||
|
|
||||||
register!(dram_param0, DramParam0, RW, u32);
|
|
||||||
register_bits!(dram_param0, t_rc, u8, 0, 5);
|
|
||||||
register_bits!(dram_param0, t_rfc_min, u8, 6, 13);
|
|
||||||
register_bits!(dram_param0, post_selfref_gap_x32, u8, 14, 20);
|
|
||||||
|
|
||||||
register!(dram_param2, DramParam2, RW, u32);
|
|
||||||
register_bits!(dram_param2, write_latency, u8, 0, 4);
|
|
||||||
register_bits!(dram_param2, rd2wr, u8, 5, 9);
|
|
||||||
register_bits!(dram_param2, wr2rd, u8, 10, 14);
|
|
||||||
register_bits!(dram_param2, t_xp, u8, 15, 19);
|
|
||||||
register_bits!(dram_param2, pad_pd, u8, 20, 22);
|
|
||||||
register_bits!(dram_param2, rd2pre, u8, 23, 27);
|
|
||||||
register_bits!(dram_param2, t_rcd, u8, 28, 31);
|
|
||||||
|
|
||||||
register!(dram_emr_mr, DramEmrMr, RW, u32);
|
|
||||||
register_bits!(dram_emr_mr, mr, u16, 0, 15);
|
|
||||||
register_bits!(dram_emr_mr, emr, u16, 16, 31);
|
|
||||||
|
|
||||||
register!(phy_cmd_timeout_rddata_cpt, PhyCmdTimeoutRddataCpt, RW, u32);
|
|
||||||
register_bits!(phy_cmd_timeout_rddata_cpt, rd_cmd_to_data, u8, 0, 3);
|
|
||||||
register_bits!(phy_cmd_timeout_rddata_cpt, wr_cmd_to_data, u8, 4, 7);
|
|
||||||
register_bits!(phy_cmd_timeout_rddata_cpt, we_to_re_delay, u8, 8, 11);
|
|
||||||
register_bit!(phy_cmd_timeout_rddata_cpt, rdc_fifo_rst_disable, 15);
|
|
||||||
register_bit!(phy_cmd_timeout_rddata_cpt, use_fixed_re, 16);
|
|
||||||
register_bit!(phy_cmd_timeout_rddata_cpt, rdc_fifo_rst_err_cnt_clr, 17);
|
|
||||||
register_bit!(phy_cmd_timeout_rddata_cpt, dis_phy_ctrl_rstn, 18);
|
|
||||||
register_bit!(phy_cmd_timeout_rddata_cpt, clk_stall_level, 19);
|
|
||||||
register_bits!(phy_cmd_timeout_rddata_cpt, gatelvl_num_of_dq0, u8, 24, 27);
|
|
||||||
register_bits!(phy_cmd_timeout_rddata_cpt, wrlvl_num_of_dq0, u8, 28, 31);
|
|
||||||
|
|
||||||
register!(reg_2c, Reg2C, RW, u32);
|
|
||||||
register_bits!(reg_2c, wrlvl_max_x1024, u16, 0, 11);
|
|
||||||
register_bits!(reg_2c, rdlvl_max_x1024, u16, 12, 23);
|
|
||||||
register_bit!(reg_2c, twrlvl_max_error, 24);
|
|
||||||
register_bit!(reg_2c, trdlvl_max_error, 25);
|
|
||||||
register_bit!(reg_2c, dfi_wr_level_en, 26);
|
|
||||||
register_bit!(reg_2c, dfi_rd_dqs_gate_level, 27);
|
|
||||||
register_bit!(reg_2c, dfi_rd_data_eye_train, 28);
|
|
||||||
|
|
||||||
register!(dfi_timing, DfiTiming, RW, u32);
|
|
||||||
register_bits!(dfi_timing, rddata_en, u8, 0, 4);
|
|
||||||
register_bits!(dfi_timing, ctrlup_min, u16, 5, 14);
|
|
||||||
register_bits!(dfi_timing, ctrlup_max, u16, 15, 24);
|
|
||||||
|
|
||||||
register!(phy_init_ratio, PhyInitRatio, RW, u32);
|
|
||||||
register_bits!(phy_init_ratio, wrlvl_init_ratio, u16, 0, 9);
|
|
||||||
register_bits!(phy_init_ratio, gatelvl_init_ratio, u16, 10, 19);
|
|
||||||
|
|
||||||
register!(reg_65, Reg65, RW, u32);
|
|
||||||
register_bits!(reg_65, wr_rl_delay, u8, 0, 4);
|
|
||||||
register_bits!(reg_65, rd_rl_delay, u8, 5, 9);
|
|
||||||
register_bits!(reg_65, dll_lock_diff, u8, 10, 13);
|
|
||||||
register_bit!(reg_65, use_wr_level, 14);
|
|
||||||
register_bit!(reg_65, use_rd_dqs_gate_level, 15);
|
|
||||||
register_bit!(reg_65, use_rd_data_eye_level, 16);
|
|
||||||
register_bit!(reg_65, dis_calib_rst, 17);
|
|
||||||
register_bits!(reg_65, ctrl_slave_delay, u8, 18, 19);
|
|
||||||
|
|
||||||
// Controller operation mode status
|
// Controller operation mode status
|
||||||
register!(mode_sts_reg,
|
register!(mode_sts_reg,
|
||||||
ModeStsReg, RO, u32);
|
ModeStsReg, RO, u32);
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use super::clocks::Clocks;
|
||||||
use super::time::Milliseconds;
|
use super::time::Milliseconds;
|
||||||
use crate::slcr;
|
use crate::slcr;
|
||||||
use embedded_hal::timer::CountDown;
|
use embedded_hal::timer::CountDown;
|
||||||
|
@ -10,7 +11,7 @@ mod regs;
|
||||||
pub struct DevC {
|
pub struct DevC {
|
||||||
regs: &'static mut regs::RegisterBlock,
|
regs: &'static mut regs::RegisterBlock,
|
||||||
enabled: bool,
|
enabled: bool,
|
||||||
count_down: super::timer::global::CountDown<Milliseconds>,
|
count_down: super::timer::global::CountDown,
|
||||||
timeout_ms: Milliseconds,
|
timeout_ms: Milliseconds,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
//! PrimeCell DMA Controller (PL330)
|
||||||
|
|
||||||
|
mod regs;
|
|
@ -0,0 +1,386 @@
|
||||||
|
use libregister::{
|
||||||
|
register, register_at,
|
||||||
|
register_bit, register_bits, register_bits_typed,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct RegisterBlock {
|
||||||
|
pub ds: Ds,
|
||||||
|
pub dpc: DPc,
|
||||||
|
pub inten: Inten,
|
||||||
|
pub es: Es,
|
||||||
|
pub intstatus: IntStatus,
|
||||||
|
pub intclr: IntClr,
|
||||||
|
pub fsm: Fsm,
|
||||||
|
pub fsc: Fsc,
|
||||||
|
pub ftm: Ftm,
|
||||||
|
pub ftc: [Ftc; 8],
|
||||||
|
pub cs0: Cs,
|
||||||
|
pub cpc0: Cpc,
|
||||||
|
pub cs1: Cs,
|
||||||
|
pub cpc1: Cpc,
|
||||||
|
pub cs2: Cs,
|
||||||
|
pub cpc2: Cpc,
|
||||||
|
pub cs3: Cs,
|
||||||
|
pub cpc3: Cpc,
|
||||||
|
pub cs4: Cs,
|
||||||
|
pub cpc4: Cpc,
|
||||||
|
pub cs5: Cs,
|
||||||
|
pub cpc5: Cpc,
|
||||||
|
pub cs6: Cs,
|
||||||
|
pub cpc6: Cpc,
|
||||||
|
pub cs7: Cs,
|
||||||
|
pub cpc7: Cpc,
|
||||||
|
pub sa0: Sa,
|
||||||
|
pub da0: Da,
|
||||||
|
pub cc0: Cc,
|
||||||
|
pub lc0_0: Lc,
|
||||||
|
pub lc0_1: Lc,
|
||||||
|
pub sa1: Sa,
|
||||||
|
pub da1: Da,
|
||||||
|
pub cc1: Cc,
|
||||||
|
pub lc1_0: Lc,
|
||||||
|
pub lc1_1: Lc,
|
||||||
|
pub sa2: Sa,
|
||||||
|
pub da2: Da,
|
||||||
|
pub cc2: Cc,
|
||||||
|
pub lc2_0: Lc,
|
||||||
|
pub lc2_1: Lc,
|
||||||
|
pub sa3: Sa,
|
||||||
|
pub da3: Da,
|
||||||
|
pub cc3: Cc,
|
||||||
|
pub lc3_0: Lc,
|
||||||
|
pub lc3_1: Lc,
|
||||||
|
pub sa4: Sa,
|
||||||
|
pub da4: Da,
|
||||||
|
pub cc4: Cc,
|
||||||
|
pub lc4_0: Lc,
|
||||||
|
pub lc4_1: Lc,
|
||||||
|
pub sa5: Sa,
|
||||||
|
pub da5: Da,
|
||||||
|
pub cc5: Cc,
|
||||||
|
pub lc5_0: Lc,
|
||||||
|
pub lc5_1: Lc,
|
||||||
|
pub sa6: Sa,
|
||||||
|
pub da6: Da,
|
||||||
|
pub cc6: Cc,
|
||||||
|
pub lc6_0: Lc,
|
||||||
|
pub lc6_1: Lc,
|
||||||
|
pub sa7: Sa,
|
||||||
|
pub da7: Da,
|
||||||
|
pub cc7: Cc,
|
||||||
|
pub lc7_0: Lc,
|
||||||
|
pub lc7_1: Lc,
|
||||||
|
pub dbgstatus: DbgStatus,
|
||||||
|
pub dbgcmd: DbgCmd,
|
||||||
|
pub dbginst0: DbgInst0,
|
||||||
|
pub dbginst1: DbgInst1,
|
||||||
|
pub cr0: Cr0,
|
||||||
|
pub cr1: Cr1,
|
||||||
|
pub cr2: Cr2,
|
||||||
|
pub cr3: Cr3,
|
||||||
|
pub cr4: Cr4,
|
||||||
|
pub crdn: Crdn,
|
||||||
|
pub wd: Wd,
|
||||||
|
pub periph_id_0: PeriphId0,
|
||||||
|
pub periph_id_1: PeriphId1,
|
||||||
|
pub periph_id_2: PeriphId2,
|
||||||
|
pub periph_id_3: PeriphId3,
|
||||||
|
pub pcell_id_0: PCellId0,
|
||||||
|
pub pcell_id_1: PCellId1,
|
||||||
|
pub pcell_id_2: PCellId2,
|
||||||
|
pub pcell_id_3: PCellId3,
|
||||||
|
}
|
||||||
|
|
||||||
|
register_at!(RegisterBlock, 0xF8004000, dmac0_ns);
|
||||||
|
register_at!(RegisterBlock, 0xF8003000, dmac0_s);
|
||||||
|
|
||||||
|
impl RegisterBlock {
|
||||||
|
pub fn channel_regs(&mut self, channel: usize) -> Option<ChannelRegisters>
|
||||||
|
{
|
||||||
|
match channel {
|
||||||
|
0 => Some(ChannelRegisters {
|
||||||
|
ftc: &mut self.ftc[0],
|
||||||
|
cs: &mut self.cs0,
|
||||||
|
cpc: &mut self.cpc0,
|
||||||
|
sa: &mut self.sa0,
|
||||||
|
da: &mut self.da0,
|
||||||
|
cc: &mut self.cc0,
|
||||||
|
lc: [&mut self.lc0_0, &mut self.lc0_1],
|
||||||
|
}),
|
||||||
|
1 => Some(ChannelRegisters {
|
||||||
|
ftc: &mut self.ftc[1],
|
||||||
|
cs: &mut self.cs1,
|
||||||
|
cpc: &mut self.cpc1,
|
||||||
|
sa: &mut self.sa1,
|
||||||
|
da: &mut self.da1,
|
||||||
|
cc: &mut self.cc1,
|
||||||
|
lc: [&mut self.lc1_0, &mut self.lc1_1],
|
||||||
|
}),
|
||||||
|
2 => Some(ChannelRegisters {
|
||||||
|
ftc: &mut self.ftc[2],
|
||||||
|
cs: &mut self.cs2,
|
||||||
|
cpc: &mut self.cpc2,
|
||||||
|
sa: &mut self.sa2,
|
||||||
|
da: &mut self.da2,
|
||||||
|
cc: &mut self.cc2,
|
||||||
|
lc: [&mut self.lc2_0, &mut self.lc2_1],
|
||||||
|
}),
|
||||||
|
3 => Some(ChannelRegisters {
|
||||||
|
ftc: &mut self.ftc[3],
|
||||||
|
cs: &mut self.cs3,
|
||||||
|
cpc: &mut self.cpc3,
|
||||||
|
sa: &mut self.sa3,
|
||||||
|
da: &mut self.da3,
|
||||||
|
cc: &mut self.cc3,
|
||||||
|
lc: [&mut self.lc3_0, &mut self.lc3_1],
|
||||||
|
}),
|
||||||
|
4 => Some(ChannelRegisters {
|
||||||
|
ftc: &mut self.ftc[4],
|
||||||
|
cs: &mut self.cs4,
|
||||||
|
cpc: &mut self.cpc4,
|
||||||
|
sa: &mut self.sa4,
|
||||||
|
da: &mut self.da4,
|
||||||
|
cc: &mut self.cc4,
|
||||||
|
lc: [&mut self.lc4_0, &mut self.lc4_1],
|
||||||
|
}),
|
||||||
|
5 => Some(ChannelRegisters {
|
||||||
|
ftc: &mut self.ftc[5],
|
||||||
|
cs: &mut self.cs5,
|
||||||
|
cpc: &mut self.cpc5,
|
||||||
|
sa: &mut self.sa5,
|
||||||
|
da: &mut self.da5,
|
||||||
|
cc: &mut self.cc5,
|
||||||
|
lc: [&mut self.lc5_0, &mut self.lc5_1],
|
||||||
|
}),
|
||||||
|
6 => Some(ChannelRegisters {
|
||||||
|
ftc: &mut self.ftc[6],
|
||||||
|
cs: &mut self.cs6,
|
||||||
|
cpc: &mut self.cpc6,
|
||||||
|
sa: &mut self.sa6,
|
||||||
|
da: &mut self.da6,
|
||||||
|
cc: &mut self.cc6,
|
||||||
|
lc: [&mut self.lc6_0, &mut self.lc6_1],
|
||||||
|
}),
|
||||||
|
7 => Some(ChannelRegisters {
|
||||||
|
ftc: &mut self.ftc[7],
|
||||||
|
cs: &mut self.cs7,
|
||||||
|
cpc: &mut self.cpc7,
|
||||||
|
sa: &mut self.sa7,
|
||||||
|
da: &mut self.da7,
|
||||||
|
cc: &mut self.cc7,
|
||||||
|
lc: [&mut self.lc7_0, &mut self.lc7_1],
|
||||||
|
}),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ChannelRegisters<'a> {
|
||||||
|
ftc: &'a mut Ftc,
|
||||||
|
cs: &'a mut Cs,
|
||||||
|
cpc: &'a mut Cpc,
|
||||||
|
sa: &'a mut Sa,
|
||||||
|
da: &'a mut Da,
|
||||||
|
cc: &'a mut Cc,
|
||||||
|
lc: [&'a mut Lc; 2],
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
#[repr(u8)]
|
||||||
|
pub enum WakeUpEvent{
|
||||||
|
// @missing: there's a binary prefix ahead of this as per TRM 1173 Wakeup_event
|
||||||
|
Event0 = 0b0000,
|
||||||
|
Event1 = 0b0001,
|
||||||
|
Event2 = 0b0010,
|
||||||
|
Event3 = 0b0011,
|
||||||
|
Event4 = 0b0100,
|
||||||
|
Event5 = 0b0101,
|
||||||
|
Event6 = 0b0110,
|
||||||
|
Event7 = 0b0111,
|
||||||
|
Event8 = 0b1000,
|
||||||
|
Event9 = 0b1001,
|
||||||
|
Event10 = 0b1010,
|
||||||
|
Event11 = 0b1011,
|
||||||
|
Event12 = 0b1100,
|
||||||
|
Event13 = 0b1101,
|
||||||
|
Event14 = 0b1110,
|
||||||
|
Event15 = 0b1111,
|
||||||
|
}
|
||||||
|
#[allow(unused)]
|
||||||
|
#[repr(u8)]
|
||||||
|
pub enum DMAStatus{
|
||||||
|
Stopped = 0b0000,
|
||||||
|
Executing = 0b0001,
|
||||||
|
CacheMiss = 0b0010,
|
||||||
|
UpdatingPc = 0b0011,
|
||||||
|
WaitingForEvent = 0b0100,
|
||||||
|
Reserved0 = 0b0101,
|
||||||
|
Reserved1 = 0b0110,
|
||||||
|
Reserved2 = 0b0111,
|
||||||
|
Reserved3 = 0b1000,
|
||||||
|
Reserved4 = 0b1001,
|
||||||
|
Reserved5 = 0b1010,
|
||||||
|
Reserved6 = 0b1011,
|
||||||
|
Reserved7 = 0b1100,
|
||||||
|
Reserved8 = 0b1101,
|
||||||
|
Reserved9 = 0b1110,
|
||||||
|
Faulting = 0b1111,
|
||||||
|
}
|
||||||
|
|
||||||
|
register!(ds, Ds, RW, u32);
|
||||||
|
register_bit!(ds, dns, 9);
|
||||||
|
register_bits_typed!(ds, wakeup_event, u8, WakeUpEvent, 4, 8);
|
||||||
|
register_bits_typed!(ds, dma_status, u8, DMAStatus, 0, 3);
|
||||||
|
|
||||||
|
register!(dpc, DPc, RW, u32);
|
||||||
|
register_bits!(dpc, pc_mgr, u8, 0, 31);
|
||||||
|
|
||||||
|
register!(inten, Inten, RW, u32);
|
||||||
|
register_bits!(inten, event_irq_select, u8, 0, 31);
|
||||||
|
|
||||||
|
register!(es, Es, RW, u32);
|
||||||
|
register_bits!(es, dmasev_active, u8, 0, 31);
|
||||||
|
|
||||||
|
register!(intstatus, IntStatus, RW, u32);
|
||||||
|
register_bits!(intstatus, irq_status, u8, 0, 31);
|
||||||
|
|
||||||
|
register!(intclr, IntClr, RW, u32);
|
||||||
|
register_bits!(intstatus, irq_clr, u8, 0, 31);
|
||||||
|
|
||||||
|
register!(fsm, Fsm, RW, u32);
|
||||||
|
register_bit!(fsm, fs_mgr, 0);
|
||||||
|
|
||||||
|
register!(fsc, Fsc, RW, u32);
|
||||||
|
register_bits!(fsc, fault_status, u8, 0, 7);
|
||||||
|
|
||||||
|
register!(ftm, Ftm, RW, u32);
|
||||||
|
register_bit!(ftm, dbg_instr, 30);
|
||||||
|
register_bit!(ftm, instr_fetch_err, 16);
|
||||||
|
register_bit!(ftm, mgr_evnt_err, 5);
|
||||||
|
register_bit!(ftm, dmago_err, 4);
|
||||||
|
register_bit!(ftm, operand_invalid, 1);
|
||||||
|
register_bit!(ftm, undef_instr, 0);
|
||||||
|
|
||||||
|
register!(ftc, Ftc, RW, u32);
|
||||||
|
register_bit!(ftc, lockup_err, 31);
|
||||||
|
register_bit!(ftc, dbg_instr, 30);
|
||||||
|
register_bit!(ftc, data_read_err, 18);
|
||||||
|
register_bit!(ftc, data_write_err, 17);
|
||||||
|
register_bit!(ftc, instr_fetch_err, 16);
|
||||||
|
register_bit!(ftc, st_data_unavailable, 13);
|
||||||
|
register_bit!(ftc, mfifo_err, 12);
|
||||||
|
register_bit!(ftc, ch_rdwr_err, 7);
|
||||||
|
register_bit!(ftc, ch_periph_err, 6);
|
||||||
|
register_bit!(ftc, ch_evnt_err, 5);
|
||||||
|
register_bit!(ftc, operand_invalid, 1);
|
||||||
|
register_bit!(ftc, undef_instr, 0);
|
||||||
|
|
||||||
|
register!(cs, Cs, RW, u32);
|
||||||
|
register_bit!(cs, cns, 21);
|
||||||
|
register_bit!(cs, dmawfp_periph, 15);
|
||||||
|
register_bit!(cs, dmawfp_b_ns, 14);
|
||||||
|
register_bits!(cs, wakeup_num, u8, 4, 8);
|
||||||
|
register_bits!(cs, channel_status, u8, 0, 3);
|
||||||
|
|
||||||
|
register!(cpc, Cpc, RW, u32);
|
||||||
|
register_bits!(cpc, pc_chnl, u8, 0, 31);
|
||||||
|
|
||||||
|
register!(sa, Sa, RW, u32);
|
||||||
|
register_bits!(sa, src_addr, u8, 0, 31);
|
||||||
|
|
||||||
|
register!(da, Da, RW, u32);
|
||||||
|
register_bits!(da, dest_addr, u8, 0, 31);
|
||||||
|
|
||||||
|
register!(cc, Cc, RW, u32);
|
||||||
|
register_bits!(cc, endian_swap_size, u8, 28, 30);
|
||||||
|
register_bits!(cc, dst_cache_ctrl, u8, 25, 27);
|
||||||
|
register_bits!(cc, dst_prot_ctrl, u8, 22, 24);
|
||||||
|
register_bits!(cc, dst_burst_len, u8, 18, 21);
|
||||||
|
register_bits!(cc, dst_burst_size, u8, 15, 17);
|
||||||
|
register_bit!(cc, dst_inc, 14);
|
||||||
|
register_bits!(cc, src_cache_ctrl, u8, 11, 13);
|
||||||
|
register_bits!(cc, src_prot_ctrl, u8, 8, 10);
|
||||||
|
register_bits!(cc, src_burst_len, u8, 4, 7);
|
||||||
|
register_bits!(cc, src_burst_size, u8, 1, 3);
|
||||||
|
register_bit!(cc, src_inc, 0);
|
||||||
|
|
||||||
|
register!(lc0, Lc, RW, u32);
|
||||||
|
register_bits!(lc0, loop_counter_iteration, u8, 0, 7);
|
||||||
|
|
||||||
|
register!(dbgstatus, DbgStatus, RW, u32);
|
||||||
|
register_bit!(dbgstatus, dbgstatus, 0);
|
||||||
|
|
||||||
|
register!(dbgcmd, DbgCmd, RW, u32);
|
||||||
|
register_bits!(dbgcmd, dbgcmd, u8, 0, 1);
|
||||||
|
|
||||||
|
register!(dbginst0, DbgInst0, RW, u32);
|
||||||
|
register_bits!(dbginst0, instruction_byte1, u8, 24, 31);
|
||||||
|
register_bits!(dbginst0, instruction_byte0, u8, 16, 23);
|
||||||
|
register_bits!(dbginst0, channel_num, u8, 8, 10);
|
||||||
|
register_bit!(dbginst0, debug_thread, 0);
|
||||||
|
|
||||||
|
register!(dbginst1, DbgInst1, RW, u32);
|
||||||
|
register_bits!(dbginst1, instruction_byte5, u8, 24, 31);
|
||||||
|
register_bits!(dbginst1, instruction_byte4, u8, 16, 23);
|
||||||
|
register_bits!(dbginst1, instruction_byte3, u8, 8, 10);
|
||||||
|
register_bits!(dbginst1, instruction_byte2, u8, 0, 7);
|
||||||
|
|
||||||
|
register!(cr0, Cr0, RW, u32);
|
||||||
|
register_bits!(cr0, num_events, u8, 17, 21);
|
||||||
|
register_bits!(cr0, num_periph_req, u8, 12, 16);
|
||||||
|
register_bits!(cr0, num_chnls, u8, 4, 6);
|
||||||
|
register_bit!(cr0, mgr_ns_at_rst, 2);
|
||||||
|
register_bit!(cr0, boot_en, 1);
|
||||||
|
register_bit!(cr0, periph_req, 0);
|
||||||
|
|
||||||
|
register!(cr1, Cr1, RW, u32);
|
||||||
|
register_bits!(cr1, num_icache_lines, u8, 4, 7);
|
||||||
|
register_bits!(cr1, icache_len, u8, 0, 2);
|
||||||
|
|
||||||
|
register!(cr2, Cr2, RW, u32);
|
||||||
|
register_bits!(cr2, boot_addr, u8, 0, 31);
|
||||||
|
|
||||||
|
register!(cr3, Cr3, RW, u32);
|
||||||
|
register_bits!(cr3, ins, u8, 0, 31);
|
||||||
|
|
||||||
|
register!(cr4, Cr4, RW, u32);
|
||||||
|
register_bits!(cr4, ins, u8, 0, 31);
|
||||||
|
|
||||||
|
register!(crdn, Crdn, RW, u32);
|
||||||
|
register_bits!(crdn, data_buffer_dep, u8, 20, 29);
|
||||||
|
register_bits!(crdn, rd_q_dep, u8, 16, 19);
|
||||||
|
register_bits!(crdn, rd_cap, u8, 12, 14);
|
||||||
|
register_bits!(crdn, wr_q_dep, u8, 8, 11);
|
||||||
|
register_bits!(crdn, wr_cap, u8, 4, 6);
|
||||||
|
register_bits!(crdn, data_width, u8, 0, 2);
|
||||||
|
|
||||||
|
register!(wd, Wd, RW, u32);
|
||||||
|
register_bit!(wd, wd_irq_only, 0);
|
||||||
|
|
||||||
|
register!(periph_id_0, PeriphId0, RW, u32);
|
||||||
|
register_bits!(periph_id_0, part_number_0, u8, 0, 7);
|
||||||
|
|
||||||
|
register!(periph_id_1, PeriphId1, RW, u32);
|
||||||
|
register_bits!(periph_id_1, designer_0, u8, 4, 7);
|
||||||
|
register_bits!(periph_id_1, part_number_1, u8, 0, 3);
|
||||||
|
|
||||||
|
register!(periph_id_2, PeriphId2, RW, u32);
|
||||||
|
register_bits!(periph_id_2, revision, u8, 4, 7);
|
||||||
|
register_bits!(periph_id_2, designer_1, u8, 0, 3);
|
||||||
|
|
||||||
|
register!(periph_id_3, PeriphId3, RW, u32);
|
||||||
|
register_bit!(periph_id_3, integration_cfg, 0);
|
||||||
|
|
||||||
|
register!(pcell_id_0, PCellId0, RW, u32);
|
||||||
|
register_bits!(pcell_id_0, pcell_id_0, u8, 0, 7);
|
||||||
|
|
||||||
|
register!(pcell_id_1, PCellId1, RW, u32);
|
||||||
|
register_bits!(pcell_id_1, pcell_id_1, u8, 0, 7);
|
||||||
|
|
||||||
|
register!(pcell_id_2, PCellId2, RW, u32);
|
||||||
|
register_bits!(pcell_id_2, pcell_id_2, u8, 0, 7);
|
||||||
|
|
||||||
|
register!(pcell_id_3, PCellId3, RW, u32);
|
||||||
|
register_bits!(pcell_id_3, pcell_id_3, u8, 0, 7);
|
|
@ -1,8 +1,5 @@
|
||||||
use core::{
|
use core::ops::{Deref, DerefMut};
|
||||||
marker::PhantomData,
|
use log::{error, info, warn};
|
||||||
ops::{Deref, DerefMut},
|
|
||||||
};
|
|
||||||
use log::{debug, info, warn, error};
|
|
||||||
use libregister::*;
|
use libregister::*;
|
||||||
use super::slcr;
|
use super::slcr;
|
||||||
use super::clocks::Clocks;
|
use super::clocks::Clocks;
|
||||||
|
@ -27,7 +24,7 @@ const TX_1000: u32 = 125_000_000;
|
||||||
pub struct Buffer(pub [u8; MTU]);
|
pub struct Buffer(pub [u8; MTU]);
|
||||||
|
|
||||||
impl Buffer {
|
impl Buffer {
|
||||||
pub const fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Buffer([0; MTU])
|
Buffer([0; MTU])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -45,110 +42,15 @@ impl DerefMut for Buffer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gigabit Ethernet Peripheral
|
pub struct Eth<'r, RX, TX> {
|
||||||
pub trait Gem {
|
|
||||||
fn setup_clock(tx_clock: u32);
|
|
||||||
fn regs() -> &'static mut regs::RegisterBlock;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// first Gigabit Ethernet peripheral
|
|
||||||
pub struct Gem0;
|
|
||||||
|
|
||||||
impl Gem for Gem0 {
|
|
||||||
fn setup_clock(tx_clock: u32) {
|
|
||||||
let (divisor0, divisor1) = calculate_tx_divisors(tx_clock);
|
|
||||||
|
|
||||||
slcr::RegisterBlock::unlocked(|slcr| {
|
|
||||||
slcr.gem0_clk_ctrl.write(
|
|
||||||
// 0x0050_0801: 8, 5: 100 Mb/s
|
|
||||||
// ...: 8, 1: 1000 Mb/s
|
|
||||||
slcr::GemClkCtrl::zeroed()
|
|
||||||
.clkact(true)
|
|
||||||
.srcsel(slcr::PllSource::IoPll)
|
|
||||||
.divisor(divisor0 as u8)
|
|
||||||
.divisor1(divisor1 as u8)
|
|
||||||
);
|
|
||||||
// Enable gem0 recv clock
|
|
||||||
slcr.gem0_rclk_ctrl.write(
|
|
||||||
// 0x0000_0801
|
|
||||||
slcr::RclkCtrl::zeroed()
|
|
||||||
.clkact(true)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
fn regs() -> &'static mut regs::RegisterBlock {
|
|
||||||
regs::RegisterBlock::gem0()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// second Gigabit Ethernet peripheal
|
|
||||||
pub struct Gem1;
|
|
||||||
|
|
||||||
impl Gem for Gem1 {
|
|
||||||
fn setup_clock(tx_clock: u32) {
|
|
||||||
let (divisor0, divisor1) = calculate_tx_divisors(tx_clock);
|
|
||||||
|
|
||||||
slcr::RegisterBlock::unlocked(|slcr| {
|
|
||||||
slcr.gem1_clk_ctrl.write(
|
|
||||||
slcr::GemClkCtrl::zeroed()
|
|
||||||
.clkact(true)
|
|
||||||
.srcsel(slcr::PllSource::IoPll)
|
|
||||||
.divisor(divisor0 as u8)
|
|
||||||
.divisor1(divisor1 as u8)
|
|
||||||
);
|
|
||||||
// Enable gem1 recv clock
|
|
||||||
slcr.gem1_rclk_ctrl.write(
|
|
||||||
// 0x0000_0801
|
|
||||||
slcr::RclkCtrl::zeroed()
|
|
||||||
.clkact(true)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
fn regs() -> &'static mut regs::RegisterBlock {
|
|
||||||
regs::RegisterBlock::gem1()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn calculate_tx_divisors(tx_clock: u32) -> (u8, u8) {
|
|
||||||
let io_pll = Clocks::get().io;
|
|
||||||
let target = (tx_clock - 1 + io_pll) / tx_clock;
|
|
||||||
|
|
||||||
let mut best = None;
|
|
||||||
let mut best_error = 0;
|
|
||||||
for divisor0 in 1..63 {
|
|
||||||
for divisor1 in 1..63 {
|
|
||||||
let current = (divisor0 as u32) * (divisor1 as u32);
|
|
||||||
let error = if current > target {
|
|
||||||
current - target
|
|
||||||
} else {
|
|
||||||
target - current
|
|
||||||
};
|
|
||||||
if best.is_none() || best_error > error {
|
|
||||||
best = Some((divisor0, divisor1));
|
|
||||||
best_error = error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let result = best.unwrap();
|
|
||||||
debug!("Eth TX clock for {}: {} / {} / {} = {}",
|
|
||||||
tx_clock, io_pll,
|
|
||||||
result.0, result.1,
|
|
||||||
io_pll / result.0 as u32 / result.1 as u32
|
|
||||||
);
|
|
||||||
result
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Eth<GEM: Gem, RX, TX> {
|
|
||||||
rx: RX,
|
rx: RX,
|
||||||
tx: TX,
|
tx: TX,
|
||||||
inner: EthInner<GEM>,
|
inner: EthInner<'r>,
|
||||||
phy: Phy,
|
phy: Phy,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Eth<Gem0, (), ()> {
|
impl<'r> Eth<'r, (), ()> {
|
||||||
pub fn eth0(macaddr: [u8; 6]) -> Self {
|
pub fn default(macaddr: [u8; 6]) -> Self {
|
||||||
slcr::RegisterBlock::unlocked(|slcr| {
|
slcr::RegisterBlock::unlocked(|slcr| {
|
||||||
// Manual example: 0x0000_1280
|
// Manual example: 0x0000_1280
|
||||||
// MDIO
|
// MDIO
|
||||||
|
@ -224,48 +126,48 @@ impl Eth<Gem0, (), ()> {
|
||||||
// RX_CLK
|
// RX_CLK
|
||||||
slcr.mio_pin_22.write(
|
slcr.mio_pin_22.write(
|
||||||
slcr::MioPin22::zeroed()
|
slcr::MioPin22::zeroed()
|
||||||
|
.tri_enable(true)
|
||||||
.l0_sel(true)
|
.l0_sel(true)
|
||||||
.speed(true)
|
|
||||||
.io_type(slcr::IoBufferType::Hstl)
|
.io_type(slcr::IoBufferType::Hstl)
|
||||||
.pullup(true)
|
.pullup(true)
|
||||||
);
|
);
|
||||||
// RX_CTRL
|
// RX_CTRL
|
||||||
slcr.mio_pin_27.write(
|
slcr.mio_pin_27.write(
|
||||||
slcr::MioPin27::zeroed()
|
slcr::MioPin27::zeroed()
|
||||||
|
.tri_enable(true)
|
||||||
.l0_sel(true)
|
.l0_sel(true)
|
||||||
.speed(true)
|
|
||||||
.io_type(slcr::IoBufferType::Hstl)
|
.io_type(slcr::IoBufferType::Hstl)
|
||||||
.pullup(true)
|
.pullup(true)
|
||||||
);
|
);
|
||||||
// RXD3
|
// RXD3
|
||||||
slcr.mio_pin_26.write(
|
slcr.mio_pin_26.write(
|
||||||
slcr::MioPin26::zeroed()
|
slcr::MioPin26::zeroed()
|
||||||
|
.tri_enable(true)
|
||||||
.l0_sel(true)
|
.l0_sel(true)
|
||||||
.speed(true)
|
|
||||||
.io_type(slcr::IoBufferType::Hstl)
|
.io_type(slcr::IoBufferType::Hstl)
|
||||||
.pullup(true)
|
.pullup(true)
|
||||||
);
|
);
|
||||||
// RXD2
|
// RXD2
|
||||||
slcr.mio_pin_25.write(
|
slcr.mio_pin_25.write(
|
||||||
slcr::MioPin25::zeroed()
|
slcr::MioPin25::zeroed()
|
||||||
|
.tri_enable(true)
|
||||||
.l0_sel(true)
|
.l0_sel(true)
|
||||||
.speed(true)
|
|
||||||
.io_type(slcr::IoBufferType::Hstl)
|
.io_type(slcr::IoBufferType::Hstl)
|
||||||
.pullup(true)
|
.pullup(true)
|
||||||
);
|
);
|
||||||
// RXD1
|
// RXD1
|
||||||
slcr.mio_pin_24.write(
|
slcr.mio_pin_24.write(
|
||||||
slcr::MioPin24::zeroed()
|
slcr::MioPin24::zeroed()
|
||||||
|
.tri_enable(true)
|
||||||
.l0_sel(true)
|
.l0_sel(true)
|
||||||
.speed(true)
|
|
||||||
.io_type(slcr::IoBufferType::Hstl)
|
.io_type(slcr::IoBufferType::Hstl)
|
||||||
.pullup(true)
|
.pullup(true)
|
||||||
);
|
);
|
||||||
// RXD0
|
// RXD0
|
||||||
slcr.mio_pin_23.write(
|
slcr.mio_pin_23.write(
|
||||||
slcr::MioPin23::zeroed()
|
slcr::MioPin23::zeroed()
|
||||||
|
.tri_enable(true)
|
||||||
.l0_sel(true)
|
.l0_sel(true)
|
||||||
.speed(true)
|
|
||||||
.io_type(slcr::IoBufferType::Hstl)
|
.io_type(slcr::IoBufferType::Hstl)
|
||||||
.pullup(true)
|
.pullup(true)
|
||||||
);
|
);
|
||||||
|
@ -280,26 +182,22 @@ impl Eth<Gem0, (), ()> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn gem0(macaddr: [u8; 6]) -> Self {
|
pub fn gem0(macaddr: [u8; 6]) -> Self {
|
||||||
Self::gem_common(macaddr)
|
Self::setup_gem0_clock(TX_1000);
|
||||||
|
|
||||||
|
let regs = regs::RegisterBlock::gem0();
|
||||||
|
Self::from_regs(regs, macaddr)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
impl Eth<Gem1, (), ()> {
|
|
||||||
// TODO: Add a `eth1()`
|
|
||||||
|
|
||||||
pub fn gem1(macaddr: [u8; 6]) -> Self {
|
pub fn gem1(macaddr: [u8; 6]) -> Self {
|
||||||
Self::gem_common(macaddr)
|
Self::setup_gem1_clock(TX_1000);
|
||||||
|
|
||||||
|
let regs = regs::RegisterBlock::gem1();
|
||||||
|
Self::from_regs(regs, macaddr)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
impl<GEM: Gem> Eth<GEM, (), ()> {
|
|
||||||
fn gem_common(macaddr: [u8; 6]) -> Self {
|
|
||||||
GEM::setup_clock(TX_1000);
|
|
||||||
|
|
||||||
|
fn from_regs(regs: &'r mut regs::RegisterBlock, macaddr: [u8; 6]) -> Self {
|
||||||
let mut inner = EthInner {
|
let mut inner = EthInner {
|
||||||
gem: PhantomData,
|
regs,
|
||||||
link: None,
|
link: None,
|
||||||
};
|
};
|
||||||
inner.init();
|
inner.init();
|
||||||
|
@ -318,8 +216,54 @@ impl<GEM: Gem> Eth<GEM, (), ()> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<GEM: Gem, RX, TX> Eth<GEM, RX, TX> {
|
impl<'r, RX, TX> Eth<'r, RX, TX> {
|
||||||
pub fn start_rx(self, rx_size: usize) -> Eth<GEM, rx::DescList, TX> {
|
pub fn setup_gem0_clock(tx_clock: u32) {
|
||||||
|
let io_pll = Clocks::get().io;
|
||||||
|
let d0 = ((tx_clock - 1 + io_pll) / tx_clock).max(1).min(63);
|
||||||
|
let d1 = (io_pll / tx_clock / d0).max(1).min(63);
|
||||||
|
|
||||||
|
slcr::RegisterBlock::unlocked(|slcr| {
|
||||||
|
slcr.gem0_clk_ctrl.write(
|
||||||
|
// 0x0050_0801: 8, 5: 100 Mb/s
|
||||||
|
// ...: 8, 1: 1000 Mb/s
|
||||||
|
slcr::GemClkCtrl::zeroed()
|
||||||
|
.clkact(true)
|
||||||
|
.srcsel(slcr::PllSource::IoPll)
|
||||||
|
.divisor(d0 as u8)
|
||||||
|
.divisor1(d1 as u8)
|
||||||
|
);
|
||||||
|
// Enable gem0 recv clock
|
||||||
|
slcr.gem0_rclk_ctrl.write(
|
||||||
|
// 0x0000_0801
|
||||||
|
slcr::RclkCtrl::zeroed()
|
||||||
|
.clkact(true)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn setup_gem1_clock(tx_clock: u32) {
|
||||||
|
let io_pll = Clocks::get().io;
|
||||||
|
let d0 = ((tx_clock - 1 + io_pll) / tx_clock).max(1).min(63);
|
||||||
|
let d1 = (io_pll / tx_clock / d0).max(1).min(63);
|
||||||
|
|
||||||
|
slcr::RegisterBlock::unlocked(|slcr| {
|
||||||
|
slcr.gem1_clk_ctrl.write(
|
||||||
|
slcr::GemClkCtrl::zeroed()
|
||||||
|
.clkact(true)
|
||||||
|
.srcsel(slcr::PllSource::IoPll)
|
||||||
|
.divisor(d0 as u8)
|
||||||
|
.divisor1(d1 as u8)
|
||||||
|
);
|
||||||
|
// Enable gem1 recv clock
|
||||||
|
slcr.gem1_rclk_ctrl.write(
|
||||||
|
// 0x0000_0801
|
||||||
|
slcr::RclkCtrl::zeroed()
|
||||||
|
.clkact(true)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn start_rx(self, rx_size: usize) -> Eth<'r, rx::DescList, TX> {
|
||||||
let new_self = Eth {
|
let new_self = Eth {
|
||||||
rx: rx::DescList::new(rx_size),
|
rx: rx::DescList::new(rx_size),
|
||||||
tx: self.tx,
|
tx: self.tx,
|
||||||
|
@ -328,17 +272,17 @@ impl<GEM: Gem, RX, TX> Eth<GEM, RX, TX> {
|
||||||
};
|
};
|
||||||
let list_addr = new_self.rx.list_addr();
|
let list_addr = new_self.rx.list_addr();
|
||||||
assert!(list_addr & 0b11 == 0);
|
assert!(list_addr & 0b11 == 0);
|
||||||
GEM::regs().rx_qbar.write(
|
new_self.inner.regs.rx_qbar.write(
|
||||||
regs::RxQbar::zeroed()
|
regs::RxQbar::zeroed()
|
||||||
.rx_q_baseaddr(list_addr >> 2)
|
.rx_q_baseaddr(list_addr >> 2)
|
||||||
);
|
);
|
||||||
GEM::regs().net_ctrl.modify(|_, w|
|
new_self.inner.regs.net_ctrl.modify(|_, w|
|
||||||
w.rx_en(true)
|
w.rx_en(true)
|
||||||
);
|
);
|
||||||
new_self
|
new_self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn start_tx(self, tx_size: usize) -> Eth<GEM, RX, tx::DescList> {
|
pub fn start_tx(self, tx_size: usize) -> Eth<'r, RX, tx::DescList> {
|
||||||
let new_self = Eth {
|
let new_self = Eth {
|
||||||
rx: self.rx,
|
rx: self.rx,
|
||||||
tx: tx::DescList::new(tx_size),
|
tx: tx::DescList::new(tx_size),
|
||||||
|
@ -347,23 +291,23 @@ impl<GEM: Gem, RX, TX> Eth<GEM, RX, TX> {
|
||||||
};
|
};
|
||||||
let list_addr = &new_self.tx.list_addr();
|
let list_addr = &new_self.tx.list_addr();
|
||||||
assert!(list_addr & 0b11 == 0);
|
assert!(list_addr & 0b11 == 0);
|
||||||
GEM::regs().tx_qbar.write(
|
new_self.inner.regs.tx_qbar.write(
|
||||||
regs::TxQbar::zeroed()
|
regs::TxQbar::zeroed()
|
||||||
.tx_q_baseaddr(list_addr >> 2)
|
.tx_q_baseaddr(list_addr >> 2)
|
||||||
);
|
);
|
||||||
GEM::regs().net_ctrl.modify(|_, w|
|
new_self.inner.regs.net_ctrl.modify(|_, w|
|
||||||
w.tx_en(true)
|
w.tx_en(true)
|
||||||
);
|
);
|
||||||
new_self
|
new_self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<GEM: Gem, TX> Eth<GEM, rx::DescList, TX> {
|
impl<'r, TX> Eth<'r, rx::DescList, TX> {
|
||||||
pub fn recv_next<'s: 'p, 'p>(&'s mut self) -> Result<Option<rx::PktRef<'p>>, rx::Error> {
|
pub fn recv_next<'s: 'p, 'p>(&'s mut self) -> Result<Option<rx::PktRef<'p>>, rx::Error> {
|
||||||
let status = GEM::regs().rx_status.read();
|
let status = self.inner.regs.rx_status.read();
|
||||||
if status.hresp_not_ok() {
|
if status.hresp_not_ok() {
|
||||||
// Clear
|
// Clear
|
||||||
GEM::regs().rx_status.write(
|
self.inner.regs.rx_status.write(
|
||||||
regs::RxStatus::zeroed()
|
regs::RxStatus::zeroed()
|
||||||
.hresp_not_ok(true)
|
.hresp_not_ok(true)
|
||||||
);
|
);
|
||||||
|
@ -371,7 +315,7 @@ impl<GEM: Gem, TX> Eth<GEM, rx::DescList, TX> {
|
||||||
}
|
}
|
||||||
if status.rx_overrun() {
|
if status.rx_overrun() {
|
||||||
// Clear
|
// Clear
|
||||||
GEM::regs().rx_status.write(
|
self.inner.regs.rx_status.write(
|
||||||
regs::RxStatus::zeroed()
|
regs::RxStatus::zeroed()
|
||||||
.rx_overrun(true)
|
.rx_overrun(true)
|
||||||
);
|
);
|
||||||
|
@ -379,7 +323,7 @@ impl<GEM: Gem, TX> Eth<GEM, rx::DescList, TX> {
|
||||||
}
|
}
|
||||||
if status.buffer_not_avail() {
|
if status.buffer_not_avail() {
|
||||||
// Clear
|
// Clear
|
||||||
GEM::regs().rx_status.write(
|
self.inner.regs.rx_status.write(
|
||||||
regs::RxStatus::zeroed()
|
regs::RxStatus::zeroed()
|
||||||
.buffer_not_avail(true)
|
.buffer_not_avail(true)
|
||||||
);
|
);
|
||||||
|
@ -391,7 +335,7 @@ impl<GEM: Gem, TX> Eth<GEM, rx::DescList, TX> {
|
||||||
match result {
|
match result {
|
||||||
Ok(None) => {
|
Ok(None) => {
|
||||||
// No packet, clear status bit
|
// No packet, clear status bit
|
||||||
GEM::regs().rx_status.write(
|
self.inner.regs.rx_status.write(
|
||||||
regs::RxStatus::zeroed()
|
regs::RxStatus::zeroed()
|
||||||
.frame_recd(true)
|
.frame_recd(true)
|
||||||
);
|
);
|
||||||
|
@ -406,13 +350,13 @@ impl<GEM: Gem, TX> Eth<GEM, rx::DescList, TX> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<GEM: Gem, RX> Eth<GEM, RX, tx::DescList> {
|
impl<'r, RX> Eth<'r, RX, tx::DescList> {
|
||||||
pub fn send<'s: 'p, 'p>(&'s mut self, length: usize) -> Option<tx::PktRef<'p>> {
|
pub fn send<'s: 'p, 'p>(&'s mut self, length: usize) -> Option<tx::PktRef<'p>> {
|
||||||
self.tx.send(GEM::regs(), length)
|
self.tx.send(self.inner.regs, length)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, GEM: Gem> smoltcp::phy::Device<'a> for &mut Eth<GEM, rx::DescList, tx::DescList> {
|
impl<'r, 'a> smoltcp::phy::Device<'a> for &mut Eth<'r, rx::DescList, tx::DescList> {
|
||||||
type RxToken = rx::PktRef<'a>;
|
type RxToken = rx::PktRef<'a>;
|
||||||
type TxToken = tx::Token<'a>;
|
type TxToken = tx::Token<'a>;
|
||||||
|
|
||||||
|
@ -426,7 +370,6 @@ impl<'a, GEM: Gem> smoltcp::phy::Device<'a> for &mut Eth<GEM, rx::DescList, tx::
|
||||||
|
|
||||||
let mut caps = DeviceCapabilities::default();
|
let mut caps = DeviceCapabilities::default();
|
||||||
caps.max_transmission_unit = MTU;
|
caps.max_transmission_unit = MTU;
|
||||||
caps.max_burst_size = Some(self.rx.len().min(self.tx.len()));
|
|
||||||
caps.checksum = checksum_caps;
|
caps.checksum = checksum_caps;
|
||||||
|
|
||||||
caps
|
caps
|
||||||
|
@ -436,7 +379,7 @@ impl<'a, GEM: Gem> smoltcp::phy::Device<'a> for &mut Eth<GEM, rx::DescList, tx::
|
||||||
match self.rx.recv_next() {
|
match self.rx.recv_next() {
|
||||||
Ok(Some(pktref)) => {
|
Ok(Some(pktref)) => {
|
||||||
let tx_token = tx::Token {
|
let tx_token = tx::Token {
|
||||||
regs: GEM::regs(),
|
regs: self.inner.regs,
|
||||||
desc_list: &mut self.tx,
|
desc_list: &mut self.tx,
|
||||||
};
|
};
|
||||||
Some((pktref, tx_token))
|
Some((pktref, tx_token))
|
||||||
|
@ -454,32 +397,33 @@ impl<'a, GEM: Gem> smoltcp::phy::Device<'a> for &mut Eth<GEM, rx::DescList, tx::
|
||||||
|
|
||||||
fn transmit(&'a mut self) -> Option<Self::TxToken> {
|
fn transmit(&'a mut self) -> Option<Self::TxToken> {
|
||||||
Some(tx::Token {
|
Some(tx::Token {
|
||||||
regs: GEM::regs(),
|
regs: self.inner.regs,
|
||||||
desc_list: &mut self.tx,
|
desc_list: &mut self.tx,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
struct EthInner<GEM: Gem> {
|
struct EthInner<'r> {
|
||||||
gem: PhantomData<GEM>,
|
regs: &'r mut regs::RegisterBlock,
|
||||||
link: Option<phy::Link>,
|
link: Option<phy::Link>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<GEM: Gem> EthInner<GEM> {
|
impl<'r> EthInner<'r> {
|
||||||
fn init(&mut self) {
|
fn init(&mut self) {
|
||||||
// Clear the Network Control register.
|
// Clear the Network Control register.
|
||||||
GEM::regs().net_ctrl.write(regs::NetCtrl::zeroed());
|
self.regs.net_ctrl.write(regs::NetCtrl::zeroed());
|
||||||
GEM::regs().net_ctrl.write(regs::NetCtrl::zeroed().clear_stat_regs(true));
|
self.regs.net_ctrl.write(regs::NetCtrl::zeroed().clear_stat_regs(true));
|
||||||
// Clear the Status registers.
|
// Clear the Status registers.
|
||||||
GEM::regs().rx_status.write(
|
self.regs.rx_status.write(
|
||||||
regs::RxStatus::zeroed()
|
regs::RxStatus::zeroed()
|
||||||
.buffer_not_avail(true)
|
.buffer_not_avail(true)
|
||||||
.frame_recd(true)
|
.frame_recd(true)
|
||||||
.rx_overrun(true)
|
.rx_overrun(true)
|
||||||
.hresp_not_ok(true)
|
.hresp_not_ok(true)
|
||||||
);
|
);
|
||||||
GEM::regs().tx_status.write(
|
self.regs.tx_status.write(
|
||||||
regs::TxStatus::zeroed()
|
regs::TxStatus::zeroed()
|
||||||
.used_bit_read(true)
|
.used_bit_read(true)
|
||||||
.collision(true)
|
.collision(true)
|
||||||
|
@ -493,7 +437,7 @@ impl<GEM: Gem> EthInner<GEM> {
|
||||||
.hresp_not_ok(true)
|
.hresp_not_ok(true)
|
||||||
);
|
);
|
||||||
// Disable all interrupts.
|
// Disable all interrupts.
|
||||||
GEM::regs().intr_dis.write(
|
self.regs.intr_dis.write(
|
||||||
regs::IntrDis::zeroed()
|
regs::IntrDis::zeroed()
|
||||||
.mgmt_done(true)
|
.mgmt_done(true)
|
||||||
.rx_complete(true)
|
.rx_complete(true)
|
||||||
|
@ -523,32 +467,29 @@ impl<GEM: Gem> EthInner<GEM> {
|
||||||
.tsu_sec_incr(true)
|
.tsu_sec_incr(true)
|
||||||
);
|
);
|
||||||
// Clear the buffer queues.
|
// Clear the buffer queues.
|
||||||
GEM::regs().rx_qbar.write(
|
self.regs.rx_qbar.write(
|
||||||
regs::RxQbar::zeroed()
|
regs::RxQbar::zeroed()
|
||||||
);
|
);
|
||||||
GEM::regs().tx_qbar.write(
|
self.regs.tx_qbar.write(
|
||||||
regs::TxQbar::zeroed()
|
regs::TxQbar::zeroed()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn configure(&mut self, macaddr: [u8; 6]) {
|
fn configure(&mut self, macaddr: [u8; 6]) {
|
||||||
let clocks = Clocks::get();
|
let clocks = Clocks::get();
|
||||||
let mut mdc_clk_div = clocks.cpu_1x() / MAX_MDC;
|
let mdc_clk_div = (clocks.cpu_1x() / MAX_MDC) + 1;
|
||||||
if clocks.cpu_1x() % MAX_MDC > 0 {
|
|
||||||
mdc_clk_div += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
GEM::regs().net_cfg.write(
|
self.regs.net_cfg.write(
|
||||||
regs::NetCfg::zeroed()
|
regs::NetCfg::zeroed()
|
||||||
.full_duplex(true)
|
.full_duplex(true)
|
||||||
.gige_en(true)
|
.gige_en(true)
|
||||||
.speed(true)
|
.speed(true)
|
||||||
.no_broadcast(false)
|
.no_broadcast(false)
|
||||||
.multi_hash_en(true)
|
.multi_hash_en(true)
|
||||||
.rx_1536_byte_frames(true)
|
// Promiscuous mode (TODO?)
|
||||||
|
.copy_all(true)
|
||||||
// Remove 4-byte Frame CheckSum
|
// Remove 4-byte Frame CheckSum
|
||||||
.fcs_remove(true)
|
.fcs_remove(true)
|
||||||
.dis_cp_pause_frame(true)
|
|
||||||
// RX checksum offload
|
// RX checksum offload
|
||||||
.rx_chksum_offld_en(true)
|
.rx_chksum_offld_en(true)
|
||||||
// One of the slower speeds
|
// One of the slower speeds
|
||||||
|
@ -556,25 +497,24 @@ impl<GEM: Gem> EthInner<GEM> {
|
||||||
);
|
);
|
||||||
|
|
||||||
let macaddr_msbs =
|
let macaddr_msbs =
|
||||||
(u16::from(macaddr[5]) << 8) |
|
(u16::from(macaddr[0]) << 8) |
|
||||||
u16::from(macaddr[4]);
|
u16::from(macaddr[1]);
|
||||||
let macaddr_lsbs =
|
let macaddr_lsbs =
|
||||||
(u32::from(macaddr[3]) << 24) |
|
(u32::from(macaddr[2]) << 24) |
|
||||||
(u32::from(macaddr[2]) << 16) |
|
(u32::from(macaddr[3]) << 16) |
|
||||||
(u32::from(macaddr[1]) << 8) |
|
(u32::from(macaddr[4]) << 8) |
|
||||||
u32::from(macaddr[0]);
|
u32::from(macaddr[5]);
|
||||||
// writing to bot would disable the specific address
|
self.regs.spec_addr1_top.write(
|
||||||
GEM::regs().spec_addr1_bot.write(
|
|
||||||
regs::SpecAddrBot::zeroed()
|
|
||||||
.addr_lsbs(macaddr_lsbs)
|
|
||||||
);
|
|
||||||
// writing to top would enable it again
|
|
||||||
GEM::regs().spec_addr1_top.write(
|
|
||||||
regs::SpecAddrTop::zeroed()
|
regs::SpecAddrTop::zeroed()
|
||||||
.addr_msbs(macaddr_msbs)
|
.addr_msbs(macaddr_msbs)
|
||||||
);
|
);
|
||||||
|
self.regs.spec_addr1_bot.write(
|
||||||
|
regs::SpecAddrBot::zeroed()
|
||||||
|
.addr_lsbs(macaddr_lsbs)
|
||||||
|
);
|
||||||
|
|
||||||
GEM::regs().dma_cfg.write(
|
|
||||||
|
self.regs.dma_cfg.write(
|
||||||
regs::DmaCfg::zeroed()
|
regs::DmaCfg::zeroed()
|
||||||
// 1536 bytes
|
// 1536 bytes
|
||||||
.ahb_mem_rx_buf_size((MTU >> 6) as u8)
|
.ahb_mem_rx_buf_size((MTU >> 6) as u8)
|
||||||
|
@ -590,7 +530,7 @@ impl<GEM: Gem> EthInner<GEM> {
|
||||||
.ahb_fixed_burst_len(0x10)
|
.ahb_fixed_burst_len(0x10)
|
||||||
);
|
);
|
||||||
|
|
||||||
GEM::regs().net_ctrl.write(
|
self.regs.net_ctrl.write(
|
||||||
regs::NetCtrl::zeroed()
|
regs::NetCtrl::zeroed()
|
||||||
.mgmt_port_en(true)
|
.mgmt_port_en(true)
|
||||||
);
|
);
|
||||||
|
@ -598,7 +538,7 @@ impl<GEM: Gem> EthInner<GEM> {
|
||||||
|
|
||||||
|
|
||||||
fn wait_phy_idle(&self) {
|
fn wait_phy_idle(&self) {
|
||||||
while !GEM::regs().net_status.read().phy_mgmt_idle() {}
|
while !self.regs.net_status.read().phy_mgmt_idle() {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -617,15 +557,17 @@ impl<GEM: Gem> EthInner<GEM> {
|
||||||
Some(link) => {
|
Some(link) => {
|
||||||
info!("eth: got {:?}", link);
|
info!("eth: got {:?}", link);
|
||||||
|
|
||||||
use phy::{LinkDuplex::Full, LinkSpeed::*};
|
use phy::LinkSpeed::*;
|
||||||
let txclock = match link.speed {
|
let txclock = match link.speed {
|
||||||
S10 => TX_10,
|
S10 => TX_10,
|
||||||
S100 => TX_100,
|
S100 => TX_100,
|
||||||
S1000 => TX_1000,
|
S1000 => TX_1000,
|
||||||
};
|
};
|
||||||
GEM::setup_clock(txclock);
|
Eth::<(), ()>::setup_gem0_clock(txclock);
|
||||||
GEM::regs().net_cfg.modify(|_, w| w
|
/* .full_duplex(false) doesn't work even if
|
||||||
.full_duplex(link.duplex == Full)
|
half duplex has been negotiated. */
|
||||||
|
self.regs.net_cfg.modify(|_, w| w
|
||||||
|
.full_duplex(true)
|
||||||
.gige_en(link.speed == S1000)
|
.gige_en(link.speed == S1000)
|
||||||
.speed(link.speed != S10)
|
.speed(link.speed != S10)
|
||||||
);
|
);
|
||||||
|
@ -644,10 +586,10 @@ impl<GEM: Gem> EthInner<GEM> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<GEM: Gem> PhyAccess for EthInner<GEM> {
|
impl<'r> PhyAccess for EthInner<'r> {
|
||||||
fn read_phy(&mut self, addr: u8, reg: u8) -> u16 {
|
fn read_phy(&mut self, addr: u8, reg: u8) -> u16 {
|
||||||
self.wait_phy_idle();
|
self.wait_phy_idle();
|
||||||
GEM::regs().phy_maint.write(
|
self.regs.phy_maint.write(
|
||||||
regs::PhyMaint::zeroed()
|
regs::PhyMaint::zeroed()
|
||||||
.clause_22(true)
|
.clause_22(true)
|
||||||
.operation(regs::PhyOperation::Read)
|
.operation(regs::PhyOperation::Read)
|
||||||
|
@ -656,12 +598,12 @@ impl<GEM: Gem> PhyAccess for EthInner<GEM> {
|
||||||
.must_10(0b10)
|
.must_10(0b10)
|
||||||
);
|
);
|
||||||
self.wait_phy_idle();
|
self.wait_phy_idle();
|
||||||
GEM::regs().phy_maint.read().data()
|
self.regs.phy_maint.read().data()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_phy(&mut self, addr: u8, reg: u8, data: u16) {
|
fn write_phy(&mut self, addr: u8, reg: u8, data: u16) {
|
||||||
self.wait_phy_idle();
|
self.wait_phy_idle();
|
||||||
GEM::regs().phy_maint.write(
|
self.regs.phy_maint.write(
|
||||||
regs::PhyMaint::zeroed()
|
regs::PhyMaint::zeroed()
|
||||||
.clause_22(true)
|
.clause_22(true)
|
||||||
.operation(regs::PhyOperation::Write)
|
.operation(regs::PhyOperation::Write)
|
||||||
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
use bit_field::BitField;
|
||||||
|
use super::{PhyRegister, Link, LinkDuplex, LinkSpeed};
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
/// 1000Base-T Extended Status Register
|
||||||
|
pub struct ExtendedStatus(pub u16);
|
||||||
|
|
||||||
|
impl ExtendedStatus {
|
||||||
|
pub fn cap_1000base_t_half(&self) -> bool {
|
||||||
|
self.0.get_bit(12)
|
||||||
|
}
|
||||||
|
pub fn cap_1000base_t_full(&self) -> bool {
|
||||||
|
self.0.get_bit(13)
|
||||||
|
}
|
||||||
|
pub fn cap_1000base_x_half(&self) -> bool {
|
||||||
|
self.0.get_bit(14)
|
||||||
|
}
|
||||||
|
pub fn cap_1000base_x_full(&self) -> bool {
|
||||||
|
self.0.get_bit(12)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_link(&self) -> Option<Link> {
|
||||||
|
if self.cap_1000base_t_half() {
|
||||||
|
Some(Link {
|
||||||
|
speed: LinkSpeed::S1000,
|
||||||
|
duplex: LinkDuplex::Half,
|
||||||
|
})
|
||||||
|
} else if self.cap_1000base_t_full() {
|
||||||
|
Some(Link {
|
||||||
|
speed: LinkSpeed::S1000,
|
||||||
|
duplex: LinkDuplex::Full,
|
||||||
|
})
|
||||||
|
} else if self.cap_1000base_x_half() {
|
||||||
|
Some(Link {
|
||||||
|
speed: LinkSpeed::S1000,
|
||||||
|
duplex: LinkDuplex::Half,
|
||||||
|
})
|
||||||
|
} else if self.cap_1000base_x_full() {
|
||||||
|
Some(Link {
|
||||||
|
speed: LinkSpeed::S1000,
|
||||||
|
duplex: LinkDuplex::Full,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PhyRegister for ExtendedStatus {
|
||||||
|
fn addr() -> u8 {
|
||||||
|
0xF
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<u16> for ExtendedStatus {
|
||||||
|
fn from(value: u16) -> Self {
|
||||||
|
ExtendedStatus(value)
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,10 +2,10 @@ pub mod id;
|
||||||
use id::{identify_phy, PhyIdentifier};
|
use id::{identify_phy, PhyIdentifier};
|
||||||
mod status;
|
mod status;
|
||||||
pub use status::Status;
|
pub use status::Status;
|
||||||
|
mod extended_status;
|
||||||
|
pub use extended_status::ExtendedStatus;
|
||||||
mod control;
|
mod control;
|
||||||
pub use control::Control;
|
pub use control::Control;
|
||||||
mod pssr;
|
|
||||||
pub use pssr::PSSR;
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub struct Link {
|
pub struct Link {
|
||||||
|
@ -39,36 +39,43 @@ pub struct Phy {
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub enum PhyDevice {
|
pub enum PhyDevice {
|
||||||
Marvell88E1116R,
|
Marvel88E1116R,
|
||||||
Rtl8211E,
|
Rtl8211E,
|
||||||
}
|
}
|
||||||
|
|
||||||
const OUI_MARVELL: u32 = 0x005043;
|
const OUI_MARVEL: u32 = 0x005043;
|
||||||
const OUI_REALTEK: u32 = 0x000732;
|
const OUI_REALTEK: u32 = 0x000732;
|
||||||
|
|
||||||
impl Phy {
|
impl Phy {
|
||||||
/// Probe all addresses on MDIO for a known PHY
|
/// Probe all addresses on MDIO for a known PHY
|
||||||
pub fn find<PA: PhyAccess>(pa: &mut PA) -> Option<Phy> {
|
pub fn find<PA: PhyAccess>(pa: &mut PA) -> Option<Phy> {
|
||||||
(1..32).filter_map(|addr| {
|
for addr in 1..32 {
|
||||||
match identify_phy(pa, addr) {
|
let device = match identify_phy(pa, addr) {
|
||||||
Some(PhyIdentifier {
|
Some(PhyIdentifier {
|
||||||
oui: OUI_MARVELL,
|
oui: OUI_MARVEL,
|
||||||
model: 36,
|
model: 36,
|
||||||
..
|
..
|
||||||
}) => Some(PhyDevice::Marvell88E1116R),
|
}) => Some(PhyDevice::Marvel88E1116R),
|
||||||
Some(PhyIdentifier {
|
Some(PhyIdentifier {
|
||||||
oui: OUI_REALTEK,
|
oui: OUI_REALTEK,
|
||||||
model: 0b010001,
|
model: 0b010001,
|
||||||
rev: 0b0101,
|
rev: 0b0101,
|
||||||
}) => Some(PhyDevice::Rtl8211E),
|
}) => Some(PhyDevice::Rtl8211E),
|
||||||
_ => None,
|
_ => None,
|
||||||
}.map(|device| Phy { addr, device })
|
};
|
||||||
}).next()
|
match device {
|
||||||
|
Some(device) =>
|
||||||
|
return Some(Phy { addr, device }),
|
||||||
|
None => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn name(&self) -> &'static str {
|
pub fn name(&self) -> &'static str {
|
||||||
match self.device {
|
match self.device {
|
||||||
PhyDevice::Marvell88E1116R => &"Marvell 88E1116R",
|
PhyDevice::Marvel88E1116R => &"Marvel 88E1116R",
|
||||||
PhyDevice::Rtl8211E => &"RTL8211E",
|
PhyDevice::Rtl8211E => &"RTL8211E",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -113,8 +120,12 @@ impl Phy {
|
||||||
if !status.link_status() {
|
if !status.link_status() {
|
||||||
None
|
None
|
||||||
} else if status.cap_1000base_t_extended_status() {
|
} else if status.cap_1000base_t_extended_status() {
|
||||||
let phy_status: PSSR = self.read_reg(pa);
|
let ext_status: ExtendedStatus = self.read_reg(pa);
|
||||||
phy_status.get_link()
|
if let Some(link) = ext_status.get_link() {
|
||||||
|
Some(link)
|
||||||
|
} else {
|
||||||
|
status.get_link()
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
status.get_link()
|
status.get_link()
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,52 +0,0 @@
|
||||||
use bit_field::BitField;
|
|
||||||
use super::{PhyRegister, Link, LinkDuplex, LinkSpeed};
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
|
||||||
/// PHY-Specific Status Register
|
|
||||||
pub struct PSSR(pub u16);
|
|
||||||
|
|
||||||
impl PSSR {
|
|
||||||
pub fn link(&self) -> bool {
|
|
||||||
self.0.get_bit(10)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn duplex(&self) -> LinkDuplex {
|
|
||||||
if self.0.get_bit(13) {
|
|
||||||
LinkDuplex::Full
|
|
||||||
} else {
|
|
||||||
LinkDuplex::Half
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn speed(&self) -> Option<LinkSpeed> {
|
|
||||||
match self.0.get_bits(14..=15) {
|
|
||||||
0b00 => Some(LinkSpeed::S10),
|
|
||||||
0b01 => Some(LinkSpeed::S100),
|
|
||||||
0b10 => Some(LinkSpeed::S1000),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_link(&self) -> Option<Link> {
|
|
||||||
if self.link() {
|
|
||||||
Some(Link {
|
|
||||||
speed: self.speed()?,
|
|
||||||
duplex: self.duplex(),
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PhyRegister for PSSR {
|
|
||||||
fn addr() -> u8 {
|
|
||||||
0x11
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<u16> for PSSR {
|
|
||||||
fn from(value: u16) -> Self {
|
|
||||||
PSSR(value)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,6 +1,6 @@
|
||||||
use volatile_register::{RO, WO, RW};
|
use volatile_register::{RO, WO, RW};
|
||||||
|
|
||||||
use libregister::{register, register_at, register_bit, register_bits, register_bits_typed};
|
use libregister::{register, register_bit, register_bits, register_bits_typed};
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct RegisterBlock {
|
pub struct RegisterBlock {
|
||||||
|
@ -110,8 +110,18 @@ pub struct RegisterBlock {
|
||||||
pub design_cfg5: RO<u32>,
|
pub design_cfg5: RO<u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
register_at!(RegisterBlock, 0xE000B000, gem0);
|
impl RegisterBlock {
|
||||||
register_at!(RegisterBlock, 0xE000C000, gem1);
|
const GEM0: *mut Self = 0xE000B000 as *mut _;
|
||||||
|
const GEM1: *mut Self = 0xE000C000 as *mut _;
|
||||||
|
|
||||||
|
pub fn gem0() -> &'static mut Self {
|
||||||
|
unsafe { &mut *Self::GEM0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn gem1() -> &'static mut Self {
|
||||||
|
unsafe { &mut *Self::GEM1 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
register!(net_ctrl, NetCtrl, RW, u32);
|
register!(net_ctrl, NetCtrl, RW, u32);
|
||||||
register_bit!(net_ctrl, loopback_local, 1);
|
register_bit!(net_ctrl, loopback_local, 1);
|
||||||
|
|
|
@ -2,6 +2,8 @@ use core::ops::Deref;
|
||||||
use alloc::{vec, vec::Vec};
|
use alloc::{vec, vec::Vec};
|
||||||
use libcortex_a9::{asm::*, cache::*, UncachedSlice};
|
use libcortex_a9::{asm::*, cache::*, UncachedSlice};
|
||||||
use libregister::*;
|
use libregister::*;
|
||||||
|
use log::debug;
|
||||||
|
use crate::l2cache;
|
||||||
use super::Buffer;
|
use super::Buffer;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -81,9 +83,6 @@ impl DescList {
|
||||||
entry.word1.write(
|
entry.word1.write(
|
||||||
DescWord1::zeroed()
|
DescWord1::zeroed()
|
||||||
);
|
);
|
||||||
// Flush buffer from cache, to be filled by the peripheral
|
|
||||||
// before next read
|
|
||||||
dcci_slice(&buffer[..]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DescList {
|
DescList {
|
||||||
|
@ -93,10 +92,6 @@ impl DescList {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn len(&self) -> usize {
|
|
||||||
self.list.len().min(self.buffers.len())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn list_addr(&self) -> u32 {
|
pub fn list_addr(&self) -> u32 {
|
||||||
&self.list[0] as *const _ as u32
|
&self.list[0] as *const _ as u32
|
||||||
}
|
}
|
||||||
|
@ -108,21 +103,10 @@ impl DescList {
|
||||||
if entry.word0.read().used() {
|
if entry.word0.read().used() {
|
||||||
let word1 = entry.word1.read();
|
let word1 = entry.word1.read();
|
||||||
let len = word1.frame_length_lsbs().into();
|
let len = word1.frame_length_lsbs().into();
|
||||||
let padding = {
|
|
||||||
let diff = len % 0x20;
|
|
||||||
if diff == 0 {
|
|
||||||
0
|
|
||||||
} else {
|
|
||||||
0x20 - diff
|
|
||||||
}
|
|
||||||
};
|
|
||||||
unsafe {
|
|
||||||
// invalidate the buffer
|
|
||||||
// we cannot do it in the drop function, as L2 cache data prefetch would prefetch
|
|
||||||
// the data, and there is no way for us to prevent that unless changing MMU table.
|
|
||||||
dci_slice(&mut self.buffers[self.next][0..len + padding]);
|
|
||||||
}
|
|
||||||
let buffer = &mut self.buffers[self.next][0..len];
|
let buffer = &mut self.buffers[self.next][0..len];
|
||||||
|
// Invalidate caches for packet buffer
|
||||||
|
l2cache().invalidate_slice(&mut buffer[..]);
|
||||||
|
dcci_slice(&buffer[..]);
|
||||||
|
|
||||||
self.next += 1;
|
self.next += 1;
|
||||||
if self.next >= list_len {
|
if self.next >= list_len {
|
||||||
|
@ -131,8 +115,10 @@ impl DescList {
|
||||||
|
|
||||||
let pkt = PktRef { entry, buffer };
|
let pkt = PktRef { entry, buffer };
|
||||||
if word1.start_of_frame() && word1.end_of_frame() {
|
if word1.start_of_frame() && word1.end_of_frame() {
|
||||||
|
// debug!("pkt {}: {:08X}..{:08X}", len, &pkt.buffer[0] as *const _ as usize, &pkt.buffer[pkt.len()-1] as *const _ as usize);
|
||||||
Ok(Some(pkt))
|
Ok(Some(pkt))
|
||||||
} else {
|
} else {
|
||||||
|
debug!("pkt trunc");
|
||||||
Err(Error::Truncated)
|
Err(Error::Truncated)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -149,6 +135,7 @@ pub struct PktRef<'a> {
|
||||||
|
|
||||||
impl<'a> Drop for PktRef<'a> {
|
impl<'a> Drop for PktRef<'a> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
|
|
||||||
self.entry.word0.modify(|_, w| w.used(false));
|
self.entry.word0.modify(|_, w| w.used(false));
|
||||||
dmb();
|
dmb();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
use core::ops::{Deref, DerefMut};
|
use core::ops::{Deref, DerefMut};
|
||||||
use alloc::{vec, vec::Vec};
|
use alloc::{vec, vec::Vec};
|
||||||
use libcortex_a9::{cache::dcc_slice, UncachedSlice};
|
use libcortex_a9::{asm::dmb, cache::dcc_slice, UncachedSlice};
|
||||||
use libregister::*;
|
use libregister::*;
|
||||||
|
use log::{debug, warn};
|
||||||
|
use crate::l2cache;
|
||||||
use super::{Buffer, regs};
|
use super::{Buffer, regs};
|
||||||
|
|
||||||
/// Descriptor entry
|
/// Descriptor entry
|
||||||
|
@ -85,17 +87,15 @@ impl DescList {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn len(&self) -> usize {
|
|
||||||
self.list.len().min(self.buffers.len())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn list_addr(&self) -> u32 {
|
pub fn list_addr(&self) -> u32 {
|
||||||
&self.list[0] as *const _ as u32
|
&self.list[0] as *const _ as u32
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send<'s: 'p, 'p>(&'s mut self, regs: &'s mut regs::RegisterBlock, length: usize) -> Option<PktRef<'p>> {
|
pub fn send<'s: 'p, 'p>(&'s mut self, regs: &'s mut regs::RegisterBlock, length: usize) -> Option<PktRef<'p>> {
|
||||||
|
// debug!("send {}", length);
|
||||||
let list_len = self.list.len();
|
let list_len = self.list.len();
|
||||||
let entry = &mut self.list[self.next];
|
let entry = &mut self.list[self.next];
|
||||||
|
dmb();
|
||||||
if entry.word1.read().used() {
|
if entry.word1.read().used() {
|
||||||
let buffer = &mut self.buffers[self.next][0..length];
|
let buffer = &mut self.buffers[self.next][0..length];
|
||||||
entry.word1.write(DescWord1::zeroed()
|
entry.word1.write(DescWord1::zeroed()
|
||||||
|
@ -113,6 +113,7 @@ impl DescList {
|
||||||
Some(PktRef { entry, buffer, regs })
|
Some(PktRef { entry, buffer, regs })
|
||||||
} else {
|
} else {
|
||||||
// Still in use by HW (sending too fast, ring exceeded)
|
// Still in use by HW (sending too fast, ring exceeded)
|
||||||
|
warn!("tx ring overflow");
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -128,12 +129,17 @@ pub struct PktRef<'a> {
|
||||||
|
|
||||||
impl<'a> Drop for PktRef<'a> {
|
impl<'a> Drop for PktRef<'a> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
// Write back all dirty cachelines of this buffer
|
// Write back all dirty cachelines of packet buffer
|
||||||
dcc_slice(self.buffer);
|
dcc_slice(self.buffer);
|
||||||
|
l2cache().clean_slice(self.buffer);
|
||||||
|
|
||||||
self.entry.word1.modify(|_, w| w.used(false));
|
self.entry.word1.modify(|_, w| w.used(false));
|
||||||
// Start the TX engine
|
dmb();
|
||||||
self.regs.net_ctrl.modify(|_, w| w.start_tx(true));
|
// dsb();
|
||||||
|
if ! self.regs.tx_status.read().tx_go() {
|
||||||
|
// Start TX if not already running
|
||||||
|
self.regs.net_ctrl.modify(|_, w| w.start_tx(true));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -164,7 +170,10 @@ impl<'a> smoltcp::phy::TxToken for Token<'a> {
|
||||||
None =>
|
None =>
|
||||||
Err(smoltcp::Error::Exhausted),
|
Err(smoltcp::Error::Exhausted),
|
||||||
Some(mut pktref) => {
|
Some(mut pktref) => {
|
||||||
f(pktref.deref_mut())
|
let result = f(pktref.deref_mut());
|
||||||
|
// TODO: on result.is_err() don;t send
|
||||||
|
drop(pktref);
|
||||||
|
result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
pub trait BytesTransferExt: Sized {
|
||||||
|
// Turn u32 into u8
|
||||||
|
fn bytes_transfer(self) -> BytesTransfer<Self>
|
||||||
|
where
|
||||||
|
Self: Iterator<Item = u32>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: Iterator<Item = u32>> BytesTransferExt for I {
|
||||||
|
// Turn u32 into u8
|
||||||
|
fn bytes_transfer(self) -> BytesTransfer<Self> {
|
||||||
|
BytesTransfer {
|
||||||
|
iter: self,
|
||||||
|
shift: 0,
|
||||||
|
word: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct BytesTransfer<I: Iterator<Item = u32> + Sized> {
|
||||||
|
iter: I,
|
||||||
|
shift: u8,
|
||||||
|
word: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: Iterator<Item = u32> + Sized> Iterator for BytesTransfer<I> {
|
||||||
|
type Item = u8;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<u8> {
|
||||||
|
if self.shift > 0 {
|
||||||
|
self.shift -= 8;
|
||||||
|
Some((self.word >> self.shift) as u8)
|
||||||
|
} else {
|
||||||
|
self.iter.next()
|
||||||
|
.and_then(|word| {
|
||||||
|
self.shift = 32;
|
||||||
|
self.word = word;
|
||||||
|
self.next()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,503 @@
|
||||||
|
//! Quad-SPI Flash Controller
|
||||||
|
|
||||||
|
use core::marker::PhantomData;
|
||||||
|
use log::{error, info, warn};
|
||||||
|
use libregister::{RegisterR, RegisterW, RegisterRW};
|
||||||
|
use crate::{print, println};
|
||||||
|
use super::slcr;
|
||||||
|
use super::clocks::source::{IoPll, ClockSource};
|
||||||
|
|
||||||
|
mod regs;
|
||||||
|
mod bytes;
|
||||||
|
pub use bytes::{BytesTransferExt, BytesTransfer};
|
||||||
|
mod spi_flash_register;
|
||||||
|
use spi_flash_register::*;
|
||||||
|
mod transfer;
|
||||||
|
use transfer::Transfer;
|
||||||
|
|
||||||
|
const FLASH_BAUD_RATE: u32 = 50_000_000;
|
||||||
|
/// 16 MB
|
||||||
|
pub const SINGLE_CAPACITY: u32 = 0x1000000;
|
||||||
|
pub const SECTOR_SIZE: u32 = 0x10000;
|
||||||
|
pub const PAGE_SIZE: u32 = 0x100;
|
||||||
|
|
||||||
|
/// Instruction: Read Identification
|
||||||
|
const INST_RDID: u8 = 0x9F;
|
||||||
|
/// Instruction: Read
|
||||||
|
const INST_READ: u8 = 0x03;
|
||||||
|
/// Instruction: Quad I/O Fast Read
|
||||||
|
const INST_4IO_FAST_READ: u8 = 0xEB;
|
||||||
|
/// Instruction: Write Disable
|
||||||
|
const INST_WRDI: u8 = 0x04;
|
||||||
|
/// Instruction: Write Enable
|
||||||
|
const INST_WREN: u8 = 0x06;
|
||||||
|
/// Instruction: Program page
|
||||||
|
const INST_PP: u8 = 0x02;
|
||||||
|
/// Instruction: Erase 4K Block
|
||||||
|
const INST_BE_4K: u8 = 0x20;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub enum SpiWord {
|
||||||
|
W8(u8),
|
||||||
|
W16(u16),
|
||||||
|
W24(u32),
|
||||||
|
W32(u32),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<u8> for SpiWord {
|
||||||
|
fn from(x: u8) -> Self {
|
||||||
|
SpiWord::W8(x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<u16> for SpiWord {
|
||||||
|
fn from(x: u16) -> Self {
|
||||||
|
SpiWord::W16(x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<u32> for SpiWord {
|
||||||
|
fn from(x: u32) -> Self {
|
||||||
|
SpiWord::W32(x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Memory-mapped mode
|
||||||
|
pub struct LinearAddressing;
|
||||||
|
/// Manual I/O mode
|
||||||
|
pub struct Manual;
|
||||||
|
|
||||||
|
/// Flash Interface Driver
|
||||||
|
///
|
||||||
|
/// For 2x Spansion S25FL128SAGMFIR01
|
||||||
|
pub struct Flash<MODE> {
|
||||||
|
regs: &'static mut regs::RegisterBlock,
|
||||||
|
_mode: PhantomData<MODE>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<MODE> Flash<MODE> {
|
||||||
|
fn transition<TO>(self) -> Flash<TO> {
|
||||||
|
Flash {
|
||||||
|
regs: self.regs,
|
||||||
|
_mode: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn disable_interrupts(&mut self) {
|
||||||
|
self.regs.intr_dis.write(
|
||||||
|
regs::IntrDis::zeroed()
|
||||||
|
.rx_overflow(true)
|
||||||
|
.tx_fifo_not_full(true)
|
||||||
|
.tx_fifo_full(true)
|
||||||
|
.rx_fifo_not_empty(true)
|
||||||
|
.rx_fifo_full(true)
|
||||||
|
.tx_fifo_underflow(true)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clear_rx_fifo(&self) {
|
||||||
|
while self.regs.intr_status.read().rx_fifo_not_empty() {
|
||||||
|
let _ = self.regs.rx_data.read();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clear_interrupt_status(&mut self) {
|
||||||
|
self.regs.intr_status.write(
|
||||||
|
regs::IntrStatus::zeroed()
|
||||||
|
.rx_overflow(true)
|
||||||
|
.tx_fifo_underflow(true)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn wait_tx_fifo_flush(&mut self) {
|
||||||
|
self.regs.config.modify(|_, w| w.man_start_com(true));
|
||||||
|
while !self.regs.intr_status.read().tx_fifo_not_full() {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Flash<()> {
|
||||||
|
pub fn new(clock: u32) -> Self {
|
||||||
|
Self::enable_clocks(clock);
|
||||||
|
Self::setup_signals();
|
||||||
|
Self::reset();
|
||||||
|
|
||||||
|
let regs = regs::RegisterBlock::qspi();
|
||||||
|
let mut flash = Flash { regs, _mode: PhantomData };
|
||||||
|
flash.configure((FLASH_BAUD_RATE - 1 + clock) / FLASH_BAUD_RATE);
|
||||||
|
flash
|
||||||
|
}
|
||||||
|
|
||||||
|
/// typical: `200_000_000` Hz
|
||||||
|
fn enable_clocks(clock: u32) {
|
||||||
|
let io_pll = IoPll::freq();
|
||||||
|
let divisor = ((clock - 1 + io_pll) / clock)
|
||||||
|
.max(1).min(63) as u8;
|
||||||
|
|
||||||
|
slcr::RegisterBlock::unlocked(|slcr| {
|
||||||
|
slcr.lqspi_clk_ctrl.write(
|
||||||
|
slcr::LqspiClkCtrl::zeroed()
|
||||||
|
.src_sel(slcr::PllSource::IoPll)
|
||||||
|
.divisor(divisor)
|
||||||
|
.clkact(true)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setup_signals() {
|
||||||
|
slcr::RegisterBlock::unlocked(|slcr| {
|
||||||
|
// 1. Configure MIO pin 1 for chip select 0 output.
|
||||||
|
slcr.mio_pin_01.write(
|
||||||
|
slcr::MioPin01::zeroed()
|
||||||
|
.l0_sel(true)
|
||||||
|
.io_type(slcr::IoBufferType::Lvcmos18)
|
||||||
|
.pullup(true)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Configure MIO pins 2 through 5 for I/O.
|
||||||
|
slcr.mio_pin_02.write(
|
||||||
|
slcr::MioPin02::zeroed()
|
||||||
|
.l0_sel(true)
|
||||||
|
.io_type(slcr::IoBufferType::Lvcmos18)
|
||||||
|
);
|
||||||
|
slcr.mio_pin_03.write(
|
||||||
|
slcr::MioPin03::zeroed()
|
||||||
|
.l0_sel(true)
|
||||||
|
.io_type(slcr::IoBufferType::Lvcmos18)
|
||||||
|
);
|
||||||
|
slcr.mio_pin_04.write(
|
||||||
|
slcr::MioPin04::zeroed()
|
||||||
|
.l0_sel(true)
|
||||||
|
.io_type(slcr::IoBufferType::Lvcmos18)
|
||||||
|
);
|
||||||
|
slcr.mio_pin_05.write(
|
||||||
|
slcr::MioPin05::zeroed()
|
||||||
|
.l0_sel(true)
|
||||||
|
.io_type(slcr::IoBufferType::Lvcmos18)
|
||||||
|
);
|
||||||
|
|
||||||
|
// 3. Configure MIO pin 6 for serial clock 0 output.
|
||||||
|
slcr.mio_pin_06.write(
|
||||||
|
slcr::MioPin06::zeroed()
|
||||||
|
.l0_sel(true)
|
||||||
|
.io_type(slcr::IoBufferType::Lvcmos18)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Option: Add Second Device Chip Select
|
||||||
|
// 4. Configure MIO pin 0 for chip select 1 output.
|
||||||
|
slcr.mio_pin_00.write(
|
||||||
|
slcr::MioPin00::zeroed()
|
||||||
|
.l0_sel(true)
|
||||||
|
.io_type(slcr::IoBufferType::Lvcmos18)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Option: Add Second Serial Clock
|
||||||
|
// 5. Configure MIO pin 9 for serial clock 1 output.
|
||||||
|
slcr.mio_pin_09.write(
|
||||||
|
slcr::MioPin09::zeroed()
|
||||||
|
.l0_sel(true)
|
||||||
|
.io_type(slcr::IoBufferType::Lvcmos18)
|
||||||
|
.pullup(true)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Option: Add 4-bit Data
|
||||||
|
// 6. Configure MIO pins 10 through 13 for I/O.
|
||||||
|
slcr.mio_pin_10.write(
|
||||||
|
slcr::MioPin10::zeroed()
|
||||||
|
.l0_sel(true)
|
||||||
|
.io_type(slcr::IoBufferType::Lvcmos18)
|
||||||
|
.pullup(true)
|
||||||
|
);
|
||||||
|
slcr.mio_pin_11.write(
|
||||||
|
slcr::MioPin11::zeroed()
|
||||||
|
.l0_sel(true)
|
||||||
|
.io_type(slcr::IoBufferType::Lvcmos18)
|
||||||
|
.pullup(true)
|
||||||
|
);
|
||||||
|
slcr.mio_pin_12.write(
|
||||||
|
slcr::MioPin12::zeroed()
|
||||||
|
.l0_sel(true)
|
||||||
|
.io_type(slcr::IoBufferType::Lvcmos18)
|
||||||
|
.pullup(true)
|
||||||
|
);
|
||||||
|
slcr.mio_pin_13.write(
|
||||||
|
slcr::MioPin13::zeroed()
|
||||||
|
.l0_sel(true)
|
||||||
|
.io_type(slcr::IoBufferType::Lvcmos18)
|
||||||
|
.pullup(true)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Option: Add Feedback Output Clock
|
||||||
|
// 7. Configure MIO pin 8 for feedback clock.
|
||||||
|
slcr.mio_pin_08.write(
|
||||||
|
slcr::MioPin08::zeroed()
|
||||||
|
.l0_sel(true)
|
||||||
|
.io_type(slcr::IoBufferType::Lvcmos18)
|
||||||
|
.pullup(true)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reset() {
|
||||||
|
slcr::RegisterBlock::unlocked(|slcr| {
|
||||||
|
slcr.lqspi_rst_ctrl.write(
|
||||||
|
slcr::LqspiRstCtrl::zeroed()
|
||||||
|
.ref_rst(true)
|
||||||
|
.cpu1x_rst(true)
|
||||||
|
);
|
||||||
|
slcr.lqspi_rst_ctrl.write(
|
||||||
|
slcr::LqspiRstCtrl::zeroed()
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn configure(&mut self, divider: u32) {
|
||||||
|
// Disable
|
||||||
|
self.regs.enable.write(
|
||||||
|
regs::Enable::zeroed()
|
||||||
|
);
|
||||||
|
self.disable_interrupts();
|
||||||
|
self.regs.lqspi_cfg.write(
|
||||||
|
regs::LqspiCfg::zeroed()
|
||||||
|
);
|
||||||
|
self.clear_rx_fifo();
|
||||||
|
self.clear_interrupt_status();
|
||||||
|
|
||||||
|
// for a baud_rate_div=1 LPBK_DLY_ADJ would be required
|
||||||
|
let mut baud_rate_div = 2u32;
|
||||||
|
while baud_rate_div < 7 && 2u32.pow(1 + baud_rate_div) < divider {
|
||||||
|
baud_rate_div += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.regs.config.write(regs::Config::zeroed()
|
||||||
|
.baud_rate_div(baud_rate_div as u8)
|
||||||
|
.mode_sel(true)
|
||||||
|
.leg_flsh(true)
|
||||||
|
.holdb_dr(true)
|
||||||
|
// 32 bits TX FIFO width
|
||||||
|
.fifo_width(0b11)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Initialize RX/TX pipes thresholds
|
||||||
|
unsafe {
|
||||||
|
self.regs.rx_thres.write(1);
|
||||||
|
self.regs.tx_thres.write(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn linear_addressing_mode(self) -> Flash<LinearAddressing> {
|
||||||
|
// Set manual start enable to auto mode.
|
||||||
|
// Assert the chip select.
|
||||||
|
self.regs.config.modify(|_, w| w
|
||||||
|
.man_start_en(false)
|
||||||
|
.pcs(false)
|
||||||
|
.manual_cs(false)
|
||||||
|
);
|
||||||
|
|
||||||
|
self.regs.lqspi_cfg.write(regs::LqspiCfg::zeroed()
|
||||||
|
// Quad I/O Fast Read
|
||||||
|
.inst_code(INST_4IO_FAST_READ)
|
||||||
|
.dummy_mask(0x2)
|
||||||
|
.mode_en(false)
|
||||||
|
.mode_bits(0xFF)
|
||||||
|
// 2 devices
|
||||||
|
.two_mem(true)
|
||||||
|
.u_page(false)
|
||||||
|
// Quad SPI mode
|
||||||
|
.lq_mode(true)
|
||||||
|
);
|
||||||
|
|
||||||
|
self.regs.enable.write(
|
||||||
|
regs::Enable::zeroed()
|
||||||
|
.spi_en(true)
|
||||||
|
);
|
||||||
|
|
||||||
|
self.transition()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn manual_mode(self, chip_index: usize) -> Flash<Manual> {
|
||||||
|
self.regs.config.modify(|_, w| w
|
||||||
|
.man_start_en(true)
|
||||||
|
.manual_cs(true)
|
||||||
|
.endian(true)
|
||||||
|
);
|
||||||
|
|
||||||
|
self.regs.lqspi_cfg.write(regs::LqspiCfg::zeroed()
|
||||||
|
// Quad I/O Fast Read
|
||||||
|
.inst_code(INST_READ)
|
||||||
|
.dummy_mask(0x2)
|
||||||
|
.mode_en(false)
|
||||||
|
.mode_bits(0xFF)
|
||||||
|
// 2 devices
|
||||||
|
.two_mem(true)
|
||||||
|
.u_page(chip_index != 0)
|
||||||
|
// Quad SPI mode
|
||||||
|
.lq_mode(false)
|
||||||
|
);
|
||||||
|
|
||||||
|
self.transition()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Flash<LinearAddressing> {
|
||||||
|
/// Stop linear addressing mode
|
||||||
|
pub fn stop(self) -> Flash<()> {
|
||||||
|
self.regs.enable.modify(|_, w| w.spi_en(false));
|
||||||
|
// De-assert chip select.
|
||||||
|
self.regs.config.modify(|_, w| w.pcs(true));
|
||||||
|
|
||||||
|
self.transition()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ptr<T>(&mut self) -> *mut T {
|
||||||
|
0xFC00_0000 as *mut _
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn size(&self) -> usize {
|
||||||
|
2 * (SINGLE_CAPACITY as usize)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Flash<Manual> {
|
||||||
|
pub fn stop(self) -> Flash<()> {
|
||||||
|
self.transition()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read_reg<R: SpiFlashRegister>(&mut self) -> R {
|
||||||
|
let args = Some(R::inst_code());
|
||||||
|
let transfer = self.transfer(args.into_iter(), 2)
|
||||||
|
.bytes_transfer();
|
||||||
|
R::new(transfer.skip(1).next().unwrap())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read_reg_until<R, F, A>(&mut self, f: F) -> A
|
||||||
|
where
|
||||||
|
R: SpiFlashRegister,
|
||||||
|
F: Fn(R) -> Option<A>,
|
||||||
|
{
|
||||||
|
let mut result = None;
|
||||||
|
while result.is_none() {
|
||||||
|
let args = Some(R::inst_code());
|
||||||
|
for b in self.transfer(args.into_iter(), 32)
|
||||||
|
.bytes_transfer().skip(1) {
|
||||||
|
result = f(R::new(b));
|
||||||
|
|
||||||
|
if result.is_none() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Status Register-1 remains `0x00` immediately after invoking a command.
|
||||||
|
fn wait_while_sr1_zeroed(&mut self) -> SR1 {
|
||||||
|
self.read_reg_until::<SR1, _, SR1>(|sr1|
|
||||||
|
if sr1.is_zeroed() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(sr1)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Read Identification
|
||||||
|
pub fn rdid(&mut self) -> core::iter::Skip<BytesTransfer<Transfer<core::option::IntoIter<u32>, u32>>> {
|
||||||
|
let args = Some((INST_RDID as u32) << 24);
|
||||||
|
self.transfer(args.into_iter(), 0x44)
|
||||||
|
.bytes_transfer().skip(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Read flash data
|
||||||
|
pub fn read(&mut self, offset: u32, len: usize
|
||||||
|
) -> core::iter::Take<core::iter::Skip<BytesTransfer<Transfer<core::option::IntoIter<u32>, u32>>>>
|
||||||
|
{
|
||||||
|
let args = Some(((INST_READ as u32) << 24) | (offset as u32));
|
||||||
|
self.transfer(args.into_iter(), len + 6)
|
||||||
|
.bytes_transfer().skip(6).take(len)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn erase(&mut self, offset: u32) {
|
||||||
|
let args = Some(((INST_BE_4K as u32) << 24) | (offset as u32));
|
||||||
|
self.transfer(args.into_iter(), 4);
|
||||||
|
|
||||||
|
let sr1 = self.wait_while_sr1_zeroed();
|
||||||
|
|
||||||
|
if sr1.e_err() {
|
||||||
|
error!("E_ERR");
|
||||||
|
} else if sr1.p_err() {
|
||||||
|
error!("P_ERR");
|
||||||
|
} else if sr1.wip() {
|
||||||
|
info!("Erase in progress");
|
||||||
|
while self.read_reg::<SR1>().wip() {
|
||||||
|
print!(".");
|
||||||
|
}
|
||||||
|
println!("");
|
||||||
|
} else {
|
||||||
|
warn!("erased? sr1={:02X}", sr1.inner);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn program<I: Iterator<Item=u32>>(&mut self, offset: u32, data: I) {
|
||||||
|
{
|
||||||
|
let len = 4 + 4 * data.size_hint().0;
|
||||||
|
let args = Some(SpiWord::W32(((INST_PP as u32) << 24) | (offset as u32))).into_iter()
|
||||||
|
.chain(data.map(SpiWord::W32));
|
||||||
|
self.transfer(args, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
// let sr1 = self.wait_while_sr1_zeroed();
|
||||||
|
let sr1 = self.read_reg::<SR1>();
|
||||||
|
|
||||||
|
if sr1.e_err() {
|
||||||
|
error!("E_ERR");
|
||||||
|
} else if sr1.p_err() {
|
||||||
|
error!("P_ERR");
|
||||||
|
} else if sr1.wip() {
|
||||||
|
info!("Program in progress");
|
||||||
|
while self.read_reg::<SR1>().wip() {
|
||||||
|
print!(".");
|
||||||
|
}
|
||||||
|
println!("");
|
||||||
|
} else {
|
||||||
|
warn!("programmed? sr1={:02X}", sr1.inner);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write_enabled<F: Fn(&mut Self) -> R, R>(&mut self, f: F) -> R {
|
||||||
|
// Write Enable
|
||||||
|
let args = Some(INST_WREN);
|
||||||
|
self.transfer(args.into_iter(), 1);
|
||||||
|
self.regs.gpio.modify(|_, w| w.wp_n(true));
|
||||||
|
let sr1 = self.wait_while_sr1_zeroed();
|
||||||
|
if !sr1.wel() {
|
||||||
|
panic!("Cannot write-enable flash");
|
||||||
|
}
|
||||||
|
|
||||||
|
let result = f(self);
|
||||||
|
|
||||||
|
// Write Disable
|
||||||
|
let args = Some(INST_WRDI);
|
||||||
|
self.transfer(args.into_iter(), 1);
|
||||||
|
self.regs.gpio.modify(|_, w| w.wp_n(false));
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn transfer<'s: 't, 't, Args, W>(&'s mut self, args: Args, len: usize) -> Transfer<'t, Args, W>
|
||||||
|
where
|
||||||
|
Args: Iterator<Item = W>,
|
||||||
|
W: Into<SpiWord>,
|
||||||
|
{
|
||||||
|
Transfer::new(self, args, len)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dump(&mut self, label: &'_ str, inst_code: u8) {
|
||||||
|
print!("{}:", label);
|
||||||
|
|
||||||
|
let args = Some(u32::from(inst_code) << 24);
|
||||||
|
for b in self.transfer(args.into_iter(), 32).bytes_transfer() {
|
||||||
|
print!(" {:02X}", b);
|
||||||
|
}
|
||||||
|
println!("");
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,126 @@
|
||||||
|
use volatile_register::{RO, WO, RW};
|
||||||
|
|
||||||
|
use libregister::{register, register_bit, register_bits};
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct RegisterBlock {
|
||||||
|
pub config: Config,
|
||||||
|
pub intr_status: IntrStatus,
|
||||||
|
pub intr_en: IntrEn,
|
||||||
|
pub intr_dis: IntrDis,
|
||||||
|
pub intr_mask: RO<u32>,
|
||||||
|
pub enable: Enable,
|
||||||
|
pub delay: RW<u32>,
|
||||||
|
pub txd0: WO<u32>,
|
||||||
|
pub rx_data: RO<u32>,
|
||||||
|
pub slave_idle_count: RW<u32>,
|
||||||
|
pub tx_thres: RW<u32>,
|
||||||
|
pub rx_thres: RW<u32>,
|
||||||
|
pub gpio: QspiGpio,
|
||||||
|
pub _unused1: RO<u32>,
|
||||||
|
pub lpbk_dly_adj: RW<u32>,
|
||||||
|
pub _unused2: [RO<u32>; 17],
|
||||||
|
pub txd1: WO<u32>,
|
||||||
|
pub txd2: WO<u32>,
|
||||||
|
pub txd3: WO<u32>,
|
||||||
|
pub _unused3: [RO<u32>; 5],
|
||||||
|
pub lqspi_cfg: LqspiCfg,
|
||||||
|
pub lqspi_sts: RW<u32>,
|
||||||
|
pub _unused4: [RO<u32>; 21],
|
||||||
|
pub mod_id: RW<u32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RegisterBlock {
|
||||||
|
const BASE_ADDRESS: *mut Self = 0xE000D000 as *mut _;
|
||||||
|
|
||||||
|
pub fn qspi() -> &'static mut Self {
|
||||||
|
unsafe { &mut *Self::BASE_ADDRESS }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
register!(config, Config, RW, u32);
|
||||||
|
register_bit!(config,
|
||||||
|
/// Enables master mode
|
||||||
|
mode_sel, 0);
|
||||||
|
register_bit!(config,
|
||||||
|
/// Clock polarity low/high
|
||||||
|
clk_pol, 1);
|
||||||
|
register_bit!(config,
|
||||||
|
/// Clock phase
|
||||||
|
clk_ph, 2);
|
||||||
|
register_bits!(config,
|
||||||
|
/// divider = 2 ** (1 + baud_rate_div)
|
||||||
|
baud_rate_div, u8, 3, 5);
|
||||||
|
register_bits!(config,
|
||||||
|
/// Must be set to 0b11
|
||||||
|
fifo_width, u8, 6, 7);
|
||||||
|
register_bit!(config,
|
||||||
|
/// Must be 0
|
||||||
|
ref_clk, 8);
|
||||||
|
register_bit!(config,
|
||||||
|
/// Peripheral Chip Select Line
|
||||||
|
pcs, 10);
|
||||||
|
register_bit!(config,
|
||||||
|
/// false: auto mode, true: manual CS mode
|
||||||
|
manual_cs, 14);
|
||||||
|
register_bit!(config,
|
||||||
|
/// false: auto mode, true: enables manual start enable
|
||||||
|
man_start_en, 15);
|
||||||
|
register_bit!(config,
|
||||||
|
/// false: auto mode, true: enables manual start command
|
||||||
|
man_start_com, 16);
|
||||||
|
register_bit!(config, holdb_dr, 19);
|
||||||
|
register_bit!(config,
|
||||||
|
/// false: little, true: endian
|
||||||
|
endian, 26);
|
||||||
|
register_bit!(config,
|
||||||
|
/// false: legacy SPI mode, true: Flash memory interface mode
|
||||||
|
leg_flsh, 31);
|
||||||
|
|
||||||
|
register!(intr_status, IntrStatus, RW, u32);
|
||||||
|
register_bit!(intr_status, rx_overflow, 0);
|
||||||
|
register_bit!(intr_status,
|
||||||
|
/// < tx_thres
|
||||||
|
tx_fifo_not_full, 2);
|
||||||
|
register_bit!(intr_status, tx_fifo_full, 3);
|
||||||
|
register_bit!(intr_status,
|
||||||
|
/// >= rx_thres
|
||||||
|
rx_fifo_not_empty, 4);
|
||||||
|
register_bit!(intr_status, rx_fifo_full, 5);
|
||||||
|
register_bit!(intr_status, tx_fifo_underflow, 6);
|
||||||
|
|
||||||
|
register!(intr_en, IntrEn, WO, u32);
|
||||||
|
register_bit!(intr_en, rx_overflow, 0);
|
||||||
|
register_bit!(intr_en, tx_fifo_not_full, 2);
|
||||||
|
register_bit!(intr_en, tx_fifo_full, 3);
|
||||||
|
register_bit!(intr_en, rx_fifo_not_empty, 4);
|
||||||
|
register_bit!(intr_en, rx_fifo_full, 5);
|
||||||
|
register_bit!(intr_en, tx_fifo_underflow, 6);
|
||||||
|
|
||||||
|
register!(intr_dis, IntrDis, WO, u32);
|
||||||
|
register_bit!(intr_dis, rx_overflow, 0);
|
||||||
|
register_bit!(intr_dis, tx_fifo_not_full, 2);
|
||||||
|
register_bit!(intr_dis, tx_fifo_full, 3);
|
||||||
|
register_bit!(intr_dis, rx_fifo_not_empty, 4);
|
||||||
|
register_bit!(intr_dis, rx_fifo_full, 5);
|
||||||
|
register_bit!(intr_dis, tx_fifo_underflow, 6);
|
||||||
|
|
||||||
|
register!(enable, Enable, RW, u32);
|
||||||
|
register_bit!(enable, spi_en, 0);
|
||||||
|
|
||||||
|
// named to avoid confusion with normal gpio
|
||||||
|
register!(qspi_gpio, QspiGpio, RW, u32);
|
||||||
|
register_bit!(qspi_gpio,
|
||||||
|
/// Write protect pin (inverted)
|
||||||
|
wp_n, 0);
|
||||||
|
|
||||||
|
register!(lqspi_cfg, LqspiCfg, RW, u32);
|
||||||
|
register_bits!(lqspi_cfg, inst_code, u8, 0, 7);
|
||||||
|
register_bits!(lqspi_cfg, dummy_mask, u8, 8, 10);
|
||||||
|
register_bits!(lqspi_cfg, mode_bits, u8, 16, 23);
|
||||||
|
register_bit!(lqspi_cfg, mode_on, 24);
|
||||||
|
register_bit!(lqspi_cfg, mode_en, 25);
|
||||||
|
register_bit!(lqspi_cfg, u_page, 28);
|
||||||
|
register_bit!(lqspi_cfg, sep_bus, 29);
|
||||||
|
register_bit!(lqspi_cfg, two_mem, 30);
|
||||||
|
register_bit!(lqspi_cfg, lq_mode, 31);
|
|
@ -0,0 +1,62 @@
|
||||||
|
use bit_field::BitField;
|
||||||
|
|
||||||
|
pub trait SpiFlashRegister {
|
||||||
|
fn inst_code() -> u8;
|
||||||
|
fn new(src: u8) -> Self;
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! u8_register {
|
||||||
|
($name: ident, $doc: tt, $inst_code: expr) => {
|
||||||
|
#[derive(Clone)]
|
||||||
|
#[doc=$doc]
|
||||||
|
pub struct $name {
|
||||||
|
pub inner: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SpiFlashRegister for $name {
|
||||||
|
fn inst_code() -> u8 {
|
||||||
|
$inst_code
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new(src: u8) -> Self {
|
||||||
|
$name {
|
||||||
|
inner: src,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl $name {
|
||||||
|
#[allow(unused)]
|
||||||
|
pub fn is_zeroed(&self) -> bool {
|
||||||
|
self.inner == 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
u8_register!(CR, "Configuration Register", 0x35);
|
||||||
|
u8_register!(SR1, "Status Register-1", 0x05);
|
||||||
|
impl SR1 {
|
||||||
|
/// Write In Progress
|
||||||
|
pub fn wip(&self) -> bool {
|
||||||
|
self.inner.get_bit(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Write Enable Latch
|
||||||
|
pub fn wel(&self) -> bool {
|
||||||
|
self.inner.get_bit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Erase Error Occurred
|
||||||
|
pub fn e_err(&self) -> bool {
|
||||||
|
self.inner.get_bit(5)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Programming Error Occurred
|
||||||
|
pub fn p_err(&self) -> bool {
|
||||||
|
self.inner.get_bit(6)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
u8_register!(SR2, "Status Register-2", 0x07);
|
||||||
|
u8_register!(BA, "Bank Address Register", 0xB9);
|
|
@ -0,0 +1,125 @@
|
||||||
|
use libregister::{RegisterR, RegisterW, RegisterRW};
|
||||||
|
use super::regs;
|
||||||
|
use super::{SpiWord, Flash, Manual};
|
||||||
|
|
||||||
|
pub struct Transfer<'a, Args: Iterator<Item = W>, W: Into<SpiWord>> {
|
||||||
|
flash: &'a mut Flash<Manual>,
|
||||||
|
args: Args,
|
||||||
|
sent: usize,
|
||||||
|
received: usize,
|
||||||
|
len: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, Args: Iterator<Item = W>, W: Into<SpiWord>> Transfer<'a, Args, W> {
|
||||||
|
pub fn new(flash: &'a mut Flash<Manual>, args: Args, len: usize) -> Self {
|
||||||
|
flash.regs.config.modify(|_, w| w.pcs(false));
|
||||||
|
flash.regs.enable.write(
|
||||||
|
regs::Enable::zeroed()
|
||||||
|
.spi_en(true)
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut xfer = Transfer {
|
||||||
|
flash,
|
||||||
|
args,
|
||||||
|
sent: 0,
|
||||||
|
received: 0,
|
||||||
|
len,
|
||||||
|
};
|
||||||
|
xfer.fill_tx_fifo();
|
||||||
|
xfer.flash.regs.config.modify(|_, w| w.man_start_com(true));
|
||||||
|
xfer
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fill_tx_fifo(&mut self) {
|
||||||
|
while self.sent < self.len && !self.flash.regs.intr_status.read().tx_fifo_full() {
|
||||||
|
let arg = self.args.next()
|
||||||
|
.map(|n| n.into())
|
||||||
|
.unwrap_or(SpiWord::W32(0));
|
||||||
|
match arg {
|
||||||
|
SpiWord::W32(w) => {
|
||||||
|
// println!("txd0 {:08X}", w);
|
||||||
|
unsafe {
|
||||||
|
self.flash.regs.txd0.write(w);
|
||||||
|
}
|
||||||
|
self.sent += 4;
|
||||||
|
}
|
||||||
|
// Only txd0 can be used without flushing
|
||||||
|
_ => {
|
||||||
|
if !self.flash.regs.intr_status.read().tx_fifo_not_full() {
|
||||||
|
// Flush if necessary
|
||||||
|
self.flash.wait_tx_fifo_flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
match arg {
|
||||||
|
SpiWord::W8(w) => {
|
||||||
|
// println!("txd1 {:02X}", w);
|
||||||
|
unsafe {
|
||||||
|
self.flash.regs.txd1.write(u32::from(w) << 24);
|
||||||
|
}
|
||||||
|
self.sent += 1;
|
||||||
|
}
|
||||||
|
SpiWord::W16(w) => {
|
||||||
|
unsafe {
|
||||||
|
self.flash.regs.txd2.write(u32::from(w) << 16);
|
||||||
|
}
|
||||||
|
self.sent += 2;
|
||||||
|
}
|
||||||
|
SpiWord::W24(w) => {
|
||||||
|
unsafe {
|
||||||
|
self.flash.regs.txd3.write(w << 8);
|
||||||
|
}
|
||||||
|
self.sent += 3;
|
||||||
|
}
|
||||||
|
SpiWord::W32(_) => unreachable!(),
|
||||||
|
}
|
||||||
|
|
||||||
|
self.flash.wait_tx_fifo_flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn can_read(&mut self) -> bool {
|
||||||
|
self.flash.regs.intr_status.read().rx_fifo_not_empty()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read(&mut self) -> u32 {
|
||||||
|
let rx = self.flash.regs.rx_data.read();
|
||||||
|
self.received += 4;
|
||||||
|
rx
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, Args: Iterator<Item = W>, W: Into<SpiWord>> Drop for Transfer<'a, Args, W> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
// Discard remaining rx_data
|
||||||
|
while self.can_read() {
|
||||||
|
self.read();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop
|
||||||
|
self.flash.regs.enable.write(
|
||||||
|
regs::Enable::zeroed()
|
||||||
|
.spi_en(false)
|
||||||
|
);
|
||||||
|
self.flash.regs.config.modify(|_, w| w
|
||||||
|
.pcs(true)
|
||||||
|
.man_start_com(false)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, Args: Iterator<Item = W>, W: Into<SpiWord>> Iterator for Transfer<'a, Args, W> {
|
||||||
|
type Item = u32;
|
||||||
|
|
||||||
|
fn next<'s>(&'s mut self) -> Option<u32> {
|
||||||
|
if self.received >= self.len {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.fill_tx_fifo();
|
||||||
|
|
||||||
|
while !self.can_read() {}
|
||||||
|
Some(self.read())
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,150 +0,0 @@
|
||||||
//! ARM Generic Interrupt Controller
|
|
||||||
|
|
||||||
use bit_field::BitField;
|
|
||||||
use libregister::{RegisterW, RegisterRW, RegisterR};
|
|
||||||
use super::mpcore;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
pub struct InterruptId(pub u8);
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
#[repr(u8)]
|
|
||||||
pub enum CPUCore {
|
|
||||||
Core0 = 0b01,
|
|
||||||
Core1 = 0b10
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
pub struct TargetCPU(u8);
|
|
||||||
|
|
||||||
impl TargetCPU {
|
|
||||||
pub const fn none() -> TargetCPU {
|
|
||||||
TargetCPU(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const fn and(self, other: TargetCPU) -> TargetCPU {
|
|
||||||
TargetCPU(self.0 | other.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<CPUCore> for TargetCPU {
|
|
||||||
fn from(core: CPUCore) -> Self {
|
|
||||||
TargetCPU(core as u8)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum TargetList {
|
|
||||||
CPUList(TargetCPU),
|
|
||||||
Others,
|
|
||||||
This
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<CPUCore> for TargetList {
|
|
||||||
fn from(core: CPUCore) -> Self {
|
|
||||||
TargetList::CPUList(TargetCPU(core as u8))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<TargetCPU> for TargetList {
|
|
||||||
fn from(cpu: TargetCPU) -> Self {
|
|
||||||
TargetList::CPUList(cpu)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
pub enum InterruptSensitivity {
|
|
||||||
Level,
|
|
||||||
Edge,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct InterruptController {
|
|
||||||
mpcore: &'static mut mpcore::RegisterBlock,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl InterruptController {
|
|
||||||
pub fn gic(mpcore: &'static mut mpcore::RegisterBlock) -> Self {
|
|
||||||
InterruptController { mpcore }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn disable_interrupts(&mut self) {
|
|
||||||
self.mpcore.iccicr.modify(|_, w| w.enable_ns(false)
|
|
||||||
.enable_s(false));
|
|
||||||
// FIXME: Should we disable the distributor globally when we disable interrupt (for a single
|
|
||||||
// core)?
|
|
||||||
// self.mpcore.icddcr.modify(|_, w| w.enable_secure(false)
|
|
||||||
// .enable_non_secure(false));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// enable interrupt signaling
|
|
||||||
pub fn enable_interrupts(&mut self) {
|
|
||||||
self.mpcore.iccicr.modify(|_, w| w.enable_ns(true)
|
|
||||||
.enable_s(true));
|
|
||||||
self.mpcore.icddcr.modify(|_, w| w.enable_secure(true));
|
|
||||||
|
|
||||||
// Enable all interrupts except those of the lowest priority.
|
|
||||||
self.mpcore.iccpmr.write(mpcore::ICCPMR::zeroed().priority(0xFF));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// send software generated interrupt
|
|
||||||
pub fn send_sgi(&mut self, id: InterruptId, targets: TargetList) {
|
|
||||||
assert!(id.0 < 16);
|
|
||||||
self.mpcore.icdsgir.modify(|_, w| match targets {
|
|
||||||
TargetList::CPUList(list) => w.target_list_filter(0).cpu_target_list(list.0),
|
|
||||||
TargetList::Others => w.target_list_filter(0b01),
|
|
||||||
TargetList::This => w.target_list_filter(0b10)
|
|
||||||
}.sgiintid(id.0).satt(false));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// enable the interrupt *for this core*.
|
|
||||||
/// Not needed for SGI.
|
|
||||||
pub fn enable(&mut self, id: InterruptId, target_cpu: CPUCore, sensitivity: InterruptSensitivity, priority: u8) {
|
|
||||||
// only 5 bits of the priority is useful
|
|
||||||
assert!(priority < 32);
|
|
||||||
|
|
||||||
self.disable_interrupts();
|
|
||||||
|
|
||||||
// enable
|
|
||||||
let m = (id.0 >> 5) as usize;
|
|
||||||
let n = (id.0 & 0x1F) as usize;
|
|
||||||
assert!(m < 3);
|
|
||||||
unsafe {
|
|
||||||
self.mpcore.icdiser[m].modify(|mut icdiser| *icdiser.set_bit(n, true));
|
|
||||||
}
|
|
||||||
|
|
||||||
// target cpu
|
|
||||||
let m = (id.0 >> 2) as usize;
|
|
||||||
let n = (8 * (id.0 & 3)) as usize;
|
|
||||||
unsafe {
|
|
||||||
self.mpcore.icdiptr[m].modify(|mut icdiptr| *icdiptr.set_bits(n..=n+1, target_cpu as u32 + 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
// sensitivity
|
|
||||||
let m = (id.0 >> 4) as usize;
|
|
||||||
let n = (2 * (id.0 & 0xF)) as usize;
|
|
||||||
unsafe {
|
|
||||||
self.mpcore.icdicfr[m].modify(|mut icdicfr| *icdicfr.set_bits(n..=n+1, match sensitivity {
|
|
||||||
InterruptSensitivity::Level => 0b00,
|
|
||||||
InterruptSensitivity::Edge => 0b10,
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
// priority
|
|
||||||
let offset = (id.0 % 4) * 8;
|
|
||||||
let priority: u32 = (priority as u32) << (offset + 3);
|
|
||||||
let mask: u32 = 0xFFFFFFFF ^ (0xFF << offset);
|
|
||||||
unsafe {
|
|
||||||
self.mpcore.icdipr[id.0 as usize / 4].modify(|v| (v & mask) | priority);
|
|
||||||
}
|
|
||||||
|
|
||||||
self.enable_interrupts();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn end_interrupt(&mut self, id: InterruptId) {
|
|
||||||
self.mpcore.icceoir.modify(|_, w| w.eoiintid(id.0 as u32));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_interrupt_id(&self) -> InterruptId {
|
|
||||||
InterruptId(self.mpcore.icciar.read().ackintid() as u8)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,107 +0,0 @@
|
||||||
use super::I2c;
|
|
||||||
use crate::time::Milliseconds;
|
|
||||||
use embedded_hal::timer::CountDown;
|
|
||||||
|
|
||||||
pub struct EEPROM<'a> {
|
|
||||||
i2c: &'a mut I2c,
|
|
||||||
port: u8,
|
|
||||||
address: u8,
|
|
||||||
page_size: u8,
|
|
||||||
count_down: crate::timer::global::CountDown<Milliseconds>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> EEPROM<'a> {
|
|
||||||
#[cfg(feature = "target_zc706")]
|
|
||||||
pub fn new(i2c: &'a mut I2c, page_size: u8) -> Self {
|
|
||||||
EEPROM {
|
|
||||||
i2c: i2c,
|
|
||||||
port: 2,
|
|
||||||
address: 0b1010100,
|
|
||||||
page_size: page_size,
|
|
||||||
count_down: unsafe { crate::timer::GlobalTimer::get() }.countdown()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "target_zc706")]
|
|
||||||
fn select(&mut self) -> Result<(), &'static str> {
|
|
||||||
let mask: u16 = 1 << self.port;
|
|
||||||
self.i2c.pca9548_select(0b1110100, mask as u8)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Random read
|
|
||||||
pub fn read<'r>(&mut self, addr: u8, buf: &'r mut [u8]) -> Result<(), &'static str> {
|
|
||||||
self.select()?;
|
|
||||||
|
|
||||||
self.i2c.start()?;
|
|
||||||
self.i2c.write(self.address << 1)?;
|
|
||||||
self.i2c.write(addr)?;
|
|
||||||
|
|
||||||
self.i2c.restart()?;
|
|
||||||
self.i2c.write((self.address << 1) | 1)?;
|
|
||||||
let buf_len = buf.len();
|
|
||||||
for (i, byte) in buf.iter_mut().enumerate() {
|
|
||||||
*byte = self.i2c.read(i < buf_len - 1)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.i2c.stop()?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Smart multi-page writing
|
|
||||||
/// Using the "Page Write" function of an EEPROM, the memory region for each transaction
|
|
||||||
/// (i.e. from byte `addr` to byte `addr+buf.len()`) should fit under each page
|
|
||||||
/// (i.e. `addr+buf.len()` < `addr/self.page_size+1`); otherwise, a roll-oever occurs,
|
|
||||||
/// where bytes beyond the page end. This smart function takes care of the scenario to avoid
|
|
||||||
/// any roll-over when writing ambiguous memory regions.
|
|
||||||
pub fn write(&mut self, addr: u8, buf: &[u8]) -> Result<(), &'static str> {
|
|
||||||
self.select()?;
|
|
||||||
|
|
||||||
let buf_len = buf.len();
|
|
||||||
let mut pb: u8 = addr % self.page_size;
|
|
||||||
for (i, byte) in buf.iter().enumerate() {
|
|
||||||
if (i == 0) || (pb == 0) {
|
|
||||||
self.i2c.start()?;
|
|
||||||
self.i2c.write(self.address << 1)?;
|
|
||||||
self.i2c.write(addr + (i as u8))?;
|
|
||||||
}
|
|
||||||
self.i2c.write(*byte)?;
|
|
||||||
pb += 1;
|
|
||||||
|
|
||||||
if (i == buf_len-1) || (pb == self.page_size) {
|
|
||||||
self.i2c.stop()?;
|
|
||||||
self.poll(1_000)?;
|
|
||||||
pb = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Poll
|
|
||||||
pub fn poll(&mut self, timeout_ms: u64) -> Result<(), &'static str> {
|
|
||||||
self.select()?;
|
|
||||||
|
|
||||||
self.count_down.start(Milliseconds(timeout_ms));
|
|
||||||
loop {
|
|
||||||
self.i2c.start()?;
|
|
||||||
let ack = self.i2c.write(self.address << 1)?;
|
|
||||||
self.i2c.stop()?;
|
|
||||||
if ack {
|
|
||||||
break
|
|
||||||
};
|
|
||||||
if !self.count_down.waiting() {
|
|
||||||
return Err("I2C polling timeout")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn read_eui48<'r>(&mut self) -> Result<[u8; 6], &'static str> {
|
|
||||||
let mut buffer = [0u8; 6];
|
|
||||||
self.read(0xFA, &mut buffer)?;
|
|
||||||
Ok(buffer)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,231 +0,0 @@
|
||||||
//! I2C Bit-banging Controller
|
|
||||||
|
|
||||||
mod regs;
|
|
||||||
pub mod eeprom;
|
|
||||||
use super::slcr;
|
|
||||||
use super::time::Microseconds;
|
|
||||||
use embedded_hal::timer::CountDown;
|
|
||||||
use libregister::{RegisterR, RegisterRW, RegisterW};
|
|
||||||
|
|
||||||
pub struct I2c {
|
|
||||||
regs: regs::RegisterBlock,
|
|
||||||
count_down: super::timer::global::CountDown<Microseconds>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl I2c {
|
|
||||||
#[cfg(feature = "target_zc706")]
|
|
||||||
pub fn i2c0() -> Self {
|
|
||||||
// Route I2C 0 SCL / SDA Signals to MIO Pins 50 / 51
|
|
||||||
slcr::RegisterBlock::unlocked(|slcr| {
|
|
||||||
// SCL
|
|
||||||
slcr.mio_pin_50.write(
|
|
||||||
slcr::MioPin50::zeroed()
|
|
||||||
.l3_sel(0b000) // as GPIO 50
|
|
||||||
.io_type(slcr::IoBufferType::Lvcmos18)
|
|
||||||
.pullup(true)
|
|
||||||
.disable_rcvr(true)
|
|
||||||
);
|
|
||||||
// SDA
|
|
||||||
slcr.mio_pin_51.write(
|
|
||||||
slcr::MioPin51::zeroed()
|
|
||||||
.l3_sel(0b000) // as GPIO 51
|
|
||||||
.io_type(slcr::IoBufferType::Lvcmos18)
|
|
||||||
.pullup(true)
|
|
||||||
.disable_rcvr(true)
|
|
||||||
);
|
|
||||||
// Reset
|
|
||||||
slcr.gpio_rst_ctrl.reset_gpio();
|
|
||||||
});
|
|
||||||
|
|
||||||
Self::i2c_common(0xFFFF - 0x000C)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn i2c_common(gpio_output_mask: u16) -> Self {
|
|
||||||
// Setup register block
|
|
||||||
let self_ = Self {
|
|
||||||
regs: regs::RegisterBlock::i2c(),
|
|
||||||
count_down: unsafe { super::timer::GlobalTimer::get() }.countdown()
|
|
||||||
};
|
|
||||||
|
|
||||||
// Setup GPIO output mask
|
|
||||||
self_.regs.gpio_output_mask.modify(|_, w| {
|
|
||||||
w.mask(gpio_output_mask)
|
|
||||||
});
|
|
||||||
// Setup GPIO driver direction
|
|
||||||
self_.regs.gpio_direction.modify(|_, w| {
|
|
||||||
w.scl(true).sda(true)
|
|
||||||
});
|
|
||||||
|
|
||||||
self_
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Delay for I2C operations, simple wrapper for nb.
|
|
||||||
fn delay_us(&mut self, us: u64) {
|
|
||||||
self.count_down.start(Microseconds(us));
|
|
||||||
nb::block!(self.count_down.wait()).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn half_period(&mut self) { self.delay_us(100) }
|
|
||||||
|
|
||||||
fn sda_i(&mut self) -> bool {
|
|
||||||
self.regs.gpio_input.read().sda()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn scl_i(&mut self) -> bool {
|
|
||||||
self.regs.gpio_input.read().scl()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn sda_oe(&mut self, oe: bool) {
|
|
||||||
self.regs.gpio_output_enable.modify(|_, w| {
|
|
||||||
w.sda(oe)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn sda_o(&mut self, o: bool) {
|
|
||||||
self.regs.gpio_output_mask.modify(|_, w| {
|
|
||||||
w.sda_o(o)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn scl_oe(&mut self, oe: bool) {
|
|
||||||
self.regs.gpio_output_enable.modify(|_, w| {
|
|
||||||
w.scl(oe)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn scl_o(&mut self, o: bool) {
|
|
||||||
self.regs.gpio_output_mask.modify(|_, w| {
|
|
||||||
w.scl_o(o)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn init(&mut self) -> Result<(), &'static str> {
|
|
||||||
self.scl_oe(false);
|
|
||||||
self.sda_oe(false);
|
|
||||||
self.scl_o(false);
|
|
||||||
self.sda_o(false);
|
|
||||||
|
|
||||||
// Check the I2C bus is ready
|
|
||||||
self.half_period();
|
|
||||||
self.half_period();
|
|
||||||
if !self.sda_i() {
|
|
||||||
// Try toggling SCL a few times
|
|
||||||
for _bit in 0..8 {
|
|
||||||
self.scl_oe(true);
|
|
||||||
self.half_period();
|
|
||||||
self.scl_oe(false);
|
|
||||||
self.half_period();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !self.sda_i() {
|
|
||||||
return Err("SDA is stuck low and doesn't get unstuck");
|
|
||||||
}
|
|
||||||
if !self.scl_i() {
|
|
||||||
return Err("SCL is stuck low and doesn't get unstuck");
|
|
||||||
}
|
|
||||||
// postcondition: SCL and SDA high
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn start(&mut self) -> Result<(), &'static str> {
|
|
||||||
// precondition: SCL and SDA high
|
|
||||||
if !self.scl_i() {
|
|
||||||
return Err("SCL is stuck low and doesn't get unstuck");
|
|
||||||
}
|
|
||||||
if !self.sda_i() {
|
|
||||||
return Err("SDA arbitration lost");
|
|
||||||
}
|
|
||||||
self.sda_oe(true);
|
|
||||||
self.half_period();
|
|
||||||
self.scl_oe(true);
|
|
||||||
// postcondition: SCL and SDA low
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn restart(&mut self) -> Result<(), &'static str> {
|
|
||||||
// precondition SCL and SDA low
|
|
||||||
self.sda_oe(false);
|
|
||||||
self.half_period();
|
|
||||||
self.scl_oe(false);
|
|
||||||
self.half_period();
|
|
||||||
self.start()?;
|
|
||||||
// postcondition: SCL and SDA low
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn stop(&mut self) -> Result<(), &'static str> {
|
|
||||||
// precondition: SCL and SDA low
|
|
||||||
self.half_period();
|
|
||||||
self.scl_oe(false);
|
|
||||||
self.half_period();
|
|
||||||
self.sda_oe(false);
|
|
||||||
self.half_period();
|
|
||||||
if !self.sda_i() {
|
|
||||||
return Err("SDA arbitration lost");
|
|
||||||
}
|
|
||||||
// postcondition: SCL and SDA high
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn write(&mut self, data: u8) -> Result<bool, &'static str> {
|
|
||||||
// precondition: SCL and SDA low
|
|
||||||
// MSB first
|
|
||||||
for bit in (0..8).rev() {
|
|
||||||
self.sda_oe(data & (1 << bit) == 0);
|
|
||||||
self.half_period();
|
|
||||||
self.scl_oe(false);
|
|
||||||
self.half_period();
|
|
||||||
self.scl_oe(true);
|
|
||||||
}
|
|
||||||
self.sda_oe(false);
|
|
||||||
self.half_period();
|
|
||||||
self.scl_oe(false);
|
|
||||||
self.half_period();
|
|
||||||
// Read ack/nack
|
|
||||||
let ack = !self.sda_i();
|
|
||||||
self.scl_oe(true);
|
|
||||||
self.sda_oe(true);
|
|
||||||
// postcondition: SCL and SDA low
|
|
||||||
|
|
||||||
Ok(ack)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn read(&mut self, ack: bool) -> Result<u8, &'static str> {
|
|
||||||
// precondition: SCL and SDA low
|
|
||||||
self.sda_oe(false);
|
|
||||||
|
|
||||||
let mut data: u8 = 0;
|
|
||||||
|
|
||||||
// MSB first
|
|
||||||
for bit in (0..8).rev() {
|
|
||||||
self.half_period();
|
|
||||||
self.scl_oe(false);
|
|
||||||
self.half_period();
|
|
||||||
if self.sda_i() { data |= 1 << bit }
|
|
||||||
self.scl_oe(true);
|
|
||||||
}
|
|
||||||
// Send ack/nack
|
|
||||||
self.sda_oe(ack);
|
|
||||||
self.half_period();
|
|
||||||
self.scl_oe(false);
|
|
||||||
self.half_period();
|
|
||||||
self.scl_oe(true);
|
|
||||||
self.sda_oe(true);
|
|
||||||
// postcondition: SCL and SDA low
|
|
||||||
|
|
||||||
Ok(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn pca9548_select(&mut self, address: u8, channels: u8) -> Result<(), &'static str> {
|
|
||||||
self.start()?;
|
|
||||||
if !self.write(address << 1)? {
|
|
||||||
return Err("PCA9548 failed to ack write address")
|
|
||||||
}
|
|
||||||
if !self.write(channels)? {
|
|
||||||
return Err("PCA9548 failed to ack control word")
|
|
||||||
}
|
|
||||||
self.stop()?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,91 +0,0 @@
|
||||||
use libregister::{
|
|
||||||
register, register_at,
|
|
||||||
register_bit, register_bits
|
|
||||||
};
|
|
||||||
|
|
||||||
// With reference to:
|
|
||||||
//
|
|
||||||
// artiq:artiq/gateware/targets/kasli.py:
|
|
||||||
// self.submodules.i2c = gpio.GPIOTristate([i2c.scl, i2c.sda])
|
|
||||||
//
|
|
||||||
// misoc:misoc/cores/gpio.py:
|
|
||||||
// class GPIOTristate(Module, AutoCSR):
|
|
||||||
// def __init__(self, signals, reset_out=0, reset_oe=0):
|
|
||||||
// l = len(signals)
|
|
||||||
// self._in = CSRStatus(l)
|
|
||||||
// self._out = CSRStorage(l, reset=reset_out)
|
|
||||||
// self._oe = CSRStorage(l, reset=reset_oe)
|
|
||||||
//
|
|
||||||
// Hence, using GPIOs as SCL and SDA GPIOs respectively.
|
|
||||||
//
|
|
||||||
// Current compatibility:
|
|
||||||
// zc706: GPIO 50, 51 == SCL, SDA
|
|
||||||
|
|
||||||
pub struct RegisterBlock {
|
|
||||||
pub gpio_output_mask: &'static mut GPIOOutputMask,
|
|
||||||
pub gpio_input: &'static mut GPIOInput,
|
|
||||||
pub gpio_direction: &'static mut GPIODirection,
|
|
||||||
pub gpio_output_enable: &'static mut GPIOOutputEnable,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RegisterBlock {
|
|
||||||
pub fn i2c() -> Self {
|
|
||||||
Self {
|
|
||||||
gpio_output_mask: GPIOOutputMask::new(),
|
|
||||||
gpio_input: GPIOInput::new(),
|
|
||||||
gpio_direction: GPIODirection::new(),
|
|
||||||
gpio_output_enable: GPIOOutputEnable::new()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MASK_DATA_1_MSW:
|
|
||||||
// Maskable output data for MIO[53:48]
|
|
||||||
register!(gpio_output_mask, GPIOOutputMask, RW, u32);
|
|
||||||
#[cfg(feature = "target_zc706")]
|
|
||||||
register_at!(GPIOOutputMask, 0xE000A00C, new);
|
|
||||||
// Output for SCL
|
|
||||||
#[cfg(feature = "target_zc706")]
|
|
||||||
register_bit!(gpio_output_mask, scl_o, 2);
|
|
||||||
// Output for SDA
|
|
||||||
#[cfg(feature = "target_zc706")]
|
|
||||||
register_bit!(gpio_output_mask, sda_o, 3);
|
|
||||||
// Mask for keeping bits except SCL and SDA unchanged
|
|
||||||
#[cfg(feature = "target_zc706")]
|
|
||||||
register_bits!(gpio_output_mask, mask, u16, 16, 31);
|
|
||||||
|
|
||||||
// DATA_1_RO:
|
|
||||||
// Input data for MIO[53:32]
|
|
||||||
register!(gpio_input, GPIOInput, RO, u32);
|
|
||||||
#[cfg(feature = "target_zc706")]
|
|
||||||
register_at!(GPIOInput, 0xE000A064, new);
|
|
||||||
// Input for SCL
|
|
||||||
#[cfg(feature = "target_zc706")]
|
|
||||||
register_bit!(gpio_input, scl, 18);
|
|
||||||
// Input for SDA
|
|
||||||
#[cfg(feature = "target_zc706")]
|
|
||||||
register_bit!(gpio_input, sda, 19);
|
|
||||||
|
|
||||||
// DIRM_1:
|
|
||||||
// Direction mode for MIO[53:32]; 0/1 = in/out
|
|
||||||
register!(gpio_direction, GPIODirection, RW, u32);
|
|
||||||
#[cfg(feature = "target_zc706")]
|
|
||||||
register_at!(GPIODirection, 0xE000A244, new);
|
|
||||||
// Direction for SCL
|
|
||||||
#[cfg(feature = "target_zc706")]
|
|
||||||
register_bit!(gpio_direction, scl, 18);
|
|
||||||
// Direction for SDA
|
|
||||||
#[cfg(feature = "target_zc706")]
|
|
||||||
register_bit!(gpio_direction, sda, 19);
|
|
||||||
|
|
||||||
// OEN_1:
|
|
||||||
// Output enable for MIO[53:32]
|
|
||||||
register!(gpio_output_enable, GPIOOutputEnable, RW, u32);
|
|
||||||
#[cfg(feature = "target_zc706")]
|
|
||||||
register_at!(GPIOOutputEnable, 0xE000A248, new);
|
|
||||||
// Output enable for SCL
|
|
||||||
#[cfg(feature = "target_zc706")]
|
|
||||||
register_bit!(gpio_output_enable, scl, 18);
|
|
||||||
// Output enable for SDA
|
|
||||||
#[cfg(feature = "target_zc706")]
|
|
||||||
register_bit!(gpio_output_enable, sda, 19);
|
|
|
@ -15,11 +15,37 @@ pub mod axi_hp;
|
||||||
pub mod axi_gp;
|
pub mod axi_gp;
|
||||||
pub mod ddr;
|
pub mod ddr;
|
||||||
pub mod mpcore;
|
pub mod mpcore;
|
||||||
pub mod gic;
|
pub mod flash;
|
||||||
|
pub mod dmac;
|
||||||
pub mod time;
|
pub mod time;
|
||||||
pub mod timer;
|
pub mod timer;
|
||||||
pub mod sdio;
|
pub mod sdio;
|
||||||
#[cfg(feature = "target_zc706")]
|
|
||||||
pub mod i2c;
|
|
||||||
pub mod logger;
|
pub mod logger;
|
||||||
pub mod ps7_init;
|
|
||||||
|
pub use libcortex_a9::pl310::L2Cache;
|
||||||
|
|
||||||
|
pub fn l2cache() -> L2Cache {
|
||||||
|
const PL310_BASEADDR: usize = 0xF8F02000;
|
||||||
|
L2Cache::new(PL310_BASEADDR)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn setup_l2cache() {
|
||||||
|
slcr::RegisterBlock::unlocked(|slcr| {
|
||||||
|
assert_eq!(&slcr.unnamed1 as *const _ as u32, 0xF8000A1C);
|
||||||
|
unsafe { slcr.unnamed1.write(0x020202); }
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut l2 = l2cache();
|
||||||
|
use log::info;
|
||||||
|
info!("l2 aux={:08X}", l2.regs.aux_control.read());
|
||||||
|
// TODO: set prefetch
|
||||||
|
|
||||||
|
// Configure ZYNQ-specific latency
|
||||||
|
l2.set_tag_ram_latencies(1, 1, 1);
|
||||||
|
l2.set_data_ram_latencies(1, 2, 1);
|
||||||
|
|
||||||
|
l2.disable_interrupts();
|
||||||
|
l2.reset_interrupts();
|
||||||
|
l2.invalidate_all();
|
||||||
|
l2.enable();
|
||||||
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@ impl log::Log for Logger {
|
||||||
if self.enabled(record.metadata()) {
|
if self.enabled(record.metadata()) {
|
||||||
let timestamp = unsafe {
|
let timestamp = unsafe {
|
||||||
GlobalTimer::get()
|
GlobalTimer::get()
|
||||||
}.get_us().0;
|
}.get_us();
|
||||||
let seconds = timestamp / 1_000_000;
|
let seconds = timestamp / 1_000_000;
|
||||||
let micros = timestamp % 1_000_000;
|
let micros = timestamp % 1_000_000;
|
||||||
|
|
||||||
|
|
|
@ -8,140 +8,47 @@ use libregister::{
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct RegisterBlock {
|
pub struct RegisterBlock {
|
||||||
/// SCU Control Register
|
|
||||||
pub scu_control: ScuControl,
|
pub scu_control: ScuControl,
|
||||||
/// SCU Configuration Register
|
pub scu_config: RO<u32>,
|
||||||
pub scu_config: ScuConfig,
|
pub scu_cpu_power: RW<u32>,
|
||||||
/// SCU CPU Power Status Register
|
|
||||||
pub scu_cpu_power_status: SCUCPUPowerStatusRegister,
|
|
||||||
/// SCU Invalidate All Registers in Secure State
|
|
||||||
pub scu_invalidate: ScuInvalidate,
|
pub scu_invalidate: ScuInvalidate,
|
||||||
unused0: [u32; 12],
|
reserved0: [u32; 12],
|
||||||
/// Filtering Start Address Register
|
pub filter_start: RW<u32>,
|
||||||
pub filtering_start_address: FilteringStartAddressRegister,
|
pub filter_end: RW<u32>,
|
||||||
/// Defined by FILTEREND input
|
reserved1: [u32; 2],
|
||||||
pub filtering_end_address: FilteringEndAddressRegister,
|
pub scu_access_control: RW<u32>,
|
||||||
unused1: [u32; 2],
|
pub scu_non_secure_access_control: RW<u32>,
|
||||||
/// SCU Access Control (SAC) Register
|
reserved2: [u32; 42],
|
||||||
pub scu_access_control_sac: SCUAccessControlRegisterSAC,
|
pub iccicr: RW<u32>,
|
||||||
/// SCU Non-secure Access Control Register SNSAC
|
pub iccpmw: RW<u32>,
|
||||||
pub scu_non_secure_access_control: SCUNonSecureAccessControlRegister,
|
pub iccbpr: RW<u32>,
|
||||||
unused2: [u32; 42],
|
pub icciar: RW<u32>,
|
||||||
/// CPU Interface Control Register
|
pub icceoir: RW<u32>,
|
||||||
pub iccicr: ICCICR,
|
pub iccrpr: RW<u32>,
|
||||||
/// Interrupt Priority Mask Register
|
pub icchpir: RW<u32>,
|
||||||
pub iccpmr: ICCPMR,
|
pub iccabpr: RW<u32>,
|
||||||
/// Binary Point Register
|
reserved3: [u32; 55],
|
||||||
pub iccbpr: ICCBPR,
|
pub iccidr: RW<u32>,
|
||||||
/// Interrupt Acknowledge Register
|
|
||||||
pub icciar: ICCIAR,
|
|
||||||
/// End Of Interrupt Register
|
|
||||||
pub icceoir: ICCEOIR,
|
|
||||||
/// Running Priority Register
|
|
||||||
pub iccrpr: ICCRPR,
|
|
||||||
/// Highest Pending Interrupt Register
|
|
||||||
pub icchpir: ICCHPIR,
|
|
||||||
/// Aliased Non-secure Binary Point Register
|
|
||||||
pub iccabpr: ICCABPR,
|
|
||||||
unused3: [u32; 55],
|
|
||||||
/// CPU Interface Implementer Identification Register
|
|
||||||
pub iccidr: ICCIDR,
|
|
||||||
/// Global Timer Counter Register 0
|
|
||||||
pub global_timer_counter0: ValueRegister,
|
pub global_timer_counter0: ValueRegister,
|
||||||
pub global_timer_counter1: ValueRegister,
|
pub global_timer_counter1: ValueRegister,
|
||||||
/// Global Timer Control Register
|
|
||||||
pub global_timer_control: GlobalTimerControl,
|
pub global_timer_control: GlobalTimerControl,
|
||||||
/// Global Timer Interrupt Status Register
|
pub global_timer_interrupt_status: RW<u32>,
|
||||||
pub global_timer_interrupt_status: GlobalTimerInterruptStatusRegister,
|
|
||||||
/// Comparator Value Register_0
|
|
||||||
pub comparator_value0: ValueRegister,
|
pub comparator_value0: ValueRegister,
|
||||||
pub comparator_value1: ValueRegister,
|
pub comparator_value1: ValueRegister,
|
||||||
/// Auto-increment Register
|
pub auto_increment: ValueRegister,
|
||||||
pub auto_increment: RW<u32>,
|
reserved4: [u32; 249],
|
||||||
unused4: [u32; 249],
|
pub private_timer_load: ValueRegister,
|
||||||
/// Private Timer Load Register
|
pub private_timer_counter: ValueRegister,
|
||||||
pub private_timer_load: RW<u32>,
|
pub private_timer_control: RW<u32>,
|
||||||
/// Private Timer Counter Register
|
pub private_timer_interrupt_status: RW<u32>,
|
||||||
pub private_timer_counter: RW<u32>,
|
reserved5: [u32; 4],
|
||||||
/// Private Timer Control Register
|
pub watchdog_load: ValueRegister,
|
||||||
pub private_timer_control: PrivateTimerControlRegister,
|
pub watchdog_counter: ValueRegister,
|
||||||
/// Private Timer Interrupt Status Register
|
pub watchdog_control: RW<u32>,
|
||||||
pub private_timer_interrupt_status: PrivateTimerInterruptStatusRegister,
|
pub watchdog_interrupt_status: RW<u32>,
|
||||||
unused5: [u32; 4],
|
// there is plenty more (unimplemented)
|
||||||
/// Watchdog Load Register
|
|
||||||
pub watchdog_load: RW<u32>,
|
|
||||||
/// Watchdog Counter Register
|
|
||||||
pub watchdog_counter: RW<u32>,
|
|
||||||
/// Watchdog Control Register
|
|
||||||
pub watchdog_control: WatchdogControlRegister,
|
|
||||||
/// Watchdog Interrupt Status Register
|
|
||||||
pub watchdog_interrupt_status: WatchdogInterruptStatusRegister,
|
|
||||||
/// Watchdog Reset Status Register
|
|
||||||
pub watchdog_reset_status: WatchdogResetStatusRegister,
|
|
||||||
/// Watchdog Disable Register
|
|
||||||
pub watchdog_disable: RW<u32>,
|
|
||||||
unused6: [u32; 626],
|
|
||||||
/// Distributor Control Register
|
|
||||||
pub icddcr: ICDDCR,
|
|
||||||
/// Interrupt Controller Type Register
|
|
||||||
pub icdictr: ICDICTR,
|
|
||||||
/// Distributor Implementer Identification Register
|
|
||||||
pub icdiidr: ICDIIDR,
|
|
||||||
unused7: [u32; 29],
|
|
||||||
/// Interrupt Security Register
|
|
||||||
pub icdisr0: RW<u32>,
|
|
||||||
pub icdisr1: RW<u32>,
|
|
||||||
pub icdisr2: RW<u32>,
|
|
||||||
unused8: [u32; 29],
|
|
||||||
/// Interrupt Set-enable Registers
|
|
||||||
pub icdiser: [RW<u32>; 3],
|
|
||||||
unused9: [u32; 29],
|
|
||||||
/// Interrupt Clear-Enable Register 0
|
|
||||||
pub icdicer0: RW<u32>,
|
|
||||||
/// Interrupt Clear-Enable Register 1
|
|
||||||
pub icdicer1: RW<u32>,
|
|
||||||
/// Interrupt Clear-Enable Register 2
|
|
||||||
pub icdicer2: RW<u32>,
|
|
||||||
unused10: [u32; 29],
|
|
||||||
/// Interrupt Set-pending Register
|
|
||||||
pub icdispr0: RW<u32>,
|
|
||||||
pub icdispr1: RW<u32>,
|
|
||||||
pub icdispr2: RW<u32>,
|
|
||||||
unused11: [u32; 29],
|
|
||||||
/// Interrupt Clear-Pending Register
|
|
||||||
pub icdicpr0: RW<u32>,
|
|
||||||
pub icdicpr1: RW<u32>,
|
|
||||||
pub icdicpr2: RW<u32>,
|
|
||||||
unused12: [u32; 29],
|
|
||||||
/// Active Bit register
|
|
||||||
pub icdabr0: RW<u32>,
|
|
||||||
pub icdabr1: RW<u32>,
|
|
||||||
pub icdabr2: RW<u32>,
|
|
||||||
unused13: [u32; 61],
|
|
||||||
/// Interrupt Priority Register
|
|
||||||
pub icdipr: [RW<u32>; 24],
|
|
||||||
unused14: [u32; 232],
|
|
||||||
/// Interrupt Processor Targets Registers
|
|
||||||
pub icdiptr: [RW<u32>; 24],
|
|
||||||
unused15: [u32; 232],
|
|
||||||
/// Interrupt Configuration Registers
|
|
||||||
pub icdicfr: [RW<u32>; 6],
|
|
||||||
unused16: [u32; 58],
|
|
||||||
/// PPI Status Register
|
|
||||||
pub ppi_status: PpiStatus,
|
|
||||||
/// SPI Status Register 0
|
|
||||||
pub spi_status_0: RO<u32>,
|
|
||||||
/// SPI Status Register 1
|
|
||||||
pub spi_status_1: RO<u32>,
|
|
||||||
unused17: [u32; 125],
|
|
||||||
/// Software Generated Interrupt Register
|
|
||||||
pub icdsgir: ICDSGIR,
|
|
||||||
}
|
}
|
||||||
|
register_at!(RegisterBlock, 0xF8F00000, new);
|
||||||
register_at!(RegisterBlock, 0xF8F00000, mpcore);
|
|
||||||
|
|
||||||
register!(value_register, ValueRegister, RW, u32);
|
|
||||||
register_bits!(value_register, value, u32, 0, 31);
|
|
||||||
|
|
||||||
register!(scu_control, ScuControl, RW, u32);
|
register!(scu_control, ScuControl, RW, u32);
|
||||||
register_bit!(scu_control, ic_standby_enable, 6);
|
register_bit!(scu_control, ic_standby_enable, 6);
|
||||||
|
@ -154,21 +61,10 @@ register_bit!(scu_control, enable, 0);
|
||||||
|
|
||||||
impl ScuControl {
|
impl ScuControl {
|
||||||
pub fn start(&mut self) {
|
pub fn start(&mut self) {
|
||||||
self.modify(|_, w| w.enable(true).scu_speculative_linefill_enable(true));
|
self.modify(|_, w| w.enable(true));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
register!(scu_config, ScuConfig, RO, u32);
|
|
||||||
register_bits!(scu_config, tag_ram_sizes, u8, 8, 15);
|
|
||||||
register_bits!(scu_config, cpus_smp, u8, 4, 7);
|
|
||||||
register_bits!(scu_config, cpu_number, u8, 0, 1);
|
|
||||||
|
|
||||||
register!(scu_cpu_power_status, SCUCPUPowerStatusRegister, RW, u32);
|
|
||||||
register_bits!(scu_cpu_power_status, cpu3_status, u8, 24, 25);
|
|
||||||
register_bits!(scu_cpu_power_status, cpu2_status, u8, 16, 17);
|
|
||||||
register_bits!(scu_cpu_power_status, cpu1_status, u8, 8, 9);
|
|
||||||
register_bits!(scu_cpu_power_status, cpu0_status, u8, 0, 1);
|
|
||||||
|
|
||||||
register!(scu_invalidate, ScuInvalidate, WO, u32);
|
register!(scu_invalidate, ScuInvalidate, WO, u32);
|
||||||
register_bits!(scu_invalidate, cpu0_ways, u8, 0, 3);
|
register_bits!(scu_invalidate, cpu0_ways, u8, 0, 3);
|
||||||
register_bits!(scu_invalidate, cpu1_ways, u8, 4, 7);
|
register_bits!(scu_invalidate, cpu1_ways, u8, 4, 7);
|
||||||
|
@ -192,71 +88,8 @@ impl ScuInvalidate {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
register!(filtering_start_address, FilteringStartAddressRegister, RW, u32);
|
register!(value_register, ValueRegister, RW, u32);
|
||||||
register_bits!(filtering_start_address, filtering_start_address, u32, 20, 31);
|
register_bits!(value_register, value, u32, 0, 31);
|
||||||
register_bits!(filtering_start_address, sbz, u32, 0, 19);
|
|
||||||
|
|
||||||
register!(filtering_end_address, FilteringEndAddressRegister, RW, u32);
|
|
||||||
register_bits!(filtering_end_address, filtering_end_address, u32, 20, 31);
|
|
||||||
register_bits!(filtering_end_address, sbz, u32, 0, 19);
|
|
||||||
|
|
||||||
register!(scu_access_control_sac, SCUAccessControlRegisterSAC, RW, u32);
|
|
||||||
register_bit!(scu_access_control_sac, cp_u3, 3);
|
|
||||||
register_bit!(scu_access_control_sac, cp_u2, 2);
|
|
||||||
register_bit!(scu_access_control_sac, cp_u1, 1);
|
|
||||||
register_bit!(scu_access_control_sac, cp_u0, 0);
|
|
||||||
|
|
||||||
register!(scu_non_secure_access_control, SCUNonSecureAccessControlRegister, RO, u32);
|
|
||||||
register_bits!(scu_non_secure_access_control, sbz, u32, 12, 31);
|
|
||||||
register_bit!(scu_non_secure_access_control, cpu3_global_timer, 11);
|
|
||||||
register_bit!(scu_non_secure_access_control, cpu2_global_timer, 10);
|
|
||||||
register_bit!(scu_non_secure_access_control, cpu1_global_timer, 9);
|
|
||||||
register_bit!(scu_non_secure_access_control, cpu0_global_timer, 8);
|
|
||||||
register_bit!(scu_non_secure_access_control, private_timers_for_cpu3, 7);
|
|
||||||
register_bit!(scu_non_secure_access_control, private_timers_for_cpu2, 6);
|
|
||||||
register_bit!(scu_non_secure_access_control, private_timers_for_cpu1, 5);
|
|
||||||
register_bit!(scu_non_secure_access_control, private_timers_for_cpu0, 4);
|
|
||||||
register_bit!(scu_non_secure_access_control, component_access_for_cpu3, 3);
|
|
||||||
register_bit!(scu_non_secure_access_control, component_access_for_cpu2, 2);
|
|
||||||
register_bit!(scu_non_secure_access_control, component_access_for_cpu1, 1);
|
|
||||||
register_bit!(scu_non_secure_access_control, component_access_for_cpu0, 0);
|
|
||||||
|
|
||||||
register!(iccicr, ICCICR, RW, u32);
|
|
||||||
register_bit!(iccicr, sbpr, 4);
|
|
||||||
register_bit!(iccicr, fiq_en, 3);
|
|
||||||
register_bit!(iccicr, ack_ctl, 2);
|
|
||||||
register_bit!(iccicr, enable_ns, 1);
|
|
||||||
register_bit!(iccicr, enable_s, 0);
|
|
||||||
|
|
||||||
register!(iccpmr, ICCPMR, RW, u32);
|
|
||||||
register_bits!(iccpmr, priority, u8, 0, 7);
|
|
||||||
|
|
||||||
register!(iccbpr, ICCBPR, RW, u32);
|
|
||||||
register_bits!(iccbpr, binary_point, u8, 0, 2);
|
|
||||||
|
|
||||||
register!(icciar, ICCIAR, RW, u32);
|
|
||||||
register_bits!(icciar, cpuid, u8, 10, 12);
|
|
||||||
register_bits!(icciar, ackintid, u32, 0, 9);
|
|
||||||
|
|
||||||
register!(icceoir, ICCEOIR, RW, u32);
|
|
||||||
register_bits!(icceoir, cpuid, u8, 10, 12);
|
|
||||||
register_bits!(icceoir, eoiintid, u32, 0, 9);
|
|
||||||
|
|
||||||
register!(iccrpr, ICCRPR, RW, u32);
|
|
||||||
register_bits!(iccrpr, priority, u8, 0, 7);
|
|
||||||
|
|
||||||
register!(icchpir, ICCHPIR, RW, u32);
|
|
||||||
register_bits!(icchpir, cpuid, u8, 10, 12);
|
|
||||||
register_bits!(icchpir, pendintid, u32, 0, 9);
|
|
||||||
|
|
||||||
register!(iccabpr, ICCABPR, RW, u32);
|
|
||||||
register_bits!(iccabpr, binary_point, u8, 0, 2);
|
|
||||||
|
|
||||||
register!(iccidr, ICCIDR, RO, u32);
|
|
||||||
register_bits!(iccidr, part_number, u32, 20, 31);
|
|
||||||
register_bits!(iccidr, architecture_version, u8, 16, 19);
|
|
||||||
register_bits!(iccidr, revision_number, u8, 12, 15);
|
|
||||||
register_bits!(iccidr, implementer, u32, 0, 11);
|
|
||||||
|
|
||||||
register!(global_timer_control, GlobalTimerControl, RW, u32);
|
register!(global_timer_control, GlobalTimerControl, RW, u32);
|
||||||
register_bits!(global_timer_control, prescaler, u8, 8, 15);
|
register_bits!(global_timer_control, prescaler, u8, 8, 15);
|
||||||
|
@ -264,58 +97,3 @@ register_bit!(global_timer_control, auto_increment_mode, 3);
|
||||||
register_bit!(global_timer_control, irq_enable, 2);
|
register_bit!(global_timer_control, irq_enable, 2);
|
||||||
register_bit!(global_timer_control, comp_enablea, 1);
|
register_bit!(global_timer_control, comp_enablea, 1);
|
||||||
register_bit!(global_timer_control, timer_enable, 0);
|
register_bit!(global_timer_control, timer_enable, 0);
|
||||||
|
|
||||||
register!(global_timer_interrupt_status, GlobalTimerInterruptStatusRegister, RW, u32);
|
|
||||||
register_bit!(global_timer_interrupt_status, event_flag, 0);
|
|
||||||
|
|
||||||
register!(private_timer_control, PrivateTimerControlRegister, RW, u32);
|
|
||||||
register_bits!(private_timer_control, sbzp, u32, 16, 31);
|
|
||||||
register_bits!(private_timer_control, prescaler, u8, 8, 15);
|
|
||||||
register_bits!(private_timer_control, unk_sbzp, u8, 3, 7);
|
|
||||||
register_bit!(private_timer_control, irq_enable, 2);
|
|
||||||
register_bit!(private_timer_control, auto_reload, 1);
|
|
||||||
register_bit!(private_timer_control, timer_enable, 0);
|
|
||||||
|
|
||||||
register!(private_timer_interrupt_status, PrivateTimerInterruptStatusRegister, RW, u32);
|
|
||||||
register_bits!(private_timer_interrupt_status, unk_sbzp, u32, 1, 31);
|
|
||||||
|
|
||||||
register!(watchdog_control, WatchdogControlRegister, RW, u32);
|
|
||||||
register_bits!(watchdog_control, prescaler, u8, 8, 15);
|
|
||||||
register_bit!(watchdog_control, watchdog_mode, 3);
|
|
||||||
register_bit!(watchdog_control, it_enable, 2);
|
|
||||||
register_bit!(watchdog_control, auto_reload, 1);
|
|
||||||
register_bit!(watchdog_control, watchdog_enable, 0);
|
|
||||||
|
|
||||||
register!(watchdog_interrupt_status, WatchdogInterruptStatusRegister, RW, u32);
|
|
||||||
register_bit!(watchdog_interrupt_status, event_flag, 0);
|
|
||||||
|
|
||||||
register!(watchdog_reset_status, WatchdogResetStatusRegister, RW, u32);
|
|
||||||
register_bit!(watchdog_reset_status, reset_flag, 0);
|
|
||||||
|
|
||||||
register!(icddcr, ICDDCR, RW, u32);
|
|
||||||
register_bit!(icddcr, enable_non_secure, 1);
|
|
||||||
register_bit!(icddcr, enable_secure, 0);
|
|
||||||
|
|
||||||
register!(icdictr, ICDICTR, RO, u32);
|
|
||||||
register_bits!(icdictr, lspi, u8, 11, 15);
|
|
||||||
register_bit!(icdictr, security_extn, 10);
|
|
||||||
register_bits!(icdictr, sbz, u8, 8, 9);
|
|
||||||
register_bits!(icdictr, cpu_number, u8, 5, 7);
|
|
||||||
register_bits!(icdictr, it_lines_number, u8, 0, 4);
|
|
||||||
|
|
||||||
register!(icdiidr, ICDIIDR, RO, u32);
|
|
||||||
register_bits!(icdiidr, implementation_version, u8, 24, 31);
|
|
||||||
register_bits!(icdiidr, revision_number, u32, 12, 23);
|
|
||||||
register_bits!(icdiidr, implementer, u32, 0, 11);
|
|
||||||
|
|
||||||
register!(ppi_status, PpiStatus, RO, u32);
|
|
||||||
register_bits!(ppi_status, ppi_status, u8, 11, 15);
|
|
||||||
register_bits!(ppi_status, sbz, u32, 0, 10);
|
|
||||||
|
|
||||||
register!(icdsgir, ICDSGIR, RW, u32);
|
|
||||||
register_bits!(icdsgir, target_list_filter, u8, 24, 25);
|
|
||||||
register_bits!(icdsgir, cpu_target_list, u8, 16, 23);
|
|
||||||
register_bit!(icdsgir, satt, 15);
|
|
||||||
register_bits!(icdsgir, sbz, u32, 4, 14);
|
|
||||||
register_bits!(icdsgir, sgiintid, u8, 0, 3);
|
|
||||||
|
|
||||||
|
|
|
@ -1,108 +0,0 @@
|
||||||
#![cfg(feature = "target_zc706")]
|
|
||||||
|
|
||||||
use crate::println;
|
|
||||||
|
|
||||||
mod zc706;
|
|
||||||
// mod cora_z7_10;
|
|
||||||
|
|
||||||
#[cfg(feature = "target_zc706")]
|
|
||||||
use zc706 as target;
|
|
||||||
// #[cfg(feature = "target_cora_z7_10")]
|
|
||||||
// use cora_z7_10 as target;
|
|
||||||
|
|
||||||
pub fn report_differences() {
|
|
||||||
for (i, op) in target::INIT_DATA.iter().enumerate() {
|
|
||||||
let address = op.address();
|
|
||||||
let overwritten_later = target::INIT_DATA[(i + 1)..].iter()
|
|
||||||
.any(|later_op| later_op.address() == address);
|
|
||||||
|
|
||||||
if !overwritten_later {
|
|
||||||
op.report_difference();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn apply() {
|
|
||||||
for op in target::INIT_DATA {
|
|
||||||
op.apply();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub enum InitOp {
|
|
||||||
MaskWrite(usize, usize, usize),
|
|
||||||
MaskPoll(usize, usize),
|
|
||||||
MaskDelay(usize, usize),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl InitOp {
|
|
||||||
fn address(&self) -> usize {
|
|
||||||
match self {
|
|
||||||
InitOp::MaskWrite(address, _, _) => *address,
|
|
||||||
InitOp::MaskPoll(address, _) => *address,
|
|
||||||
InitOp::MaskDelay(address, _) => *address,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read(&self) -> usize {
|
|
||||||
unsafe { *(self.address() as *const usize) }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn difference(&self) -> Option<(usize, usize)> {
|
|
||||||
let expected = match self {
|
|
||||||
InitOp::MaskWrite(_, mask, expected) =>
|
|
||||||
Some((*mask, *expected)),
|
|
||||||
InitOp::MaskPoll(_, mask) =>
|
|
||||||
Some((*mask, *mask)),
|
|
||||||
_ => None,
|
|
||||||
};
|
|
||||||
match expected {
|
|
||||||
Some((mask, expected)) => {
|
|
||||||
let actual = self.read();
|
|
||||||
if actual & mask == expected {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some((actual & mask, expected))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None =>
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn report_difference(&self) {
|
|
||||||
if let Some((actual, expected)) = self.difference() {
|
|
||||||
println!(
|
|
||||||
"Register {:08X} is {:08X}&={:08X} != {:08X} expected",
|
|
||||||
self.address(),
|
|
||||||
self.read(),
|
|
||||||
actual,
|
|
||||||
expected
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn apply(&self) {
|
|
||||||
let reg = self.address() as *mut usize;
|
|
||||||
println!("apply {:?}", self);
|
|
||||||
match self {
|
|
||||||
InitOp::MaskWrite(_, mask, val) =>
|
|
||||||
unsafe {
|
|
||||||
*reg = (val & mask) | (*reg & !mask);
|
|
||||||
},
|
|
||||||
InitOp::MaskPoll(_, mask) =>
|
|
||||||
while unsafe { *reg } & mask == 0 {},
|
|
||||||
InitOp::MaskDelay(_, mask) => {
|
|
||||||
let delay = get_number_of_cycles_for_delay(*mask);
|
|
||||||
while unsafe { *reg } < delay {
|
|
||||||
println!("W");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_number_of_cycles_for_delay(delay: usize) -> usize {
|
|
||||||
const APU_FREQ: usize = 666666687;
|
|
||||||
APU_FREQ * delay/ (2 * 1000)
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,6 +1,6 @@
|
||||||
/// ADMA library
|
/// ADMA library
|
||||||
use core::mem::MaybeUninit;
|
use core::mem::MaybeUninit;
|
||||||
use super::Sdio;
|
use super::SDIO;
|
||||||
use libcortex_a9::cache;
|
use libcortex_a9::cache;
|
||||||
use libregister::{
|
use libregister::{
|
||||||
register, register_bit,
|
register, register_bit,
|
||||||
|
@ -32,7 +32,7 @@ impl Adma2DescTable {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Initialize the table and setup `adma_system_address`
|
/// Initialize the table and setup `adma_system_address`
|
||||||
pub fn setup(&mut self, sdio: &mut Sdio, blk_cnt: u32, buffer: &[u8]) {
|
pub fn setup(&mut self, sdio: &mut SDIO, blk_cnt: u32, buffer: &[u8]) {
|
||||||
let descr_table = &mut self.0;
|
let descr_table = &mut self.0;
|
||||||
let blk_size = sdio
|
let blk_size = sdio
|
||||||
.regs
|
.regs
|
||||||
|
|
|
@ -12,9 +12,9 @@ use log::{trace, debug};
|
||||||
use nb;
|
use nb;
|
||||||
|
|
||||||
/// Basic SDIO Struct with common low-level functions.
|
/// Basic SDIO Struct with common low-level functions.
|
||||||
pub struct Sdio {
|
pub struct SDIO {
|
||||||
regs: &'static mut regs::RegisterBlock,
|
regs: &'static mut regs::RegisterBlock,
|
||||||
count_down: super::timer::global::CountDown<Milliseconds>,
|
count_down: super::timer::global::CountDown,
|
||||||
input_clk_hz: u32,
|
input_clk_hz: u32,
|
||||||
card_type: CardType,
|
card_type: CardType,
|
||||||
card_detect: bool,
|
card_detect: bool,
|
||||||
|
@ -48,7 +48,7 @@ pub enum CardType {
|
||||||
CardMmc,
|
CardMmc,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Sdio {
|
impl SDIO {
|
||||||
/// Initialize SDIO0
|
/// Initialize SDIO0
|
||||||
/// card_detect means if we would use the card detect pin,
|
/// card_detect means if we would use the card detect pin,
|
||||||
/// false to disable card detection (assume there is card inserted)
|
/// false to disable card detection (assume there is card inserted)
|
||||||
|
@ -116,24 +116,12 @@ impl Sdio {
|
||||||
.speed(true),
|
.speed(true),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
// redpitaya card detect pin
|
|
||||||
#[cfg(feature = "target_redpitaya")]
|
|
||||||
{
|
|
||||||
unsafe {
|
|
||||||
slcr.sd0_wp_cd_sel.write(46 << 16);
|
|
||||||
}
|
|
||||||
slcr.mio_pin_46.write(
|
|
||||||
slcr::MioPin46::zeroed()
|
|
||||||
.io_type(slcr::IoBufferType::Lvcmos25)
|
|
||||||
.speed(true),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
slcr.sdio_rst_ctrl.reset_sdio0();
|
slcr.sdio_rst_ctrl.reset_sdio0();
|
||||||
slcr.aper_clk_ctrl.enable_sdio0();
|
slcr.aper_clk_ctrl.enable_sdio0();
|
||||||
slcr.sdio_clk_ctrl.enable_sdio0();
|
slcr.sdio_clk_ctrl.enable_sdio0();
|
||||||
});
|
});
|
||||||
let clocks = Clocks::get();
|
let clocks = Clocks::get();
|
||||||
let mut self_ = Sdio {
|
let mut self_ = SDIO {
|
||||||
regs: regs::RegisterBlock::sdio0(),
|
regs: regs::RegisterBlock::sdio0(),
|
||||||
count_down: unsafe { super::timer::GlobalTimer::get() }.countdown(),
|
count_down: unsafe { super::timer::GlobalTimer::get() }.countdown(),
|
||||||
input_clk_hz: clocks.sdio_ref_clk(),
|
input_clk_hz: clocks.sdio_ref_clk(),
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use super::{adma::Adma2DescTable, cmd, CardType, CmdTransferError, Sdio};
|
use super::{adma::Adma2DescTable, cmd, CardType, CmdTransferError, SDIO};
|
||||||
use libcortex_a9::cache;
|
use libcortex_a9::cache;
|
||||||
use libregister::{RegisterR, RegisterRW, RegisterW};
|
use libregister::{RegisterR, RegisterRW, RegisterW};
|
||||||
use log::{trace, debug};
|
use log::{trace, debug};
|
||||||
|
@ -37,7 +37,7 @@ enum CardVersion {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct SdCard {
|
pub struct SdCard {
|
||||||
sdio: Sdio,
|
sdio: SDIO,
|
||||||
adma2_desc_table: Adma2DescTable,
|
adma2_desc_table: Adma2DescTable,
|
||||||
card_version: CardVersion,
|
card_version: CardVersion,
|
||||||
hcs: bool,
|
hcs: bool,
|
||||||
|
@ -171,8 +171,8 @@ impl SdCard {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert Sdio into SdCard struct, error if no card inserted or it is not an SD card.
|
/// Convert SDIO into SdCard struct, error if no card inserted or it is not an SD card.
|
||||||
pub fn from_sdio(mut sdio: Sdio) -> Result<Self, CardInitializationError> {
|
pub fn from_sdio(mut sdio: SDIO) -> Result<Self, CardInitializationError> {
|
||||||
match sdio.identify_card()? {
|
match sdio.identify_card()? {
|
||||||
CardType::CardSd => (),
|
CardType::CardSd => (),
|
||||||
_ => return Err(CardInitializationError::NoCardInserted),
|
_ => return Err(CardInitializationError::NoCardInserted),
|
||||||
|
@ -192,8 +192,8 @@ impl SdCard {
|
||||||
Ok(_self)
|
Ok(_self)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert SdCard struct back to Sdio struct.
|
/// Convert SdCard struct back to SDIO struct.
|
||||||
pub fn to_sdio(self) -> Sdio {
|
pub fn to_sdio(self) -> SDIO {
|
||||||
self.sdio
|
self.sdio
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -102,19 +102,19 @@ pub struct RegisterBlock {
|
||||||
pub dbg_clk_ctrl: RW<u32>,
|
pub dbg_clk_ctrl: RW<u32>,
|
||||||
pub pcap_clk_ctrl: RW<u32>,
|
pub pcap_clk_ctrl: RW<u32>,
|
||||||
pub topsw_clk_ctrl: RW<u32>,
|
pub topsw_clk_ctrl: RW<u32>,
|
||||||
pub fpga0_clk_ctrl: Fpga0ClkCtrl,
|
pub fpga0_clk_ctrl: RW<u32>,
|
||||||
pub fpga0_thr_ctrl: RW<u32>,
|
pub fpga0_thr_ctrl: RW<u32>,
|
||||||
pub fpga0_thr_cnt: RW<u32>,
|
pub fpga0_thr_cnt: RW<u32>,
|
||||||
pub fpga0_thr_sta: RO<u32>,
|
pub fpga0_thr_sta: RO<u32>,
|
||||||
pub fpga1_clk_ctrl: Fpga1ClkCtrl,
|
pub fpga1_clk_ctrl: RW<u32>,
|
||||||
pub fpga1_thr_ctrl: RW<u32>,
|
pub fpga1_thr_ctrl: RW<u32>,
|
||||||
pub fpga1_thr_cnt: RW<u32>,
|
pub fpga1_thr_cnt: RW<u32>,
|
||||||
pub fpga1_thr_sta: RO<u32>,
|
pub fpga1_thr_sta: RO<u32>,
|
||||||
pub fpga2_clk_ctrl: Fpga2ClkCtrl,
|
pub fpga2_clk_ctrl: RW<u32>,
|
||||||
pub fpga2_thr_ctrl: RW<u32>,
|
pub fpga2_thr_ctrl: RW<u32>,
|
||||||
pub fpga2_thr_cnt: RW<u32>,
|
pub fpga2_thr_cnt: RW<u32>,
|
||||||
pub fpga2_thr_sta: RO<u32>,
|
pub fpga2_thr_sta: RO<u32>,
|
||||||
pub fpga3_clk_ctrl: Fpga3ClkCtrl,
|
pub fpga3_clk_ctrl: RW<u32>,
|
||||||
pub fpga3_thr_ctrl: RW<u32>,
|
pub fpga3_thr_ctrl: RW<u32>,
|
||||||
pub fpga3_thr_cnt: RW<u32>,
|
pub fpga3_thr_cnt: RW<u32>,
|
||||||
pub fpga3_thr_sta: RO<u32>,
|
pub fpga3_thr_sta: RO<u32>,
|
||||||
|
@ -132,7 +132,7 @@ pub struct RegisterBlock {
|
||||||
pub can_rst_ctrl: RW<u32>,
|
pub can_rst_ctrl: RW<u32>,
|
||||||
pub i2c_rst_ctrl: RW<u32>,
|
pub i2c_rst_ctrl: RW<u32>,
|
||||||
pub uart_rst_ctrl: UartRstCtrl,
|
pub uart_rst_ctrl: UartRstCtrl,
|
||||||
pub gpio_rst_ctrl: GpioRstCtrl,
|
pub gpio_rst_ctrl: RW<u32>,
|
||||||
pub lqspi_rst_ctrl: LqspiRstCtrl,
|
pub lqspi_rst_ctrl: LqspiRstCtrl,
|
||||||
pub smc_rst_ctrl: RW<u32>,
|
pub smc_rst_ctrl: RW<u32>,
|
||||||
pub ocm_rst_ctrl: RW<u32>,
|
pub ocm_rst_ctrl: RW<u32>,
|
||||||
|
@ -229,15 +229,18 @@ pub struct RegisterBlock {
|
||||||
pub lvl_shftr_en: LvlShftr,
|
pub lvl_shftr_en: LvlShftr,
|
||||||
reserved18: [u32; 3],
|
reserved18: [u32; 3],
|
||||||
pub ocm_cfg: RW<u32>,
|
pub ocm_cfg: RW<u32>,
|
||||||
reserved19: [u32; 123],
|
reserved19: [u32; 66],
|
||||||
|
/// barely documented unnamed register to prepare L2 cache setup
|
||||||
|
pub unnamed1: RW<u32>,
|
||||||
|
reserved120: [u32; 56],
|
||||||
pub gpiob_ctrl: GpiobCtrl,
|
pub gpiob_ctrl: GpiobCtrl,
|
||||||
pub gpiob_cfg_cmos18: RW<u32>,
|
pub gpiob_cfg_cmos18: RW<u32>,
|
||||||
pub gpiob_cfg_cmos25: RW<u32>,
|
pub gpiob_cfg_cmos25: RW<u32>,
|
||||||
pub gpiob_cfg_cmos33: RW<u32>,
|
pub gpiob_cfg_cmos33: RW<u32>,
|
||||||
reserved20: [u32; 1],
|
reserved21: [u32; 1],
|
||||||
pub gpiob_cfg_hstl: RW<u32>,
|
pub gpiob_cfg_hstl: RW<u32>,
|
||||||
pub gpiob_drvr_bias_ctrl: RW<u32>,
|
pub gpiob_drvr_bias_ctrl: RW<u32>,
|
||||||
reserved21: [u32; 9],
|
reserved22: [u32; 9],
|
||||||
pub ddriob_addr0: DdriobConfig,
|
pub ddriob_addr0: DdriobConfig,
|
||||||
pub ddriob_addr1: DdriobConfig,
|
pub ddriob_addr1: DdriobConfig,
|
||||||
pub ddriob_data0: DdriobConfig,
|
pub ddriob_data0: DdriobConfig,
|
||||||
|
@ -253,18 +256,26 @@ pub struct RegisterBlock {
|
||||||
pub ddriob_dci_ctrl: DdriobDciCtrl,
|
pub ddriob_dci_ctrl: DdriobDciCtrl,
|
||||||
pub ddriob_dci_status: DdriobDciStatus,
|
pub ddriob_dci_status: DdriobDciStatus,
|
||||||
}
|
}
|
||||||
register_at!(RegisterBlock, 0xF8000000, slcr);
|
register_at!(RegisterBlock, 0xF8000000, new);
|
||||||
|
|
||||||
impl RegisterBlock {
|
impl RegisterBlock {
|
||||||
/// Required to modify any sclr register
|
/// Required to modify any sclr register
|
||||||
pub fn unlocked<F: FnMut(&mut Self) -> R, R>(mut f: F) -> R {
|
pub fn unlocked<F: FnMut(&mut Self) -> R, R>(mut f: F) -> R {
|
||||||
let mut self_ = Self::slcr();
|
let mut self_ = Self::new();
|
||||||
self_.slcr_unlock.unlock();
|
self_.slcr_unlock.unlock();
|
||||||
let r = f(&mut self_);
|
let r = f(&mut self_);
|
||||||
self_.slcr_lock.lock();
|
self_.slcr_lock.lock();
|
||||||
r
|
r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Perform a soft reset
|
||||||
|
pub fn soft_reset(&mut self) {
|
||||||
|
self.pss_rst_ctrl.write(
|
||||||
|
PssRstCtrl::zeroed()
|
||||||
|
.soft_rst(true)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn init_preload_fpga(&mut self) {
|
pub fn init_preload_fpga(&mut self) {
|
||||||
// Assert FPGA top level output resets
|
// Assert FPGA top level output resets
|
||||||
self.fpga_rst_ctrl.write(
|
self.fpga_rst_ctrl.write(
|
||||||
|
@ -531,20 +542,6 @@ impl UartRstCtrl {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
register!(gpio_rst_ctrl, GpioRstCtrl, RW, u32);
|
|
||||||
register_bit!(gpio_rst_ctrl, gpio_cpu1x_rst, 0);
|
|
||||||
register_at!(GpioRstCtrl, 0xF800022C, new);
|
|
||||||
impl GpioRstCtrl {
|
|
||||||
pub fn reset_gpio(&mut self) {
|
|
||||||
self.modify(|_, w|
|
|
||||||
w.gpio_cpu1x_rst(true)
|
|
||||||
);
|
|
||||||
self.modify(|_, w|
|
|
||||||
w.gpio_cpu1x_rst(false)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
register!(lqspi_clk_ctrl, LqspiClkCtrl, RW, u32);
|
register!(lqspi_clk_ctrl, LqspiClkCtrl, RW, u32);
|
||||||
register_bit!(lqspi_clk_ctrl, clkact, 0);
|
register_bit!(lqspi_clk_ctrl, clkact, 0);
|
||||||
register_bits_typed!(lqspi_clk_ctrl, src_sel, u8, PllSource, 4, 5);
|
register_bits_typed!(lqspi_clk_ctrl, src_sel, u8, PllSource, 4, 5);
|
||||||
|
@ -554,26 +551,6 @@ register!(lqspi_rst_ctrl, LqspiRstCtrl, RW, u32);
|
||||||
register_bit!(lqspi_rst_ctrl, ref_rst, 1);
|
register_bit!(lqspi_rst_ctrl, ref_rst, 1);
|
||||||
register_bit!(lqspi_rst_ctrl, cpu1x_rst, 0);
|
register_bit!(lqspi_rst_ctrl, cpu1x_rst, 0);
|
||||||
|
|
||||||
register!(fpga0_clk_ctrl, Fpga0ClkCtrl, RW, u32);
|
|
||||||
register_bits!(fpga0_clk_ctrl, divisor1, u8, 20, 25);
|
|
||||||
register_bits!(fpga0_clk_ctrl, divisor0, u8, 8, 13);
|
|
||||||
register_bits_typed!(fpga0_clk_ctrl, src_sel, u8, PllSource, 4, 5);
|
|
||||||
|
|
||||||
register!(fpga1_clk_ctrl, Fpga1ClkCtrl, RW, u32);
|
|
||||||
register_bits!(fpga1_clk_ctrl, divisor1, u8, 20, 25);
|
|
||||||
register_bits!(fpga1_clk_ctrl, divisor0, u8, 8, 13);
|
|
||||||
register_bits_typed!(fpga1_clk_ctrl, src_sel, u8, PllSource, 4, 5);
|
|
||||||
|
|
||||||
register!(fpga2_clk_ctrl, Fpga2ClkCtrl, RW, u32);
|
|
||||||
register_bits!(fpga2_clk_ctrl, divisor1, u8, 20, 25);
|
|
||||||
register_bits!(fpga2_clk_ctrl, divisor0, u8, 8, 13);
|
|
||||||
register_bits_typed!(fpga2_clk_ctrl, src_sel, u8, PllSource, 4, 5);
|
|
||||||
|
|
||||||
register!(fpga3_clk_ctrl, Fpga3ClkCtrl, RW, u32);
|
|
||||||
register_bits!(fpga3_clk_ctrl, divisor1, u8, 20, 25);
|
|
||||||
register_bits!(fpga3_clk_ctrl, divisor0, u8, 8, 13);
|
|
||||||
register_bits_typed!(fpga3_clk_ctrl, src_sel, u8, PllSource, 4, 5);
|
|
||||||
|
|
||||||
register!(fpga_rst_ctrl, FpgaRstCtrl, RW, u32);
|
register!(fpga_rst_ctrl, FpgaRstCtrl, RW, u32);
|
||||||
register_bit!(fpga_rst_ctrl, fpga0_out_rst, 0);
|
register_bit!(fpga_rst_ctrl, fpga0_out_rst, 0);
|
||||||
register_bit!(fpga_rst_ctrl, fpga1_out_rst, 1);
|
register_bit!(fpga_rst_ctrl, fpga1_out_rst, 1);
|
||||||
|
@ -590,19 +567,16 @@ register_bit!(a9_cpu_rst_ctrl, a9_rst0, 0);
|
||||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
pub enum BootModePins {
|
pub enum BootModePins {
|
||||||
// CAUTION!
|
|
||||||
// The BOOT_MODE bits table 6-4 in UG585 are *out of order*.
|
|
||||||
Jtag = 0b000,
|
Jtag = 0b000,
|
||||||
Nor = 0b010,
|
Nor = 0b001,
|
||||||
Nand = 0b100,
|
Nand = 0b010,
|
||||||
QuadSpi = 0b001,
|
QuadSpi = 0b100,
|
||||||
SdCard = 0b101,
|
SdCard = 0b110,
|
||||||
}
|
}
|
||||||
|
|
||||||
register!(boot_mode, BootMode, RO, u32);
|
register!(boot_mode, BootMode, RO, u32);
|
||||||
register_bit!(boot_mode, pll_bypass, 4);
|
register_bit!(boot_mode, pll_bypass, 4);
|
||||||
register_bit!(boot_mode, jtag_routing, 3);
|
register_bits_typed!(boot_mode, boot_mode_pins, u8, BootModePins, 0, 3);
|
||||||
register_bits_typed!(boot_mode, boot_mode_pins, u8, BootModePins, 0, 2);
|
|
||||||
|
|
||||||
register!(pss_rst_ctrl, PssRstCtrl, RW, u32);
|
register!(pss_rst_ctrl, PssRstCtrl, RW, u32);
|
||||||
register_bit!(pss_rst_ctrl, soft_rst, 1);
|
register_bit!(pss_rst_ctrl, soft_rst, 1);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use core::ops::{Deref, DerefMut};
|
use core::ops::{Deref, DerefMut};
|
||||||
use libcortex_a9::{asm, mutex::{Mutex, MutexGuard}};
|
use libcortex_a9::mutex::{Mutex, MutexGuard};
|
||||||
use crate::uart::Uart;
|
use crate::uart::Uart;
|
||||||
|
|
||||||
const UART_RATE: u32 = 115_200;
|
const UART_RATE: u32 = 115_200;
|
||||||
|
@ -10,15 +10,7 @@ pub fn get_uart<'a>() -> MutexGuard<'a, LazyUart> {
|
||||||
unsafe { UART.lock() }
|
unsafe { UART.lock() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Deinitialize so that the Uart will be reinitialized on next
|
|
||||||
/// output.
|
|
||||||
///
|
|
||||||
/// Delays so that an outstanding transmission can finish.
|
|
||||||
pub fn drop_uart() {
|
pub fn drop_uart() {
|
||||||
for _ in 0..1_000_000 {
|
|
||||||
asm::nop();
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe { UART = Mutex::new(LazyUart::Uninitialized); }
|
unsafe { UART = Mutex::new(LazyUart::Uninitialized); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,10 +37,7 @@ impl DerefMut for LazyUart {
|
||||||
fn deref_mut(&mut self) -> &mut Uart {
|
fn deref_mut(&mut self) -> &mut Uart {
|
||||||
match self {
|
match self {
|
||||||
LazyUart::Uninitialized => {
|
LazyUart::Uninitialized => {
|
||||||
#[cfg(any(feature = "target_cora_z7_10", feature = "target_redpitaya"))]
|
let uart = Uart::serial(UART_RATE);
|
||||||
let uart = Uart::uart0(UART_RATE);
|
|
||||||
#[cfg(feature = "target_zc706")]
|
|
||||||
let uart = Uart::uart1(UART_RATE);
|
|
||||||
*self = LazyUart::Initialized(uart);
|
*self = LazyUart::Initialized(uart);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,18 +8,3 @@ impl core::ops::Add for Milliseconds {
|
||||||
Milliseconds(self.0 + rhs.0)
|
Milliseconds(self.0 + rhs.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
|
|
||||||
pub struct Microseconds(pub u64);
|
|
||||||
|
|
||||||
impl core::ops::Add for Microseconds {
|
|
||||||
type Output = Self;
|
|
||||||
|
|
||||||
fn add(self, rhs: Self) -> Self::Output {
|
|
||||||
Microseconds(self.0 + rhs.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait TimeSource<U> {
|
|
||||||
fn now(&self) -> U;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
use core::ops::Add;
|
|
||||||
use void::Void;
|
use void::Void;
|
||||||
use libregister::{RegisterR, RegisterW};
|
use libregister::{RegisterR, RegisterW};
|
||||||
use crate::{
|
use crate::{
|
||||||
clocks::Clocks,
|
clocks::Clocks,
|
||||||
mpcore,
|
mpcore,
|
||||||
time::{Milliseconds, Microseconds, TimeSource},
|
time::Milliseconds,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// "uptime"
|
/// "uptime"
|
||||||
|
@ -16,13 +15,13 @@ pub struct GlobalTimer {
|
||||||
impl GlobalTimer {
|
impl GlobalTimer {
|
||||||
/// Get the potentially uninitialized timer
|
/// Get the potentially uninitialized timer
|
||||||
pub unsafe fn get() -> GlobalTimer {
|
pub unsafe fn get() -> GlobalTimer {
|
||||||
let regs = mpcore::RegisterBlock::mpcore();
|
let regs = mpcore::RegisterBlock::new();
|
||||||
GlobalTimer { regs }
|
GlobalTimer { regs }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the timer with a reset
|
/// Get the timer with a reset
|
||||||
pub fn start() -> GlobalTimer {
|
pub fn start() -> GlobalTimer {
|
||||||
let mut regs = mpcore::RegisterBlock::mpcore();
|
let mut regs = mpcore::RegisterBlock::new();
|
||||||
Self::reset(&mut regs);
|
Self::reset(&mut regs);
|
||||||
GlobalTimer { regs }
|
GlobalTimer { regs }
|
||||||
}
|
}
|
||||||
|
@ -80,91 +79,41 @@ impl GlobalTimer {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// read with high precision
|
/// read with high precision
|
||||||
pub fn get_us(&self) -> Microseconds {
|
pub fn get_us(&self) -> u64 {
|
||||||
let prescaler = self.regs.global_timer_control.read().prescaler() as u64;
|
let prescaler = self.regs.global_timer_control.read().prescaler() as u64;
|
||||||
let clocks = Clocks::get();
|
let clocks = Clocks::get();
|
||||||
|
|
||||||
Microseconds(1_000_000 * self.get_counter() * (prescaler + 1) / clocks.cpu_3x2x() as u64)
|
1_000_000 * self.get_counter() * (prescaler + 1) / clocks.cpu_3x2x() as u64
|
||||||
}
|
}
|
||||||
|
|
||||||
/// return a handle that has implements
|
/// return a handle that has implements
|
||||||
/// `embedded_hal::timer::CountDown`
|
/// `embedded_hal::timer::CountDown`
|
||||||
pub fn countdown<U>(&self) -> CountDown<U>
|
pub fn countdown(&self) -> CountDown {
|
||||||
where
|
|
||||||
Self: TimeSource<U>,
|
|
||||||
{
|
|
||||||
CountDown {
|
CountDown {
|
||||||
timer: self.clone(),
|
timer: self.clone(),
|
||||||
timeout: self.now(),
|
timeout: Milliseconds(0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TimeSource<Milliseconds> for GlobalTimer {
|
|
||||||
fn now(&self) -> Milliseconds {
|
|
||||||
self.get_time()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TimeSource<Microseconds> for GlobalTimer {
|
|
||||||
fn now(&self) -> Microseconds {
|
|
||||||
self.get_us()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct CountDown<U> {
|
pub struct CountDown {
|
||||||
timer: GlobalTimer,
|
timer: GlobalTimer,
|
||||||
timeout: U,
|
timeout: Milliseconds,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// embedded-hal async API
|
impl embedded_hal::timer::CountDown for CountDown {
|
||||||
impl<U: Add<Output=U> + PartialOrd> embedded_hal::timer::CountDown for CountDown<U>
|
type Time = Milliseconds;
|
||||||
where
|
|
||||||
GlobalTimer: TimeSource<U>,
|
|
||||||
{
|
|
||||||
type Time = U;
|
|
||||||
|
|
||||||
fn start<T: Into<Self::Time>>(&mut self, count: T) {
|
fn start<T: Into<Self::Time>>(&mut self, count: T) {
|
||||||
self.timeout = self.timer.now() + count.into();
|
self.timeout = self.timer.get_time() + count.into();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn wait(&mut self) -> nb::Result<(), Void> {
|
fn wait(&mut self) -> nb::Result<(), Void> {
|
||||||
if self.timer.now() <= self.timeout {
|
if self.timer.get_time() < self.timeout {
|
||||||
Err(nb::Error::WouldBlock)
|
Err(nb::Error::WouldBlock)
|
||||||
} else {
|
} else {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<U: PartialOrd> CountDown<U>
|
|
||||||
where
|
|
||||||
GlobalTimer: TimeSource<U>,
|
|
||||||
{
|
|
||||||
pub fn waiting(&self) -> bool {
|
|
||||||
self.timer.now() <= self.timeout
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// embedded-hal sync API
|
|
||||||
impl embedded_hal::blocking::delay::DelayMs<u64> for GlobalTimer {
|
|
||||||
fn delay_ms(&mut self, ms: u64) {
|
|
||||||
use embedded_hal::timer::CountDown;
|
|
||||||
|
|
||||||
let mut countdown = self.countdown::<Milliseconds>();
|
|
||||||
countdown.start(Milliseconds(ms));
|
|
||||||
nb::block!(countdown.wait()).unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// embedded-hal sync API
|
|
||||||
impl embedded_hal::blocking::delay::DelayUs<u64> for GlobalTimer {
|
|
||||||
fn delay_us(&mut self, us: u64) {
|
|
||||||
use embedded_hal::timer::CountDown;
|
|
||||||
|
|
||||||
let mut countdown = self.countdown::<Microseconds>();
|
|
||||||
countdown.start(Microseconds(us));
|
|
||||||
nb::block!(countdown.wait()).unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -13,41 +13,8 @@ pub struct Uart {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Uart {
|
impl Uart {
|
||||||
#[cfg(any(feature = "target_cora_z7_10", feature = "target_redpitaya"))]
|
|
||||||
pub fn uart0(baudrate: u32) -> Self {
|
|
||||||
slcr::RegisterBlock::unlocked(|slcr| {
|
|
||||||
// Route UART 0 RxD/TxD Signals to MIO Pins
|
|
||||||
// TX pin
|
|
||||||
slcr.mio_pin_15.write(
|
|
||||||
slcr::MioPin15::zeroed()
|
|
||||||
.l3_sel(0b111)
|
|
||||||
.io_type(slcr::IoBufferType::Lvcmos33)
|
|
||||||
.pullup(true)
|
|
||||||
);
|
|
||||||
// RX pin
|
|
||||||
slcr.mio_pin_14.write(
|
|
||||||
slcr::MioPin14::zeroed()
|
|
||||||
.tri_enable(true)
|
|
||||||
.l3_sel(0b111)
|
|
||||||
.io_type(slcr::IoBufferType::Lvcmos33)
|
|
||||||
.pullup(true)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
slcr::RegisterBlock::unlocked(|slcr| {
|
|
||||||
slcr.uart_rst_ctrl.reset_uart0();
|
|
||||||
slcr.aper_clk_ctrl.enable_uart0();
|
|
||||||
slcr.uart_clk_ctrl.enable_uart0();
|
|
||||||
});
|
|
||||||
let mut self_ = Uart {
|
|
||||||
regs: regs::RegisterBlock::uart0(),
|
|
||||||
};
|
|
||||||
self_.configure(baudrate);
|
|
||||||
self_
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "target_zc706")]
|
#[cfg(feature = "target_zc706")]
|
||||||
pub fn uart1(baudrate: u32) -> Self {
|
pub fn serial(baudrate: u32) -> Self {
|
||||||
slcr::RegisterBlock::unlocked(|slcr| {
|
slcr::RegisterBlock::unlocked(|slcr| {
|
||||||
// Route UART 1 RxD/TxD Signals to MIO Pins
|
// Route UART 1 RxD/TxD Signals to MIO Pins
|
||||||
// TX pin
|
// TX pin
|
||||||
|
@ -66,7 +33,46 @@ impl Uart {
|
||||||
.pullup(true)
|
.pullup(true)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
Self::uart1(baudrate)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "target_cora_z7_10")]
|
||||||
|
pub fn serial(baudrate: u32) -> Self {
|
||||||
|
slcr::RegisterBlock::unlocked(|slcr| {
|
||||||
|
// Route UART 0 RxD/TxD Signals to MIO Pins
|
||||||
|
// TX pin
|
||||||
|
slcr.mio_pin_15.write(
|
||||||
|
slcr::MioPin15::zeroed()
|
||||||
|
.l3_sel(0b111)
|
||||||
|
.io_type(slcr::IoBufferType::Lvcmos33)
|
||||||
|
.pullup(true)
|
||||||
|
);
|
||||||
|
// RX pin
|
||||||
|
slcr.mio_pin_14.write(
|
||||||
|
slcr::MioPin14::zeroed()
|
||||||
|
.tri_enable(true)
|
||||||
|
.l3_sel(0b111)
|
||||||
|
.io_type(slcr::IoBufferType::Lvcmos33)
|
||||||
|
.pullup(true)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
Self::uart0(baudrate)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn uart0(baudrate: u32) -> Self {
|
||||||
|
slcr::RegisterBlock::unlocked(|slcr| {
|
||||||
|
slcr.uart_rst_ctrl.reset_uart0();
|
||||||
|
slcr.aper_clk_ctrl.enable_uart0();
|
||||||
|
slcr.uart_clk_ctrl.enable_uart0();
|
||||||
|
});
|
||||||
|
let mut self_ = Uart {
|
||||||
|
regs: regs::RegisterBlock::uart0(),
|
||||||
|
};
|
||||||
|
self_.configure(baudrate);
|
||||||
|
self_
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn uart1(baudrate: u32) -> Self {
|
||||||
slcr::RegisterBlock::unlocked(|slcr| {
|
slcr::RegisterBlock::unlocked(|slcr| {
|
||||||
slcr.uart_rst_ctrl.reset_uart1();
|
slcr.uart_rst_ctrl.reset_uart1();
|
||||||
slcr.aper_clk_ctrl.enable_uart1();
|
slcr.aper_clk_ctrl.enable_uart1();
|
||||||
|
|
|
@ -1,15 +0,0 @@
|
||||||
[package]
|
|
||||||
name = "libconfig"
|
|
||||||
version = "0.1.0"
|
|
||||||
authors = ["M-Labs"]
|
|
||||||
edition = "2018"
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
libboard_zynq = { path = "../libboard_zynq" }
|
|
||||||
core_io = { version = "0.1", features = ["collections"] }
|
|
||||||
fatfs = { version = "0.3", features = ["core_io"], default-features = false }
|
|
||||||
log = "0.4"
|
|
||||||
|
|
||||||
[features]
|
|
||||||
ipv6 = []
|
|
||||||
|
|
|
@ -1,181 +0,0 @@
|
||||||
use alloc::vec::Vec;
|
|
||||||
use core_io::{Error, Read, Seek, SeekFrom};
|
|
||||||
use libboard_zynq::devc;
|
|
||||||
use log::debug;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum BootgenLoadingError {
|
|
||||||
InvalidBootImageHeader,
|
|
||||||
MissingPartition,
|
|
||||||
EncryptedBitstream,
|
|
||||||
IoError(Error),
|
|
||||||
DevcError(devc::DevcError),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Error> for BootgenLoadingError {
|
|
||||||
fn from(error: Error) -> Self {
|
|
||||||
BootgenLoadingError::IoError(error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<devc::DevcError> for BootgenLoadingError {
|
|
||||||
fn from(error: devc::DevcError) -> Self {
|
|
||||||
BootgenLoadingError::DevcError(error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl core::fmt::Display for BootgenLoadingError {
|
|
||||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
|
||||||
use BootgenLoadingError::*;
|
|
||||||
match self {
|
|
||||||
InvalidBootImageHeader => write!(
|
|
||||||
f,
|
|
||||||
"Invalid boot image header. Check if the file is correct."
|
|
||||||
),
|
|
||||||
MissingPartition => write!(f, "Partition not found. Check your compile configuration."),
|
|
||||||
EncryptedBitstream => write!(f, "Encrypted bitstream is not supported."),
|
|
||||||
IoError(e) => write!(f, "Error while reading: {}", e),
|
|
||||||
DevcError(e) => write!(f, "PCAP interface error: {}", e),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[repr(C)]
|
|
||||||
struct PartitionHeader {
|
|
||||||
pub encrypted_length: u32,
|
|
||||||
pub unencrypted_length: u32,
|
|
||||||
pub word_length: u32,
|
|
||||||
pub dest_load_addr: u32,
|
|
||||||
pub dest_exec_addr: u32,
|
|
||||||
pub data_offset: u32,
|
|
||||||
pub attribute_bits: u32,
|
|
||||||
pub section_count: u32,
|
|
||||||
pub checksum_offset: u32,
|
|
||||||
pub header_offset: u32,
|
|
||||||
pub cert_offset: u32,
|
|
||||||
pub reserved: [u32; 4],
|
|
||||||
pub checksum: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Read a u32 word from the reader.
|
|
||||||
fn read_u32<Reader: Read>(reader: &mut Reader) -> Result<u32, BootgenLoadingError> {
|
|
||||||
let mut buffer: [u8; 4] = [0; 4];
|
|
||||||
reader.read_exact(&mut buffer)?;
|
|
||||||
let mut result: u32 = 0;
|
|
||||||
for i in 0..4 {
|
|
||||||
result |= (buffer[i] as u32) << (i * 8);
|
|
||||||
}
|
|
||||||
Ok(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Load PL partition header.
|
|
||||||
fn load_pl_header<File: Read + Seek>(
|
|
||||||
file: &mut File,
|
|
||||||
) -> Result<Option<PartitionHeader>, BootgenLoadingError> {
|
|
||||||
let mut buffer: [u8; 0x40] = [0; 0x40];
|
|
||||||
file.read_exact(&mut buffer)?;
|
|
||||||
let header = unsafe { core::mem::transmute::<_, PartitionHeader>(buffer) };
|
|
||||||
if header.attribute_bits & (2 << 4) != 0 {
|
|
||||||
Ok(Some(header))
|
|
||||||
} else {
|
|
||||||
Ok(None)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn load_ps_header<File: Read + Seek>(
|
|
||||||
file: &mut File,
|
|
||||||
) -> Result<Option<PartitionHeader>, BootgenLoadingError> {
|
|
||||||
let mut buffer: [u8; 0x40] = [0; 0x40];
|
|
||||||
file.read_exact(&mut buffer)?;
|
|
||||||
let header = unsafe { core::mem::transmute::<_, PartitionHeader>(buffer) };
|
|
||||||
if header.attribute_bits & (1 << 4) != 0 {
|
|
||||||
Ok(Some(header))
|
|
||||||
} else {
|
|
||||||
Ok(None)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Locate the partition from the image, and return the size (in bytes) of the partition if successful.
|
|
||||||
/// This function would seek the file to the location of the partition.
|
|
||||||
fn locate<
|
|
||||||
File: Read + Seek,
|
|
||||||
F: Fn(&mut File) -> Result<Option<PartitionHeader>, BootgenLoadingError>,
|
|
||||||
>(
|
|
||||||
file: &mut File,
|
|
||||||
f: F,
|
|
||||||
) -> Result<usize, BootgenLoadingError> {
|
|
||||||
file.seek(SeekFrom::Start(0))?;
|
|
||||||
const BOOT_HEADER_SIGN: u32 = 0x584C4E58;
|
|
||||||
// read boot header signature
|
|
||||||
file.seek(SeekFrom::Start(0x24))?;
|
|
||||||
if read_u32(file)? != BOOT_HEADER_SIGN {
|
|
||||||
return Err(BootgenLoadingError::InvalidBootImageHeader);
|
|
||||||
}
|
|
||||||
// find fsbl offset
|
|
||||||
file.seek(SeekFrom::Start(0x30))?;
|
|
||||||
// the length is in bytes, we have to convert it to words to compare with the partition offset
|
|
||||||
// later
|
|
||||||
let fsbl = read_u32(file)? / 4;
|
|
||||||
// read partition header offset
|
|
||||||
file.seek(SeekFrom::Start(0x9C))?;
|
|
||||||
let ptr = read_u32(file)?;
|
|
||||||
debug!("Partition header pointer = {:0X}", ptr);
|
|
||||||
file.seek(SeekFrom::Start(ptr as u64))?;
|
|
||||||
|
|
||||||
// at most 3 partition headers
|
|
||||||
for _ in 0..3 {
|
|
||||||
if let Some(header) = f(file)? {
|
|
||||||
let encrypted_length = header.encrypted_length;
|
|
||||||
let unencrypted_length = header.unencrypted_length;
|
|
||||||
debug!("Unencrypted length = {:0X}", unencrypted_length);
|
|
||||||
if encrypted_length != unencrypted_length {
|
|
||||||
return Err(BootgenLoadingError::EncryptedBitstream);
|
|
||||||
}
|
|
||||||
|
|
||||||
let start_addr = header.data_offset;
|
|
||||||
// skip fsbl
|
|
||||||
if start_addr == fsbl {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
debug!("Partition start address: {:0X}", start_addr);
|
|
||||||
file.seek(SeekFrom::Start(start_addr as u64 * 4))?;
|
|
||||||
|
|
||||||
return Ok(unencrypted_length as usize * 4);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(BootgenLoadingError::MissingPartition)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Load bitstream from bootgen file.
|
|
||||||
/// This function parses the file, locate the bitstream and load it through the PCAP driver.
|
|
||||||
/// It requires a large buffer, please enable the DDR RAM before using it.
|
|
||||||
pub fn load_bitstream<File: Read + Seek>(file: &mut File) -> Result<(), BootgenLoadingError> {
|
|
||||||
let size = locate(file, load_pl_header)?;
|
|
||||||
unsafe {
|
|
||||||
// align to 64 bytes
|
|
||||||
let ptr = alloc::alloc::alloc(alloc::alloc::Layout::from_size_align(size, 64).unwrap());
|
|
||||||
let buffer = core::slice::from_raw_parts_mut(ptr, size);
|
|
||||||
file.read_exact(buffer).map_err(|e| {
|
|
||||||
core::ptr::drop_in_place(ptr);
|
|
||||||
e
|
|
||||||
})?;
|
|
||||||
let mut devcfg = devc::DevC::new();
|
|
||||||
devcfg.enable();
|
|
||||||
devcfg.program(&buffer).map_err(|e| {
|
|
||||||
core::ptr::drop_in_place(ptr);
|
|
||||||
e
|
|
||||||
})?;
|
|
||||||
core::ptr::drop_in_place(ptr);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_runtime<File: Read + Seek>(file: &mut File) -> Result<Vec<u8>, BootgenLoadingError> {
|
|
||||||
let size = locate(file, load_ps_header)?;
|
|
||||||
let mut buffer = Vec::with_capacity(size);
|
|
||||||
unsafe {
|
|
||||||
buffer.set_len(size);
|
|
||||||
}
|
|
||||||
file.read_exact(&mut buffer)?;
|
|
||||||
Ok(buffer)
|
|
||||||
}
|
|
|
@ -1,287 +0,0 @@
|
||||||
#![no_std]
|
|
||||||
extern crate alloc;
|
|
||||||
|
|
||||||
use core::fmt;
|
|
||||||
use alloc::{string::FromUtf8Error, string::String, vec::Vec, rc::Rc, str};
|
|
||||||
use core_io::{self as io, BufRead, BufReader, Read, Write, Seek, ErrorKind, SeekFrom};
|
|
||||||
use libboard_zynq::sdio;
|
|
||||||
|
|
||||||
pub mod sd_reader;
|
|
||||||
pub mod net_settings;
|
|
||||||
pub mod bootgen;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum Error<'a> {
|
|
||||||
SdError(sdio::sd_card::CardInitializationError),
|
|
||||||
IoError(io::Error),
|
|
||||||
Utf8Error(FromUtf8Error),
|
|
||||||
KeyNotFoundError(&'a str),
|
|
||||||
NoConfig,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type Result<'a, T> = core::result::Result<T, Error<'a>>;
|
|
||||||
|
|
||||||
impl<'a> fmt::Display for Error<'a> {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
Error::SdError(error) => write!(f, "SD error: {}", error),
|
|
||||||
Error::IoError(error) => write!(f, "I/O error: {}", error),
|
|
||||||
Error::Utf8Error(error) => write!(f, "UTF-8 error: {}", error),
|
|
||||||
Error::KeyNotFoundError(name) => write!(f, "Configuration key `{}` not found", name),
|
|
||||||
Error::NoConfig => write!(f, "Configuration not present"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> From<sdio::sd_card::CardInitializationError> for Error<'a> {
|
|
||||||
fn from(error: sdio::sd_card::CardInitializationError) -> Self {
|
|
||||||
Error::SdError(error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> From<io::Error> for Error<'a> {
|
|
||||||
fn from(error: io::Error) -> Self {
|
|
||||||
Error::IoError(error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> From<FromUtf8Error> for Error<'a> {
|
|
||||||
fn from(error: FromUtf8Error) -> Self {
|
|
||||||
Error::Utf8Error(error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_config<'a>(
|
|
||||||
key: &'a str,
|
|
||||||
buffer: &mut Vec<u8>,
|
|
||||||
file: fatfs::File<sd_reader::SdReader>,
|
|
||||||
) -> Result<'a, ()> {
|
|
||||||
let prefix = [key, "="].concat();
|
|
||||||
for line in BufReader::new(file).lines() {
|
|
||||||
let line = line?;
|
|
||||||
if line.starts_with(&prefix) {
|
|
||||||
buffer.extend(line[prefix.len()..].as_bytes());
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(Error::KeyNotFoundError(key))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn delete_old_entry<'a>(
|
|
||||||
key: &str,
|
|
||||||
file: fatfs::File<sd_reader::SdReader>,
|
|
||||||
mut file_tmp: fatfs::File<sd_reader::SdReader>,
|
|
||||||
) -> Result<'a, ()> {
|
|
||||||
let prefix = [key, "="].concat();
|
|
||||||
let buf_reader = BufReader::new(file);
|
|
||||||
|
|
||||||
for line in buf_reader.lines() {
|
|
||||||
let line = line?;
|
|
||||||
if !line.starts_with(&prefix) {
|
|
||||||
file_tmp.write_all(&[line.as_str(), "\n"].concat().as_bytes())?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn rename_file<'a>(dir: &fatfs::Dir<sd_reader::SdReader>, old_file_name: &str, new_file_name: &str) -> Result<'a, ()>{
|
|
||||||
{
|
|
||||||
let old_file = dir.open_file(old_file_name)?;
|
|
||||||
let mut new_file = dir.create_file(new_file_name)?;
|
|
||||||
new_file.truncate()?;
|
|
||||||
|
|
||||||
for line in BufReader::new(old_file).lines() {
|
|
||||||
let line = line?;
|
|
||||||
new_file.write_all(&[line.as_str(), "\n"].concat().as_bytes())?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dir.remove(old_file_name)?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Config {
|
|
||||||
fs: Option<Rc<fatfs::FileSystem<sd_reader::SdReader>>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Config {
|
|
||||||
pub fn new() -> Result<'static, Self> {
|
|
||||||
let sdio = sdio::Sdio::sdio0(true);
|
|
||||||
if !sdio.is_card_inserted() {
|
|
||||||
Err(sdio::sd_card::CardInitializationError::NoCardInserted)?;
|
|
||||||
}
|
|
||||||
let sd = sdio::sd_card::SdCard::from_sdio(sdio)?;
|
|
||||||
let reader = sd_reader::SdReader::new(sd);
|
|
||||||
|
|
||||||
let fs = reader.mount_fatfs(sd_reader::PartitionEntry::Entry1)?;
|
|
||||||
Ok(Config { fs: Some(Rc::new(fs)) })
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn from_fs(fs: Option<Rc<fatfs::FileSystem<sd_reader::SdReader>>>) -> Self {
|
|
||||||
Config { fs }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_dummy() -> Self {
|
|
||||||
Config { fs: None }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn read<'b>(&self, key: &'b str) -> Result<'b, Vec<u8>> {
|
|
||||||
if let Some(fs) = &self.fs {
|
|
||||||
let root_dir = fs.root_dir();
|
|
||||||
let mut buffer: Vec<u8> = Vec::new();
|
|
||||||
match root_dir.open_file(&["/CONFIG/", key, ".BIN"].concat()) {
|
|
||||||
Ok(mut f) => f.read_to_end(&mut buffer).map(|_| ())?,
|
|
||||||
Err(_) => match root_dir.open_file("/CONFIG.TXT") {
|
|
||||||
Ok(f) => parse_config(key, &mut buffer, f)?,
|
|
||||||
Err(_) => return Err(Error::KeyNotFoundError(key)),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
Ok(buffer)
|
|
||||||
} else {
|
|
||||||
Err(Error::NoConfig)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn read_str<'b>(&self, key: &'b str) -> Result<'b, String> {
|
|
||||||
Ok(String::from_utf8(self.read(key)?)?)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn erase<'b>(&mut self) -> Result<'b, ()>{
|
|
||||||
if let Some(fs) = &self.fs {
|
|
||||||
let root_dir = fs.root_dir();
|
|
||||||
|
|
||||||
match root_dir.create_file("/CONFIG.TXT") {
|
|
||||||
Ok(mut file) => {
|
|
||||||
file.truncate()?;
|
|
||||||
},
|
|
||||||
Err(e) => {
|
|
||||||
return Err(Error::IoError(e));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let dir = root_dir.create_dir("/CONFIG")?;
|
|
||||||
for r in dir.iter() {
|
|
||||||
let entry = r?;
|
|
||||||
if entry.is_file() {
|
|
||||||
dir.remove(str::from_utf8(entry.short_file_name_as_bytes()).unwrap())?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(Error::NoConfig)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn remove_config_txt<'b>(&mut self, key: &str) -> Result<'b, ()>{
|
|
||||||
if let Some(fs) = &self.fs {
|
|
||||||
let root_dir = fs.root_dir();
|
|
||||||
|
|
||||||
let config_txt_tmp = "/CONFIG.TMP";
|
|
||||||
|
|
||||||
let mut need_to_rename = false;
|
|
||||||
match root_dir.open_file("/CONFIG.TXT") {
|
|
||||||
Ok(file) => {
|
|
||||||
need_to_rename = true;
|
|
||||||
let mut file_tmp = root_dir.create_file(config_txt_tmp)?;
|
|
||||||
file_tmp.truncate()?;
|
|
||||||
delete_old_entry(key, file, file_tmp)?;
|
|
||||||
},
|
|
||||||
Err(e) => match e.kind() {
|
|
||||||
ErrorKind::NotFound => {},
|
|
||||||
_ => {
|
|
||||||
return Err(Error::IoError(e));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
if need_to_rename {
|
|
||||||
rename_file(&root_dir, config_txt_tmp, "/CONFIG.TXT")?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(Error::NoConfig)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn remove_config_key_bin<'b>(&mut self, key: &str) -> Result<'b, ()>{
|
|
||||||
if let Some(fs) = &self.fs {
|
|
||||||
let root_dir = fs.root_dir();
|
|
||||||
|
|
||||||
let config_key_bin = &["/CONFIG/", key, ".BIN"].concat();
|
|
||||||
|
|
||||||
match root_dir.remove(config_key_bin) {
|
|
||||||
Ok(_) => {},
|
|
||||||
Err(e) => match e.kind() {
|
|
||||||
ErrorKind::NotFound => {},
|
|
||||||
_ => {
|
|
||||||
return Err(Error::IoError(e));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(Error::NoConfig)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn remove<'b>(&mut self, key: &str) -> Result<'b, ()>{
|
|
||||||
self.remove_config_txt(key)?;
|
|
||||||
self.remove_config_key_bin(key)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
pub fn write_str<'b>(&mut self, key: &str, data: &str) -> Result<'b, ()>{
|
|
||||||
let mut call_remove_config_key_bin = false;
|
|
||||||
let mut call_remove_config_txt = false;
|
|
||||||
|
|
||||||
if let Some(fs) = &self.fs {
|
|
||||||
let root_dir = fs.root_dir();
|
|
||||||
|
|
||||||
let config_key_bin = &["/CONFIG/", key, ".BIN"].concat();
|
|
||||||
let config_txt_tmp = "/CONFIG.TMP";
|
|
||||||
|
|
||||||
if data.is_ascii() & (data.len() <= 100) {
|
|
||||||
match root_dir.create_file("/CONFIG.TXT") {
|
|
||||||
Ok(file) => {
|
|
||||||
let mut file_tmp = root_dir.create_file(config_txt_tmp)?;
|
|
||||||
file_tmp.truncate()?;
|
|
||||||
delete_old_entry(key, file, file_tmp)?;
|
|
||||||
},
|
|
||||||
Err(e) => {
|
|
||||||
return Err(Error::IoError(e));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
rename_file(&root_dir, config_txt_tmp, "/CONFIG.TXT")?;
|
|
||||||
|
|
||||||
let mut file = root_dir.open_file("/CONFIG.TXT")?;
|
|
||||||
file.seek(SeekFrom::End(0))?;
|
|
||||||
file.write_all(&["\n", key, "=", data, "\n"].concat().as_bytes())?;
|
|
||||||
|
|
||||||
call_remove_config_key_bin = true;
|
|
||||||
} else {
|
|
||||||
root_dir.create_dir("/CONFIG")?;
|
|
||||||
match root_dir.create_file(config_key_bin) {
|
|
||||||
Ok(mut file) => {
|
|
||||||
file.truncate()?;
|
|
||||||
file.write_all(&[data, "\n"].concat().as_bytes())?;
|
|
||||||
},
|
|
||||||
Err(e) => {
|
|
||||||
return Err(Error::IoError(e));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
call_remove_config_txt = true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return Err(Error::NoConfig);
|
|
||||||
}
|
|
||||||
|
|
||||||
if call_remove_config_key_bin {
|
|
||||||
self.remove_config_key_bin(key)?;
|
|
||||||
}
|
|
||||||
if call_remove_config_txt {
|
|
||||||
self.remove_config_txt(key)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,62 +0,0 @@
|
||||||
use core::fmt;
|
|
||||||
|
|
||||||
use libboard_zynq::smoltcp::wire::{EthernetAddress, IpAddress};
|
|
||||||
|
|
||||||
use super::Config;
|
|
||||||
|
|
||||||
pub struct NetAddresses {
|
|
||||||
pub hardware_addr: EthernetAddress,
|
|
||||||
pub ipv4_addr: IpAddress,
|
|
||||||
#[cfg(feature = "ipv6")]
|
|
||||||
pub ipv6_ll_addr: IpAddress,
|
|
||||||
#[cfg(feature = "ipv6")]
|
|
||||||
pub ipv6_addr: Option<IpAddress>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for NetAddresses {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
write!(f, "MAC={} IPv4={} ",
|
|
||||||
self.hardware_addr, self.ipv4_addr)?;
|
|
||||||
|
|
||||||
#[cfg(feature = "ipv6")]
|
|
||||||
{
|
|
||||||
write!(f, "IPv6-LL={}", self.ipv6_ll_addr)?;
|
|
||||||
match self.ipv6_addr {
|
|
||||||
Some(addr) => write!(f, " {}", addr)?,
|
|
||||||
None => write!(f, " IPv6: no configured address")?
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_adresses(cfg: &Config) -> NetAddresses {
|
|
||||||
let mut hardware_addr = EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x52]);
|
|
||||||
let mut ipv4_addr = IpAddress::v4(192, 168, 1, 52);
|
|
||||||
|
|
||||||
if let Ok(Ok(addr)) = cfg.read_str("mac").map(|s| s.parse()) {
|
|
||||||
hardware_addr = addr;
|
|
||||||
}
|
|
||||||
if let Ok(Ok(addr)) = cfg.read_str("ip").map(|s| s.parse()) {
|
|
||||||
ipv4_addr = addr;
|
|
||||||
}
|
|
||||||
#[cfg(feature = "ipv6")]
|
|
||||||
let ipv6_addr = cfg.read_str("ipv6").ok().and_then(|s| s.parse().ok());
|
|
||||||
|
|
||||||
#[cfg(feature = "ipv6")]
|
|
||||||
let ipv6_ll_addr = IpAddress::v6(
|
|
||||||
0xfe80, 0x0000, 0x0000, 0x0000,
|
|
||||||
(((hardware_addr.0[0] ^ 0x02) as u16) << 8) | (hardware_addr.0[1] as u16),
|
|
||||||
((hardware_addr.0[2] as u16) << 8) | 0x00ff,
|
|
||||||
0xfe00 | (hardware_addr.0[3] as u16),
|
|
||||||
((hardware_addr.0[4] as u16) << 8) | (hardware_addr.0[5] as u16));
|
|
||||||
|
|
||||||
NetAddresses {
|
|
||||||
hardware_addr,
|
|
||||||
ipv4_addr,
|
|
||||||
#[cfg(feature = "ipv6")]
|
|
||||||
ipv6_ll_addr,
|
|
||||||
#[cfg(feature = "ipv6")]
|
|
||||||
ipv6_addr
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,303 +0,0 @@
|
||||||
use core_io::{BufRead, Error, ErrorKind, Read, Result as IoResult, Seek, SeekFrom, Write};
|
|
||||||
use fatfs;
|
|
||||||
use libboard_zynq::sdio::{sd_card::SdCard, CmdTransferError};
|
|
||||||
use log::debug;
|
|
||||||
use alloc::vec::Vec;
|
|
||||||
|
|
||||||
const MBR_SIGNATURE: [u8; 2] = [0x55, 0xAA];
|
|
||||||
const PARTID_FAT12: u8 = 0x01;
|
|
||||||
const PARTID_FAT16_LESS32M: u8 = 0x04;
|
|
||||||
const PARTID_FAT16: u8 = 0x06;
|
|
||||||
const PARTID_FAT32: u8 = 0x0B;
|
|
||||||
const PARTID_FAT32_LBA: u8 = 0x0C;
|
|
||||||
|
|
||||||
fn cmd_error_to_io_error(_: CmdTransferError) -> Error {
|
|
||||||
Error::new(ErrorKind::Other, "Command transfer error")
|
|
||||||
}
|
|
||||||
|
|
||||||
const BLOCK_SIZE: usize = 512;
|
|
||||||
|
|
||||||
/// SdReader struct implementing `Read + BufRead + Write + Seek` traits for `core_io`.
|
|
||||||
/// Used as an adaptor for fatfs crate, but could be used directly for raw data access.
|
|
||||||
///
|
|
||||||
/// Implementation: all read/writes would be split into unaligned and block-aligned parts,
|
|
||||||
/// unaligned read/writes would do a buffered read/write using a block-sized internal buffer,
|
|
||||||
/// while aligned transactions would be sent to the SD card directly for performance reason.
|
|
||||||
pub struct SdReader {
|
|
||||||
/// Internal SdCard handle.
|
|
||||||
sd: SdCard,
|
|
||||||
/// Read buffer with the size of 1 block.
|
|
||||||
buffer: Vec<u8>,
|
|
||||||
/// Address for the next byte.
|
|
||||||
byte_addr: u32,
|
|
||||||
/// Internal index for the next byte.
|
|
||||||
/// Normally in range `[0, BLOCK_SIZE - 1]`.
|
|
||||||
///
|
|
||||||
/// `index = BLOCK_SIZE` means that the `buffer` is invalid for the current `byte_addr`,
|
|
||||||
/// the next `fill_buf` call would fill the buffer.
|
|
||||||
index: usize,
|
|
||||||
/// Dirty flag indicating the content has to be flushed.
|
|
||||||
dirty: bool,
|
|
||||||
/// Base offset for translation from logical address to physical address.
|
|
||||||
offset: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
|
||||||
#[allow(unused)]
|
|
||||||
// Partition entry enum, normally we would use entry1.
|
|
||||||
pub enum PartitionEntry {
|
|
||||||
Entry1 = 0x1BE,
|
|
||||||
Entry2 = 0x1CE,
|
|
||||||
Entry3 = 0x1DE,
|
|
||||||
Entry4 = 0x1EE,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SdReader {
|
|
||||||
/// Create SdReader from SdCard
|
|
||||||
pub fn new(sd: SdCard) -> SdReader {
|
|
||||||
let mut vec: Vec<u8> = Vec::with_capacity(BLOCK_SIZE);
|
|
||||||
unsafe {
|
|
||||||
vec.set_len(vec.capacity());
|
|
||||||
}
|
|
||||||
SdReader {
|
|
||||||
sd,
|
|
||||||
buffer: vec,
|
|
||||||
byte_addr: 0,
|
|
||||||
index: BLOCK_SIZE,
|
|
||||||
dirty: false,
|
|
||||||
offset: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Internal read function for unaligned read.
|
|
||||||
/// The read must not cross block boundary.
|
|
||||||
fn read_unaligned(&mut self, buf: &mut [u8]) -> IoResult<usize> {
|
|
||||||
if buf.len() == 0 {
|
|
||||||
return Ok(0);
|
|
||||||
}
|
|
||||||
let filled_buffer = self.fill_buf()?;
|
|
||||||
for (dest, src) in buf.iter_mut().zip(filled_buffer.iter()) {
|
|
||||||
*dest = *src;
|
|
||||||
}
|
|
||||||
self.consume(buf.len());
|
|
||||||
Ok(buf.len())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Internal write function for unaligned write.
|
|
||||||
/// The write must not cross block boundary.
|
|
||||||
fn write_unaligned(&mut self, buf: &[u8]) -> IoResult<usize> {
|
|
||||||
if buf.len() == 0 {
|
|
||||||
return Ok(0);
|
|
||||||
}
|
|
||||||
// update buffer if needed, as we will flush the entire block later.
|
|
||||||
self.fill_buf()?;
|
|
||||||
self.dirty = true;
|
|
||||||
let dest_buffer = &mut self.buffer[self.index..];
|
|
||||||
for (src, dest) in buf.iter().zip(dest_buffer.iter_mut()) {
|
|
||||||
*dest = *src;
|
|
||||||
}
|
|
||||||
self.consume(buf.len());
|
|
||||||
Ok(buf.len())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Split the slice into three segments, with the middle block-aligned.
|
|
||||||
/// Alignment depends on the current `self.byte_addr` instead of the slice pointer address
|
|
||||||
fn block_align<'b>(&self, buf: &'b [u8]) -> (&'b [u8], &'b [u8], &'b [u8]) {
|
|
||||||
let head_len = BLOCK_SIZE - (self.byte_addr as usize % BLOCK_SIZE);
|
|
||||||
if head_len > buf.len() {
|
|
||||||
(buf, &[], &[])
|
|
||||||
} else {
|
|
||||||
let remaining_length = buf.len() - head_len;
|
|
||||||
let mid_length = remaining_length - remaining_length % BLOCK_SIZE;
|
|
||||||
let (head, remaining) = buf.split_at(head_len);
|
|
||||||
let (mid, tail) = remaining.split_at(mid_length);
|
|
||||||
(head, mid, tail)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Split the mutable slice into three segments, with the middle block-aligned.
|
|
||||||
/// Alignment depends on the current `self.byte_addr` instead of the slice pointer address
|
|
||||||
fn block_align_mut<'b>(&self, buf: &'b mut [u8]) -> (&'b mut [u8], &'b mut [u8], &'b mut [u8]) {
|
|
||||||
let head_len = BLOCK_SIZE - (self.byte_addr as usize % BLOCK_SIZE);
|
|
||||||
if head_len > buf.len() {
|
|
||||||
(buf, &mut [], &mut [])
|
|
||||||
} else {
|
|
||||||
let remaining_length = buf.len() - head_len;
|
|
||||||
let mid_length = remaining_length - remaining_length % BLOCK_SIZE;
|
|
||||||
let (head, remaining) = buf.split_at_mut(head_len);
|
|
||||||
let (mid, tail) = remaining.split_at_mut(mid_length);
|
|
||||||
(head, mid, tail)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Invalidate the buffer, so later unaligned read/write would reload the buffer from SD card.
|
|
||||||
fn invalidate_buffer(&mut self) {
|
|
||||||
self.index = BLOCK_SIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set the base offset of the SD card, to transform from physical address to logical address.
|
|
||||||
fn set_base_offset(&mut self, offset: u32) -> IoResult<u64> {
|
|
||||||
self.offset = offset;
|
|
||||||
self.seek(SeekFrom::Start(0))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Mount fatfs from partition entry, and return the fatfs object if success.
|
|
||||||
/// This takes the ownership of self, so currently there is no way to recover from an error,
|
|
||||||
/// except creating a new SD card instance.
|
|
||||||
pub fn mount_fatfs(mut self, entry: PartitionEntry) -> IoResult<fatfs::FileSystem<Self>> {
|
|
||||||
let mut buffer: [u8; 4] = [0; 4];
|
|
||||||
self.seek(SeekFrom::Start(0x1FE))?;
|
|
||||||
self.read_exact(&mut buffer[..2])?;
|
|
||||||
// check MBR signature
|
|
||||||
if buffer[..2] != MBR_SIGNATURE {
|
|
||||||
return Err(Error::new(
|
|
||||||
ErrorKind::InvalidData,
|
|
||||||
"Incorrect signature for MBR sector.",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
// Read partition ID.
|
|
||||||
self.seek(SeekFrom::Start(entry as u64 + 0x4))?;
|
|
||||||
self.read_exact(&mut buffer[..1])?;
|
|
||||||
debug!("Partition ID: {:0X}", buffer[0]);
|
|
||||||
match buffer[0] {
|
|
||||||
PARTID_FAT12 | PARTID_FAT16_LESS32M | PARTID_FAT16 |
|
|
||||||
PARTID_FAT32 | PARTID_FAT32_LBA => {}
|
|
||||||
_ => {
|
|
||||||
return Err(Error::new(
|
|
||||||
ErrorKind::InvalidData,
|
|
||||||
"No FAT partition found for the specified entry.",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Read LBA
|
|
||||||
self.seek(SeekFrom::Current(0x3))?;
|
|
||||||
self.read_exact(&mut buffer)?;
|
|
||||||
let mut lba: u32 = 0;
|
|
||||||
// Little endian
|
|
||||||
for i in 0..4 {
|
|
||||||
lba |= (buffer[i] as u32) << (i * 8);
|
|
||||||
}
|
|
||||||
// Set to logical address
|
|
||||||
self.set_base_offset(lba * BLOCK_SIZE as u32)?;
|
|
||||||
// setup fatfs
|
|
||||||
fatfs::FileSystem::new(self, fatfs::FsOptions::new())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Read for SdReader {
|
|
||||||
fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> {
|
|
||||||
let total_length = buf.len();
|
|
||||||
let (a, b, c) = self.block_align_mut(buf);
|
|
||||||
self.read_unaligned(a)?;
|
|
||||||
if b.len() > 0 {
|
|
||||||
// invalidate internal buffer
|
|
||||||
self.invalidate_buffer();
|
|
||||||
if let Err(_) = self.sd.read_block(
|
|
||||||
self.byte_addr / BLOCK_SIZE as u32,
|
|
||||||
(b.len() / BLOCK_SIZE) as u16,
|
|
||||||
b,
|
|
||||||
) {
|
|
||||||
// we have to allow partial read, as per the trait required
|
|
||||||
return Ok(a.len());
|
|
||||||
}
|
|
||||||
self.byte_addr += b.len() as u32;
|
|
||||||
}
|
|
||||||
if let Err(_) = self.read_unaligned(c) {
|
|
||||||
// we have to allow partial read, as per the trait required
|
|
||||||
return Ok(a.len() + b.len());
|
|
||||||
}
|
|
||||||
Ok(total_length)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BufRead for SdReader {
|
|
||||||
fn fill_buf(&mut self) -> IoResult<&[u8]> {
|
|
||||||
if self.index == BLOCK_SIZE {
|
|
||||||
// flush the buffer if it is dirty before overwriting it with new data
|
|
||||||
if self.dirty {
|
|
||||||
self.flush()?;
|
|
||||||
}
|
|
||||||
// reload buffer
|
|
||||||
self.sd
|
|
||||||
.read_block(self.byte_addr / (BLOCK_SIZE as u32), 1, &mut self.buffer)
|
|
||||||
.map_err(cmd_error_to_io_error)?;
|
|
||||||
self.index = (self.byte_addr as usize) % BLOCK_SIZE;
|
|
||||||
}
|
|
||||||
Ok(&self.buffer[self.index..])
|
|
||||||
}
|
|
||||||
|
|
||||||
fn consume(&mut self, amt: usize) {
|
|
||||||
self.index += amt;
|
|
||||||
self.byte_addr += amt as u32;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Write for SdReader {
|
|
||||||
fn write(&mut self, buf: &[u8]) -> IoResult<usize> {
|
|
||||||
let (a, b, c) = self.block_align(buf);
|
|
||||||
self.write_unaligned(a)?;
|
|
||||||
if b.len() > 0 {
|
|
||||||
self.flush()?;
|
|
||||||
self.invalidate_buffer();
|
|
||||||
if let Err(_) = self.sd.write_block(
|
|
||||||
self.byte_addr / BLOCK_SIZE as u32,
|
|
||||||
(b.len() / BLOCK_SIZE) as u16,
|
|
||||||
b,
|
|
||||||
) {
|
|
||||||
return Ok(a.len());
|
|
||||||
}
|
|
||||||
self.byte_addr += b.len() as u32;
|
|
||||||
}
|
|
||||||
if let Err(_) = self.write_unaligned(c) {
|
|
||||||
return Ok(a.len() + b.len());
|
|
||||||
}
|
|
||||||
Ok(buf.len())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn flush(&mut self) -> IoResult<()> {
|
|
||||||
if self.dirty {
|
|
||||||
let block_addr = (self.byte_addr - self.index as u32) / (BLOCK_SIZE as u32);
|
|
||||||
self.sd
|
|
||||||
.write_block(block_addr, 1, &self.buffer)
|
|
||||||
.map_err(cmd_error_to_io_error)?;
|
|
||||||
self.dirty = false;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Seek for SdReader {
|
|
||||||
fn seek(&mut self, pos: SeekFrom) -> IoResult<u64> {
|
|
||||||
let raw_target = match pos {
|
|
||||||
SeekFrom::Start(x) => self.offset as i64 + x as i64,
|
|
||||||
SeekFrom::Current(x) => self.byte_addr as i64 + x,
|
|
||||||
SeekFrom::End(_) => panic!("SD card does not support seek from end"),
|
|
||||||
};
|
|
||||||
if raw_target < self.offset as i64 || raw_target > core::u32::MAX as i64 {
|
|
||||||
return Err(Error::new(ErrorKind::InvalidInput, "Invalid address"));
|
|
||||||
}
|
|
||||||
let target_byte_addr = raw_target as u32;
|
|
||||||
let address_same_block =
|
|
||||||
self.byte_addr / (BLOCK_SIZE as u32) == target_byte_addr / (BLOCK_SIZE as u32);
|
|
||||||
// if the buffer was invalidated, we consider seek as different block
|
|
||||||
let same_block = address_same_block && self.index != BLOCK_SIZE;
|
|
||||||
if !same_block {
|
|
||||||
self.flush()?;
|
|
||||||
}
|
|
||||||
self.byte_addr = target_byte_addr;
|
|
||||||
self.index = if same_block {
|
|
||||||
target_byte_addr as usize % BLOCK_SIZE
|
|
||||||
} else {
|
|
||||||
// invalidate the buffer as we moved to a different block
|
|
||||||
BLOCK_SIZE
|
|
||||||
};
|
|
||||||
Ok((self.byte_addr - self.offset) as u64)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Drop for SdReader {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
// just try to flush it, ignore error if any
|
|
||||||
self.flush().unwrap_or(());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,14 +0,0 @@
|
||||||
[package]
|
|
||||||
authors = ["M-Labs"]
|
|
||||||
name = "core_io"
|
|
||||||
version = "0.1.20200410"
|
|
||||||
|
|
||||||
[lib]
|
|
||||||
name = "core_io"
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
memchr = { version = "2", default-features = false, optional = true }
|
|
||||||
|
|
||||||
[features]
|
|
||||||
alloc = []
|
|
||||||
collections = ["alloc", "memchr"]
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,896 +0,0 @@
|
||||||
use crate::io::prelude::*;
|
|
||||||
|
|
||||||
use core::cmp;
|
|
||||||
use crate::io::{self, Error, ErrorKind, Initializer, SeekFrom};
|
|
||||||
|
|
||||||
#[cfg(feature = "collections")]
|
|
||||||
use core::convert::TryInto;
|
|
||||||
|
|
||||||
#[cfg(feature="collections")]
|
|
||||||
use collections::vec::Vec;
|
|
||||||
|
|
||||||
#[cfg(feature = "alloc")]
|
|
||||||
use alloc::boxed::Box;
|
|
||||||
|
|
||||||
/// A `Cursor` wraps an in-memory buffer and provides it with a
|
|
||||||
/// [`Seek`] implementation.
|
|
||||||
///
|
|
||||||
/// `Cursor`s are used with in-memory buffers, anything implementing
|
|
||||||
/// `AsRef<[u8]>`, to allow them to implement [`Read`] and/or [`Write`],
|
|
||||||
/// allowing these buffers to be used anywhere you might use a reader or writer
|
|
||||||
/// that does actual I/O.
|
|
||||||
///
|
|
||||||
/// The standard library implements some I/O traits on various types which
|
|
||||||
/// are commonly used as a buffer, like `Cursor<`[`Vec`]`<u8>>` and
|
|
||||||
/// `Cursor<`[`&[u8]`][bytes]`>`.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// We may want to write bytes to a [`File`] in our production
|
|
||||||
/// code, but use an in-memory buffer in our tests. We can do this with
|
|
||||||
/// `Cursor`:
|
|
||||||
///
|
|
||||||
/// [`Seek`]: trait.Seek.html
|
|
||||||
/// [`Read`]: ../../std/io/trait.Read.html
|
|
||||||
/// [`Write`]: ../../std/io/trait.Write.html
|
|
||||||
/// [`Vec`]: ../../std/vec/struct.Vec.html
|
|
||||||
/// [bytes]: ../../std/primitive.slice.html
|
|
||||||
/// [`File`]: ../fs/struct.File.html
|
|
||||||
///
|
|
||||||
/// ```no_run
|
|
||||||
/// use std::io::prelude::*;
|
|
||||||
/// use std::io::{self, SeekFrom};
|
|
||||||
/// use std::fs::File;
|
|
||||||
///
|
|
||||||
/// // a library function we've written
|
|
||||||
/// fn write_ten_bytes_at_end<W: Write + Seek>(writer: &mut W) -> io::Result<()> {
|
|
||||||
/// writer.seek(SeekFrom::End(-10))?;
|
|
||||||
///
|
|
||||||
/// for i in 0..10 {
|
|
||||||
/// writer.write(&[i])?;
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// // all went well
|
|
||||||
/// Ok(())
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// # fn foo() -> io::Result<()> {
|
|
||||||
/// // Here's some code that uses this library function.
|
|
||||||
/// //
|
|
||||||
/// // We might want to use a BufReader here for efficiency, but let's
|
|
||||||
/// // keep this example focused.
|
|
||||||
/// let mut file = File::create("foo.txt")?;
|
|
||||||
///
|
|
||||||
/// write_ten_bytes_at_end(&mut file)?;
|
|
||||||
/// # Ok(())
|
|
||||||
/// # }
|
|
||||||
///
|
|
||||||
/// // now let's write a test
|
|
||||||
/// #[test]
|
|
||||||
/// fn test_writes_bytes() {
|
|
||||||
/// // setting up a real File is much slower than an in-memory buffer,
|
|
||||||
/// // let's use a cursor instead
|
|
||||||
/// use std::io::Cursor;
|
|
||||||
/// let mut buff = Cursor::new(vec![0; 15]);
|
|
||||||
///
|
|
||||||
/// write_ten_bytes_at_end(&mut buff).unwrap();
|
|
||||||
///
|
|
||||||
/// assert_eq!(&buff.get_ref()[5..15], &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
#[derive(Clone, Debug, Default, Eq, PartialEq)]
|
|
||||||
pub struct Cursor<T> {
|
|
||||||
inner: T,
|
|
||||||
pos: u64,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> Cursor<T> {
|
|
||||||
/// Creates a new cursor wrapping the provided underlying in-memory buffer.
|
|
||||||
///
|
|
||||||
/// Cursor initial position is `0` even if underlying buffer (e.g., `Vec`)
|
|
||||||
/// is not empty. So writing to cursor starts with overwriting `Vec`
|
|
||||||
/// content, not with appending to it.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use std::io::Cursor;
|
|
||||||
///
|
|
||||||
/// let buff = Cursor::new(Vec::new());
|
|
||||||
/// # fn force_inference(_: &Cursor<Vec<u8>>) {}
|
|
||||||
/// # force_inference(&buff);
|
|
||||||
/// ```
|
|
||||||
pub fn new(inner: T) -> Cursor<T> {
|
|
||||||
Cursor { pos: 0, inner }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Consumes this cursor, returning the underlying value.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use std::io::Cursor;
|
|
||||||
///
|
|
||||||
/// let buff = Cursor::new(Vec::new());
|
|
||||||
/// # fn force_inference(_: &Cursor<Vec<u8>>) {}
|
|
||||||
/// # force_inference(&buff);
|
|
||||||
///
|
|
||||||
/// let vec = buff.into_inner();
|
|
||||||
/// ```
|
|
||||||
pub fn into_inner(self) -> T {
|
|
||||||
self.inner
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Gets a reference to the underlying value in this cursor.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use std::io::Cursor;
|
|
||||||
///
|
|
||||||
/// let buff = Cursor::new(Vec::new());
|
|
||||||
/// # fn force_inference(_: &Cursor<Vec<u8>>) {}
|
|
||||||
/// # force_inference(&buff);
|
|
||||||
///
|
|
||||||
/// let reference = buff.get_ref();
|
|
||||||
/// ```
|
|
||||||
pub fn get_ref(&self) -> &T {
|
|
||||||
&self.inner
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Gets a mutable reference to the underlying value in this cursor.
|
|
||||||
///
|
|
||||||
/// Care should be taken to avoid modifying the internal I/O state of the
|
|
||||||
/// underlying value as it may corrupt this cursor's position.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use std::io::Cursor;
|
|
||||||
///
|
|
||||||
/// let mut buff = Cursor::new(Vec::new());
|
|
||||||
/// # fn force_inference(_: &Cursor<Vec<u8>>) {}
|
|
||||||
/// # force_inference(&buff);
|
|
||||||
///
|
|
||||||
/// let reference = buff.get_mut();
|
|
||||||
/// ```
|
|
||||||
pub fn get_mut(&mut self) -> &mut T {
|
|
||||||
&mut self.inner
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the current position of this cursor.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use std::io::Cursor;
|
|
||||||
/// use std::io::prelude::*;
|
|
||||||
/// use std::io::SeekFrom;
|
|
||||||
///
|
|
||||||
/// let mut buff = Cursor::new(vec![1, 2, 3, 4, 5]);
|
|
||||||
///
|
|
||||||
/// assert_eq!(buff.position(), 0);
|
|
||||||
///
|
|
||||||
/// buff.seek(SeekFrom::Current(2)).unwrap();
|
|
||||||
/// assert_eq!(buff.position(), 2);
|
|
||||||
///
|
|
||||||
/// buff.seek(SeekFrom::Current(-1)).unwrap();
|
|
||||||
/// assert_eq!(buff.position(), 1);
|
|
||||||
/// ```
|
|
||||||
pub fn position(&self) -> u64 {
|
|
||||||
self.pos
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sets the position of this cursor.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use std::io::Cursor;
|
|
||||||
///
|
|
||||||
/// let mut buff = Cursor::new(vec![1, 2, 3, 4, 5]);
|
|
||||||
///
|
|
||||||
/// assert_eq!(buff.position(), 0);
|
|
||||||
///
|
|
||||||
/// buff.set_position(2);
|
|
||||||
/// assert_eq!(buff.position(), 2);
|
|
||||||
///
|
|
||||||
/// buff.set_position(4);
|
|
||||||
/// assert_eq!(buff.position(), 4);
|
|
||||||
/// ```
|
|
||||||
pub fn set_position(&mut self, pos: u64) {
|
|
||||||
self.pos = pos;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> io::Seek for Cursor<T>
|
|
||||||
where
|
|
||||||
T: AsRef<[u8]>,
|
|
||||||
{
|
|
||||||
fn seek(&mut self, style: SeekFrom) -> io::Result<u64> {
|
|
||||||
let (base_pos, offset) = match style {
|
|
||||||
SeekFrom::Start(n) => {
|
|
||||||
self.pos = n;
|
|
||||||
return Ok(n);
|
|
||||||
}
|
|
||||||
SeekFrom::End(n) => (self.inner.as_ref().len() as u64, n),
|
|
||||||
SeekFrom::Current(n) => (self.pos, n),
|
|
||||||
};
|
|
||||||
let new_pos = if offset >= 0 {
|
|
||||||
base_pos.checked_add(offset as u64)
|
|
||||||
} else {
|
|
||||||
base_pos.checked_sub((offset.wrapping_neg()) as u64)
|
|
||||||
};
|
|
||||||
match new_pos {
|
|
||||||
Some(n) => {
|
|
||||||
self.pos = n;
|
|
||||||
Ok(self.pos)
|
|
||||||
}
|
|
||||||
None => Err(Error::new(
|
|
||||||
ErrorKind::InvalidInput,
|
|
||||||
"invalid seek to a negative or overflowing position",
|
|
||||||
)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn stream_len(&mut self) -> io::Result<u64> {
|
|
||||||
Ok(self.inner.as_ref().len() as u64)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn stream_position(&mut self) -> io::Result<u64> {
|
|
||||||
Ok(self.pos)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> Read for Cursor<T>
|
|
||||||
where
|
|
||||||
T: AsRef<[u8]>,
|
|
||||||
{
|
|
||||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
|
||||||
let n = Read::read(&mut self.get_ref().as_ref(), buf)?;
|
|
||||||
self.pos += n as u64;
|
|
||||||
Ok(n)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
|
|
||||||
let n = buf.len();
|
|
||||||
Read::read_exact(&mut self.get_ref().as_ref(), buf)?;
|
|
||||||
self.pos += n as u64;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
unsafe fn initializer(&self) -> Initializer {
|
|
||||||
Initializer::nop()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "collections")]
|
|
||||||
impl<T> BufRead for Cursor<T>
|
|
||||||
where
|
|
||||||
T: AsRef<[u8]>,
|
|
||||||
{
|
|
||||||
fn fill_buf(&mut self) -> io::Result<&[u8]> {
|
|
||||||
let amt = cmp::min(self.pos, self.inner.as_ref().len() as u64);
|
|
||||||
Ok(&self.inner.as_ref()[(amt as usize)..])
|
|
||||||
}
|
|
||||||
fn consume(&mut self, amt: usize) {
|
|
||||||
self.pos += amt as u64;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Non-resizing write implementation
|
|
||||||
#[inline]
|
|
||||||
fn slice_write(pos_mut: &mut u64, slice: &mut [u8], buf: &[u8]) -> io::Result<usize> {
|
|
||||||
let pos = cmp::min(*pos_mut, slice.len() as u64);
|
|
||||||
let amt = (&mut slice[(pos as usize)..]).write(buf)?;
|
|
||||||
*pos_mut += amt as u64;
|
|
||||||
Ok(amt)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Resizing write implementation
|
|
||||||
#[cfg(feature = "collections")]
|
|
||||||
fn vec_write(pos_mut: &mut u64, vec: &mut Vec<u8>, buf: &[u8]) -> io::Result<usize> {
|
|
||||||
let pos: usize = (*pos_mut).try_into().map_err(|_| {
|
|
||||||
Error::new(
|
|
||||||
ErrorKind::InvalidInput,
|
|
||||||
"cursor position exceeds maximum possible vector length",
|
|
||||||
)
|
|
||||||
})?;
|
|
||||||
// Make sure the internal buffer is as least as big as where we
|
|
||||||
// currently are
|
|
||||||
let len = vec.len();
|
|
||||||
if len < pos {
|
|
||||||
// use `resize` so that the zero filling is as efficient as possible
|
|
||||||
vec.resize(pos, 0);
|
|
||||||
}
|
|
||||||
// Figure out what bytes will be used to overwrite what's currently
|
|
||||||
// there (left), and what will be appended on the end (right)
|
|
||||||
{
|
|
||||||
let space = vec.len() - pos;
|
|
||||||
let (left, right) = buf.split_at(cmp::min(space, buf.len()));
|
|
||||||
vec[pos..pos + left.len()].copy_from_slice(left);
|
|
||||||
vec.extend_from_slice(right);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bump us forward
|
|
||||||
*pos_mut = (pos + buf.len()) as u64;
|
|
||||||
Ok(buf.len())
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Write for Cursor<&mut [u8]> {
|
|
||||||
#[inline]
|
|
||||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
|
||||||
slice_write(&mut self.pos, self.inner, buf)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn flush(&mut self) -> io::Result<()> {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "collections")]
|
|
||||||
impl Write for Cursor<&mut Vec<u8>> {
|
|
||||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
|
||||||
vec_write(&mut self.pos, self.inner, buf)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn flush(&mut self) -> io::Result<()> {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "collections")]
|
|
||||||
impl Write for Cursor<Vec<u8>> {
|
|
||||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
|
||||||
vec_write(&mut self.pos, &mut self.inner, buf)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn flush(&mut self) -> io::Result<()> {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "alloc")]
|
|
||||||
impl Write for Cursor<Box<[u8]>> {
|
|
||||||
#[inline]
|
|
||||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
|
||||||
slice_write(&mut self.pos, &mut self.inner, buf)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn flush(&mut self) -> io::Result<()> {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use crate::io::prelude::*;
|
|
||||||
use crate::io::{Cursor, IoSlice, IoSliceMut, SeekFrom};
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_vec_writer() {
|
|
||||||
let mut writer = Vec::new();
|
|
||||||
assert_eq!(writer.write(&[0]).unwrap(), 1);
|
|
||||||
assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3);
|
|
||||||
assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4);
|
|
||||||
assert_eq!(
|
|
||||||
writer
|
|
||||||
.write_vectored(&[IoSlice::new(&[]), IoSlice::new(&[8, 9]), IoSlice::new(&[10])],)
|
|
||||||
.unwrap(),
|
|
||||||
3
|
|
||||||
);
|
|
||||||
let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
|
|
||||||
assert_eq!(writer, b);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_mem_writer() {
|
|
||||||
let mut writer = Cursor::new(Vec::new());
|
|
||||||
assert_eq!(writer.write(&[0]).unwrap(), 1);
|
|
||||||
assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3);
|
|
||||||
assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4);
|
|
||||||
assert_eq!(
|
|
||||||
writer
|
|
||||||
.write_vectored(&[IoSlice::new(&[]), IoSlice::new(&[8, 9]), IoSlice::new(&[10])],)
|
|
||||||
.unwrap(),
|
|
||||||
3
|
|
||||||
);
|
|
||||||
let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
|
|
||||||
assert_eq!(&writer.get_ref()[..], b);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_mem_mut_writer() {
|
|
||||||
let mut vec = Vec::new();
|
|
||||||
let mut writer = Cursor::new(&mut vec);
|
|
||||||
assert_eq!(writer.write(&[0]).unwrap(), 1);
|
|
||||||
assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3);
|
|
||||||
assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4);
|
|
||||||
assert_eq!(
|
|
||||||
writer
|
|
||||||
.write_vectored(&[IoSlice::new(&[]), IoSlice::new(&[8, 9]), IoSlice::new(&[10])],)
|
|
||||||
.unwrap(),
|
|
||||||
3
|
|
||||||
);
|
|
||||||
let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
|
|
||||||
assert_eq!(&writer.get_ref()[..], b);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_box_slice_writer() {
|
|
||||||
let mut writer = Cursor::new(vec![0u8; 9].into_boxed_slice());
|
|
||||||
assert_eq!(writer.position(), 0);
|
|
||||||
assert_eq!(writer.write(&[0]).unwrap(), 1);
|
|
||||||
assert_eq!(writer.position(), 1);
|
|
||||||
assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3);
|
|
||||||
assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4);
|
|
||||||
assert_eq!(writer.position(), 8);
|
|
||||||
assert_eq!(writer.write(&[]).unwrap(), 0);
|
|
||||||
assert_eq!(writer.position(), 8);
|
|
||||||
|
|
||||||
assert_eq!(writer.write(&[8, 9]).unwrap(), 1);
|
|
||||||
assert_eq!(writer.write(&[10]).unwrap(), 0);
|
|
||||||
let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8];
|
|
||||||
assert_eq!(&**writer.get_ref(), b);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_box_slice_writer_vectored() {
|
|
||||||
let mut writer = Cursor::new(vec![0u8; 9].into_boxed_slice());
|
|
||||||
assert_eq!(writer.position(), 0);
|
|
||||||
assert_eq!(writer.write_vectored(&[IoSlice::new(&[0])]).unwrap(), 1);
|
|
||||||
assert_eq!(writer.position(), 1);
|
|
||||||
assert_eq!(
|
|
||||||
writer
|
|
||||||
.write_vectored(&[IoSlice::new(&[1, 2, 3]), IoSlice::new(&[4, 5, 6, 7]),])
|
|
||||||
.unwrap(),
|
|
||||||
7,
|
|
||||||
);
|
|
||||||
assert_eq!(writer.position(), 8);
|
|
||||||
assert_eq!(writer.write_vectored(&[]).unwrap(), 0);
|
|
||||||
assert_eq!(writer.position(), 8);
|
|
||||||
|
|
||||||
assert_eq!(writer.write_vectored(&[IoSlice::new(&[8, 9])]).unwrap(), 1);
|
|
||||||
assert_eq!(writer.write_vectored(&[IoSlice::new(&[10])]).unwrap(), 0);
|
|
||||||
let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8];
|
|
||||||
assert_eq!(&**writer.get_ref(), b);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_buf_writer() {
|
|
||||||
let mut buf = [0 as u8; 9];
|
|
||||||
{
|
|
||||||
let mut writer = Cursor::new(&mut buf[..]);
|
|
||||||
assert_eq!(writer.position(), 0);
|
|
||||||
assert_eq!(writer.write(&[0]).unwrap(), 1);
|
|
||||||
assert_eq!(writer.position(), 1);
|
|
||||||
assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3);
|
|
||||||
assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4);
|
|
||||||
assert_eq!(writer.position(), 8);
|
|
||||||
assert_eq!(writer.write(&[]).unwrap(), 0);
|
|
||||||
assert_eq!(writer.position(), 8);
|
|
||||||
|
|
||||||
assert_eq!(writer.write(&[8, 9]).unwrap(), 1);
|
|
||||||
assert_eq!(writer.write(&[10]).unwrap(), 0);
|
|
||||||
}
|
|
||||||
let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8];
|
|
||||||
assert_eq!(buf, b);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_buf_writer_vectored() {
|
|
||||||
let mut buf = [0 as u8; 9];
|
|
||||||
{
|
|
||||||
let mut writer = Cursor::new(&mut buf[..]);
|
|
||||||
assert_eq!(writer.position(), 0);
|
|
||||||
assert_eq!(writer.write_vectored(&[IoSlice::new(&[0])]).unwrap(), 1);
|
|
||||||
assert_eq!(writer.position(), 1);
|
|
||||||
assert_eq!(
|
|
||||||
writer
|
|
||||||
.write_vectored(&[IoSlice::new(&[1, 2, 3]), IoSlice::new(&[4, 5, 6, 7])],)
|
|
||||||
.unwrap(),
|
|
||||||
7,
|
|
||||||
);
|
|
||||||
assert_eq!(writer.position(), 8);
|
|
||||||
assert_eq!(writer.write_vectored(&[]).unwrap(), 0);
|
|
||||||
assert_eq!(writer.position(), 8);
|
|
||||||
|
|
||||||
assert_eq!(writer.write_vectored(&[IoSlice::new(&[8, 9])]).unwrap(), 1);
|
|
||||||
assert_eq!(writer.write_vectored(&[IoSlice::new(&[10])]).unwrap(), 0);
|
|
||||||
}
|
|
||||||
let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8];
|
|
||||||
assert_eq!(buf, b);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_buf_writer_seek() {
|
|
||||||
let mut buf = [0 as u8; 8];
|
|
||||||
{
|
|
||||||
let mut writer = Cursor::new(&mut buf[..]);
|
|
||||||
assert_eq!(writer.position(), 0);
|
|
||||||
assert_eq!(writer.write(&[1]).unwrap(), 1);
|
|
||||||
assert_eq!(writer.position(), 1);
|
|
||||||
|
|
||||||
assert_eq!(writer.seek(SeekFrom::Start(2)).unwrap(), 2);
|
|
||||||
assert_eq!(writer.position(), 2);
|
|
||||||
assert_eq!(writer.write(&[2]).unwrap(), 1);
|
|
||||||
assert_eq!(writer.position(), 3);
|
|
||||||
|
|
||||||
assert_eq!(writer.seek(SeekFrom::Current(-2)).unwrap(), 1);
|
|
||||||
assert_eq!(writer.position(), 1);
|
|
||||||
assert_eq!(writer.write(&[3]).unwrap(), 1);
|
|
||||||
assert_eq!(writer.position(), 2);
|
|
||||||
|
|
||||||
assert_eq!(writer.seek(SeekFrom::End(-1)).unwrap(), 7);
|
|
||||||
assert_eq!(writer.position(), 7);
|
|
||||||
assert_eq!(writer.write(&[4]).unwrap(), 1);
|
|
||||||
assert_eq!(writer.position(), 8);
|
|
||||||
}
|
|
||||||
let b: &[_] = &[1, 3, 2, 0, 0, 0, 0, 4];
|
|
||||||
assert_eq!(buf, b);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_buf_writer_error() {
|
|
||||||
let mut buf = [0 as u8; 2];
|
|
||||||
let mut writer = Cursor::new(&mut buf[..]);
|
|
||||||
assert_eq!(writer.write(&[0]).unwrap(), 1);
|
|
||||||
assert_eq!(writer.write(&[0, 0]).unwrap(), 1);
|
|
||||||
assert_eq!(writer.write(&[0, 0]).unwrap(), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_mem_reader() {
|
|
||||||
let mut reader = Cursor::new(vec![0, 1, 2, 3, 4, 5, 6, 7]);
|
|
||||||
let mut buf = [];
|
|
||||||
assert_eq!(reader.read(&mut buf).unwrap(), 0);
|
|
||||||
assert_eq!(reader.position(), 0);
|
|
||||||
let mut buf = [0];
|
|
||||||
assert_eq!(reader.read(&mut buf).unwrap(), 1);
|
|
||||||
assert_eq!(reader.position(), 1);
|
|
||||||
let b: &[_] = &[0];
|
|
||||||
assert_eq!(buf, b);
|
|
||||||
let mut buf = [0; 4];
|
|
||||||
assert_eq!(reader.read(&mut buf).unwrap(), 4);
|
|
||||||
assert_eq!(reader.position(), 5);
|
|
||||||
let b: &[_] = &[1, 2, 3, 4];
|
|
||||||
assert_eq!(buf, b);
|
|
||||||
assert_eq!(reader.read(&mut buf).unwrap(), 3);
|
|
||||||
let b: &[_] = &[5, 6, 7];
|
|
||||||
assert_eq!(&buf[..3], b);
|
|
||||||
assert_eq!(reader.read(&mut buf).unwrap(), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_mem_reader_vectored() {
|
|
||||||
let mut reader = Cursor::new(vec![0, 1, 2, 3, 4, 5, 6, 7]);
|
|
||||||
let mut buf = [];
|
|
||||||
assert_eq!(reader.read_vectored(&mut [IoSliceMut::new(&mut buf)]).unwrap(), 0);
|
|
||||||
assert_eq!(reader.position(), 0);
|
|
||||||
let mut buf = [0];
|
|
||||||
assert_eq!(
|
|
||||||
reader
|
|
||||||
.read_vectored(&mut [IoSliceMut::new(&mut []), IoSliceMut::new(&mut buf),])
|
|
||||||
.unwrap(),
|
|
||||||
1,
|
|
||||||
);
|
|
||||||
assert_eq!(reader.position(), 1);
|
|
||||||
let b: &[_] = &[0];
|
|
||||||
assert_eq!(buf, b);
|
|
||||||
let mut buf1 = [0; 4];
|
|
||||||
let mut buf2 = [0; 4];
|
|
||||||
assert_eq!(
|
|
||||||
reader
|
|
||||||
.read_vectored(&mut [IoSliceMut::new(&mut buf1), IoSliceMut::new(&mut buf2),])
|
|
||||||
.unwrap(),
|
|
||||||
7,
|
|
||||||
);
|
|
||||||
let b1: &[_] = &[1, 2, 3, 4];
|
|
||||||
let b2: &[_] = &[5, 6, 7];
|
|
||||||
assert_eq!(buf1, b1);
|
|
||||||
assert_eq!(&buf2[..3], b2);
|
|
||||||
assert_eq!(reader.read(&mut buf).unwrap(), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_boxed_slice_reader() {
|
|
||||||
let mut reader = Cursor::new(vec![0, 1, 2, 3, 4, 5, 6, 7].into_boxed_slice());
|
|
||||||
let mut buf = [];
|
|
||||||
assert_eq!(reader.read(&mut buf).unwrap(), 0);
|
|
||||||
assert_eq!(reader.position(), 0);
|
|
||||||
let mut buf = [0];
|
|
||||||
assert_eq!(reader.read(&mut buf).unwrap(), 1);
|
|
||||||
assert_eq!(reader.position(), 1);
|
|
||||||
let b: &[_] = &[0];
|
|
||||||
assert_eq!(buf, b);
|
|
||||||
let mut buf = [0; 4];
|
|
||||||
assert_eq!(reader.read(&mut buf).unwrap(), 4);
|
|
||||||
assert_eq!(reader.position(), 5);
|
|
||||||
let b: &[_] = &[1, 2, 3, 4];
|
|
||||||
assert_eq!(buf, b);
|
|
||||||
assert_eq!(reader.read(&mut buf).unwrap(), 3);
|
|
||||||
let b: &[_] = &[5, 6, 7];
|
|
||||||
assert_eq!(&buf[..3], b);
|
|
||||||
assert_eq!(reader.read(&mut buf).unwrap(), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_boxed_slice_reader_vectored() {
|
|
||||||
let mut reader = Cursor::new(vec![0, 1, 2, 3, 4, 5, 6, 7].into_boxed_slice());
|
|
||||||
let mut buf = [];
|
|
||||||
assert_eq!(reader.read_vectored(&mut [IoSliceMut::new(&mut buf)]).unwrap(), 0);
|
|
||||||
assert_eq!(reader.position(), 0);
|
|
||||||
let mut buf = [0];
|
|
||||||
assert_eq!(
|
|
||||||
reader
|
|
||||||
.read_vectored(&mut [IoSliceMut::new(&mut []), IoSliceMut::new(&mut buf),])
|
|
||||||
.unwrap(),
|
|
||||||
1,
|
|
||||||
);
|
|
||||||
assert_eq!(reader.position(), 1);
|
|
||||||
let b: &[_] = &[0];
|
|
||||||
assert_eq!(buf, b);
|
|
||||||
let mut buf1 = [0; 4];
|
|
||||||
let mut buf2 = [0; 4];
|
|
||||||
assert_eq!(
|
|
||||||
reader
|
|
||||||
.read_vectored(&mut [IoSliceMut::new(&mut buf1), IoSliceMut::new(&mut buf2)],)
|
|
||||||
.unwrap(),
|
|
||||||
7,
|
|
||||||
);
|
|
||||||
let b1: &[_] = &[1, 2, 3, 4];
|
|
||||||
let b2: &[_] = &[5, 6, 7];
|
|
||||||
assert_eq!(buf1, b1);
|
|
||||||
assert_eq!(&buf2[..3], b2);
|
|
||||||
assert_eq!(reader.read(&mut buf).unwrap(), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn read_to_end() {
|
|
||||||
let mut reader = Cursor::new(vec![0, 1, 2, 3, 4, 5, 6, 7]);
|
|
||||||
let mut v = Vec::new();
|
|
||||||
reader.read_to_end(&mut v).unwrap();
|
|
||||||
assert_eq!(v, [0, 1, 2, 3, 4, 5, 6, 7]);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_slice_reader() {
|
|
||||||
let in_buf = vec![0, 1, 2, 3, 4, 5, 6, 7];
|
|
||||||
let reader = &mut &in_buf[..];
|
|
||||||
let mut buf = [];
|
|
||||||
assert_eq!(reader.read(&mut buf).unwrap(), 0);
|
|
||||||
let mut buf = [0];
|
|
||||||
assert_eq!(reader.read(&mut buf).unwrap(), 1);
|
|
||||||
assert_eq!(reader.len(), 7);
|
|
||||||
let b: &[_] = &[0];
|
|
||||||
assert_eq!(&buf[..], b);
|
|
||||||
let mut buf = [0; 4];
|
|
||||||
assert_eq!(reader.read(&mut buf).unwrap(), 4);
|
|
||||||
assert_eq!(reader.len(), 3);
|
|
||||||
let b: &[_] = &[1, 2, 3, 4];
|
|
||||||
assert_eq!(&buf[..], b);
|
|
||||||
assert_eq!(reader.read(&mut buf).unwrap(), 3);
|
|
||||||
let b: &[_] = &[5, 6, 7];
|
|
||||||
assert_eq!(&buf[..3], b);
|
|
||||||
assert_eq!(reader.read(&mut buf).unwrap(), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_slice_reader_vectored() {
|
|
||||||
let in_buf = vec![0, 1, 2, 3, 4, 5, 6, 7];
|
|
||||||
let reader = &mut &in_buf[..];
|
|
||||||
let mut buf = [];
|
|
||||||
assert_eq!(reader.read_vectored(&mut [IoSliceMut::new(&mut buf)]).unwrap(), 0);
|
|
||||||
let mut buf = [0];
|
|
||||||
assert_eq!(
|
|
||||||
reader
|
|
||||||
.read_vectored(&mut [IoSliceMut::new(&mut []), IoSliceMut::new(&mut buf),])
|
|
||||||
.unwrap(),
|
|
||||||
1,
|
|
||||||
);
|
|
||||||
assert_eq!(reader.len(), 7);
|
|
||||||
let b: &[_] = &[0];
|
|
||||||
assert_eq!(buf, b);
|
|
||||||
let mut buf1 = [0; 4];
|
|
||||||
let mut buf2 = [0; 4];
|
|
||||||
assert_eq!(
|
|
||||||
reader
|
|
||||||
.read_vectored(&mut [IoSliceMut::new(&mut buf1), IoSliceMut::new(&mut buf2)],)
|
|
||||||
.unwrap(),
|
|
||||||
7,
|
|
||||||
);
|
|
||||||
let b1: &[_] = &[1, 2, 3, 4];
|
|
||||||
let b2: &[_] = &[5, 6, 7];
|
|
||||||
assert_eq!(buf1, b1);
|
|
||||||
assert_eq!(&buf2[..3], b2);
|
|
||||||
assert_eq!(reader.read(&mut buf).unwrap(), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_read_exact() {
|
|
||||||
let in_buf = vec![0, 1, 2, 3, 4, 5, 6, 7];
|
|
||||||
let reader = &mut &in_buf[..];
|
|
||||||
let mut buf = [];
|
|
||||||
assert!(reader.read_exact(&mut buf).is_ok());
|
|
||||||
let mut buf = [8];
|
|
||||||
assert!(reader.read_exact(&mut buf).is_ok());
|
|
||||||
assert_eq!(buf[0], 0);
|
|
||||||
assert_eq!(reader.len(), 7);
|
|
||||||
let mut buf = [0, 0, 0, 0, 0, 0, 0];
|
|
||||||
assert!(reader.read_exact(&mut buf).is_ok());
|
|
||||||
assert_eq!(buf, [1, 2, 3, 4, 5, 6, 7]);
|
|
||||||
assert_eq!(reader.len(), 0);
|
|
||||||
let mut buf = [0];
|
|
||||||
assert!(reader.read_exact(&mut buf).is_err());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_buf_reader() {
|
|
||||||
let in_buf = vec![0, 1, 2, 3, 4, 5, 6, 7];
|
|
||||||
let mut reader = Cursor::new(&in_buf[..]);
|
|
||||||
let mut buf = [];
|
|
||||||
assert_eq!(reader.read(&mut buf).unwrap(), 0);
|
|
||||||
assert_eq!(reader.position(), 0);
|
|
||||||
let mut buf = [0];
|
|
||||||
assert_eq!(reader.read(&mut buf).unwrap(), 1);
|
|
||||||
assert_eq!(reader.position(), 1);
|
|
||||||
let b: &[_] = &[0];
|
|
||||||
assert_eq!(buf, b);
|
|
||||||
let mut buf = [0; 4];
|
|
||||||
assert_eq!(reader.read(&mut buf).unwrap(), 4);
|
|
||||||
assert_eq!(reader.position(), 5);
|
|
||||||
let b: &[_] = &[1, 2, 3, 4];
|
|
||||||
assert_eq!(buf, b);
|
|
||||||
assert_eq!(reader.read(&mut buf).unwrap(), 3);
|
|
||||||
let b: &[_] = &[5, 6, 7];
|
|
||||||
assert_eq!(&buf[..3], b);
|
|
||||||
assert_eq!(reader.read(&mut buf).unwrap(), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn seek_past_end() {
|
|
||||||
let buf = [0xff];
|
|
||||||
let mut r = Cursor::new(&buf[..]);
|
|
||||||
assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10);
|
|
||||||
assert_eq!(r.read(&mut [0]).unwrap(), 0);
|
|
||||||
|
|
||||||
let mut r = Cursor::new(vec![10]);
|
|
||||||
assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10);
|
|
||||||
assert_eq!(r.read(&mut [0]).unwrap(), 0);
|
|
||||||
|
|
||||||
let mut buf = [0];
|
|
||||||
let mut r = Cursor::new(&mut buf[..]);
|
|
||||||
assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10);
|
|
||||||
assert_eq!(r.write(&[3]).unwrap(), 0);
|
|
||||||
|
|
||||||
let mut r = Cursor::new(vec![10].into_boxed_slice());
|
|
||||||
assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10);
|
|
||||||
assert_eq!(r.write(&[3]).unwrap(), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn seek_past_i64() {
|
|
||||||
let buf = [0xff];
|
|
||||||
let mut r = Cursor::new(&buf[..]);
|
|
||||||
assert_eq!(r.seek(SeekFrom::Start(6)).unwrap(), 6);
|
|
||||||
assert_eq!(r.seek(SeekFrom::Current(0x7ffffffffffffff0)).unwrap(), 0x7ffffffffffffff6);
|
|
||||||
assert_eq!(r.seek(SeekFrom::Current(0x10)).unwrap(), 0x8000000000000006);
|
|
||||||
assert_eq!(r.seek(SeekFrom::Current(0)).unwrap(), 0x8000000000000006);
|
|
||||||
assert!(r.seek(SeekFrom::Current(0x7ffffffffffffffd)).is_err());
|
|
||||||
assert_eq!(r.seek(SeekFrom::Current(-0x8000000000000000)).unwrap(), 6);
|
|
||||||
|
|
||||||
let mut r = Cursor::new(vec![10]);
|
|
||||||
assert_eq!(r.seek(SeekFrom::Start(6)).unwrap(), 6);
|
|
||||||
assert_eq!(r.seek(SeekFrom::Current(0x7ffffffffffffff0)).unwrap(), 0x7ffffffffffffff6);
|
|
||||||
assert_eq!(r.seek(SeekFrom::Current(0x10)).unwrap(), 0x8000000000000006);
|
|
||||||
assert_eq!(r.seek(SeekFrom::Current(0)).unwrap(), 0x8000000000000006);
|
|
||||||
assert!(r.seek(SeekFrom::Current(0x7ffffffffffffffd)).is_err());
|
|
||||||
assert_eq!(r.seek(SeekFrom::Current(-0x8000000000000000)).unwrap(), 6);
|
|
||||||
|
|
||||||
let mut buf = [0];
|
|
||||||
let mut r = Cursor::new(&mut buf[..]);
|
|
||||||
assert_eq!(r.seek(SeekFrom::Start(6)).unwrap(), 6);
|
|
||||||
assert_eq!(r.seek(SeekFrom::Current(0x7ffffffffffffff0)).unwrap(), 0x7ffffffffffffff6);
|
|
||||||
assert_eq!(r.seek(SeekFrom::Current(0x10)).unwrap(), 0x8000000000000006);
|
|
||||||
assert_eq!(r.seek(SeekFrom::Current(0)).unwrap(), 0x8000000000000006);
|
|
||||||
assert!(r.seek(SeekFrom::Current(0x7ffffffffffffffd)).is_err());
|
|
||||||
assert_eq!(r.seek(SeekFrom::Current(-0x8000000000000000)).unwrap(), 6);
|
|
||||||
|
|
||||||
let mut r = Cursor::new(vec![10].into_boxed_slice());
|
|
||||||
assert_eq!(r.seek(SeekFrom::Start(6)).unwrap(), 6);
|
|
||||||
assert_eq!(r.seek(SeekFrom::Current(0x7ffffffffffffff0)).unwrap(), 0x7ffffffffffffff6);
|
|
||||||
assert_eq!(r.seek(SeekFrom::Current(0x10)).unwrap(), 0x8000000000000006);
|
|
||||||
assert_eq!(r.seek(SeekFrom::Current(0)).unwrap(), 0x8000000000000006);
|
|
||||||
assert!(r.seek(SeekFrom::Current(0x7ffffffffffffffd)).is_err());
|
|
||||||
assert_eq!(r.seek(SeekFrom::Current(-0x8000000000000000)).unwrap(), 6);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn seek_before_0() {
|
|
||||||
let buf = [0xff];
|
|
||||||
let mut r = Cursor::new(&buf[..]);
|
|
||||||
assert!(r.seek(SeekFrom::End(-2)).is_err());
|
|
||||||
|
|
||||||
let mut r = Cursor::new(vec![10]);
|
|
||||||
assert!(r.seek(SeekFrom::End(-2)).is_err());
|
|
||||||
|
|
||||||
let mut buf = [0];
|
|
||||||
let mut r = Cursor::new(&mut buf[..]);
|
|
||||||
assert!(r.seek(SeekFrom::End(-2)).is_err());
|
|
||||||
|
|
||||||
let mut r = Cursor::new(vec![10].into_boxed_slice());
|
|
||||||
assert!(r.seek(SeekFrom::End(-2)).is_err());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_seekable_mem_writer() {
|
|
||||||
let mut writer = Cursor::new(Vec::<u8>::new());
|
|
||||||
assert_eq!(writer.position(), 0);
|
|
||||||
assert_eq!(writer.write(&[0]).unwrap(), 1);
|
|
||||||
assert_eq!(writer.position(), 1);
|
|
||||||
assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3);
|
|
||||||
assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4);
|
|
||||||
assert_eq!(writer.position(), 8);
|
|
||||||
let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7];
|
|
||||||
assert_eq!(&writer.get_ref()[..], b);
|
|
||||||
|
|
||||||
assert_eq!(writer.seek(SeekFrom::Start(0)).unwrap(), 0);
|
|
||||||
assert_eq!(writer.position(), 0);
|
|
||||||
assert_eq!(writer.write(&[3, 4]).unwrap(), 2);
|
|
||||||
let b: &[_] = &[3, 4, 2, 3, 4, 5, 6, 7];
|
|
||||||
assert_eq!(&writer.get_ref()[..], b);
|
|
||||||
|
|
||||||
assert_eq!(writer.seek(SeekFrom::Current(1)).unwrap(), 3);
|
|
||||||
assert_eq!(writer.write(&[0, 1]).unwrap(), 2);
|
|
||||||
let b: &[_] = &[3, 4, 2, 0, 1, 5, 6, 7];
|
|
||||||
assert_eq!(&writer.get_ref()[..], b);
|
|
||||||
|
|
||||||
assert_eq!(writer.seek(SeekFrom::End(-1)).unwrap(), 7);
|
|
||||||
assert_eq!(writer.write(&[1, 2]).unwrap(), 2);
|
|
||||||
let b: &[_] = &[3, 4, 2, 0, 1, 5, 6, 1, 2];
|
|
||||||
assert_eq!(&writer.get_ref()[..], b);
|
|
||||||
|
|
||||||
assert_eq!(writer.seek(SeekFrom::End(1)).unwrap(), 10);
|
|
||||||
assert_eq!(writer.write(&[1]).unwrap(), 1);
|
|
||||||
let b: &[_] = &[3, 4, 2, 0, 1, 5, 6, 1, 2, 0, 1];
|
|
||||||
assert_eq!(&writer.get_ref()[..], b);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn vec_seek_past_end() {
|
|
||||||
let mut r = Cursor::new(Vec::new());
|
|
||||||
assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10);
|
|
||||||
assert_eq!(r.write(&[3]).unwrap(), 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn vec_seek_before_0() {
|
|
||||||
let mut r = Cursor::new(Vec::new());
|
|
||||||
assert!(r.seek(SeekFrom::End(-2)).is_err());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[cfg(target_pointer_width = "32")]
|
|
||||||
fn vec_seek_and_write_past_usize_max() {
|
|
||||||
let mut c = Cursor::new(Vec::new());
|
|
||||||
c.set_position(<usize>::max_value() as u64 + 1);
|
|
||||||
assert!(c.write_all(&[1, 2, 3]).is_err());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_partial_eq() {
|
|
||||||
assert_eq!(Cursor::new(Vec::<u8>::new()), Cursor::new(Vec::<u8>::new()));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_eq() {
|
|
||||||
struct AssertEq<T: Eq>(pub T);
|
|
||||||
|
|
||||||
let _: AssertEq<Cursor<Vec<u8>>> = AssertEq(Cursor::new(Vec::new()));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,551 +0,0 @@
|
||||||
#[cfg(feature="alloc")] use alloc::boxed::Box;
|
|
||||||
#[cfg(not(feature="alloc"))] use ::FakeBox as Box;
|
|
||||||
use core::convert::Into;
|
|
||||||
use core::fmt;
|
|
||||||
use core::marker::{Send, Sync};
|
|
||||||
use core::option::Option::{self, Some, None};
|
|
||||||
use core::result;
|
|
||||||
#[cfg(feature="collections")] use collections::string::String;
|
|
||||||
#[cfg(not(feature="collections"))] use ::ErrorString as String;
|
|
||||||
use core::convert::From;
|
|
||||||
|
|
||||||
/// A specialized [`Result`](../result/enum.Result.html) type for I/O
|
|
||||||
/// operations.
|
|
||||||
///
|
|
||||||
/// This type is broadly used across [`std::io`] for any operation which may
|
|
||||||
/// produce an error.
|
|
||||||
///
|
|
||||||
/// This typedef is generally used to avoid writing out [`io::Error`] directly and
|
|
||||||
/// is otherwise a direct mapping to [`Result`].
|
|
||||||
///
|
|
||||||
/// While usual Rust style is to import types directly, aliases of [`Result`]
|
|
||||||
/// often are not, to make it easier to distinguish between them. [`Result`] is
|
|
||||||
/// generally assumed to be [`std::result::Result`][`Result`], and so users of this alias
|
|
||||||
/// will generally use `io::Result` instead of shadowing the prelude's import
|
|
||||||
/// of [`std::result::Result`][`Result`].
|
|
||||||
///
|
|
||||||
/// [`std::io`]: ../io/index.html
|
|
||||||
/// [`io::Error`]: ../io/struct.Error.html
|
|
||||||
/// [`Result`]: ../result/enum.Result.html
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// A convenience function that bubbles an `io::Result` to its caller:
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use std::io;
|
|
||||||
///
|
|
||||||
/// fn get_string() -> io::Result<String> {
|
|
||||||
/// let mut buffer = String::new();
|
|
||||||
///
|
|
||||||
/// io::stdin().read_line(&mut buffer)?;
|
|
||||||
///
|
|
||||||
/// Ok(buffer)
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
pub type Result<T> = result::Result<T, Error>;
|
|
||||||
|
|
||||||
/// The error type for I/O operations of the [`Read`], [`Write`], [`Seek`], and
|
|
||||||
/// associated traits.
|
|
||||||
///
|
|
||||||
/// Errors mostly originate from the underlying OS, but custom instances of
|
|
||||||
/// `Error` can be created with crafted error messages and a particular value of
|
|
||||||
/// [`ErrorKind`].
|
|
||||||
///
|
|
||||||
/// [`Read`]: ../io/trait.Read.html
|
|
||||||
/// [`Write`]: ../io/trait.Write.html
|
|
||||||
/// [`Seek`]: ../io/trait.Seek.html
|
|
||||||
/// [`ErrorKind`]: enum.ErrorKind.html
|
|
||||||
pub struct Error {
|
|
||||||
repr: Repr,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Debug for Error {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
fmt::Debug::fmt(&self.repr, f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enum Repr {
|
|
||||||
Os(i32),
|
|
||||||
Simple(ErrorKind),
|
|
||||||
#[cfg(feature="alloc")]
|
|
||||||
Custom(Box<Custom>),
|
|
||||||
#[cfg(not(feature="alloc"))]
|
|
||||||
Custom(Custom),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct Custom {
|
|
||||||
kind: ErrorKind,
|
|
||||||
error: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A list specifying general categories of I/O error.
|
|
||||||
///
|
|
||||||
/// This list is intended to grow over time and it is not recommended to
|
|
||||||
/// exhaustively match against it.
|
|
||||||
///
|
|
||||||
/// It is used with the [`io::Error`] type.
|
|
||||||
///
|
|
||||||
/// [`io::Error`]: struct.Error.html
|
|
||||||
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
|
|
||||||
#[allow(deprecated)]
|
|
||||||
#[non_exhaustive]
|
|
||||||
pub enum ErrorKind {
|
|
||||||
/// An entity was not found, often a file.
|
|
||||||
NotFound,
|
|
||||||
/// The operation lacked the necessary privileges to complete.
|
|
||||||
PermissionDenied,
|
|
||||||
/// The connection was refused by the remote server.
|
|
||||||
ConnectionRefused,
|
|
||||||
/// The connection was reset by the remote server.
|
|
||||||
ConnectionReset,
|
|
||||||
/// The connection was aborted (terminated) by the remote server.
|
|
||||||
ConnectionAborted,
|
|
||||||
/// The network operation failed because it was not connected yet.
|
|
||||||
NotConnected,
|
|
||||||
/// A socket address could not be bound because the address is already in
|
|
||||||
/// use elsewhere.
|
|
||||||
AddrInUse,
|
|
||||||
/// A nonexistent interface was requested or the requested address was not
|
|
||||||
/// local.
|
|
||||||
AddrNotAvailable,
|
|
||||||
/// The operation failed because a pipe was closed.
|
|
||||||
BrokenPipe,
|
|
||||||
/// An entity already exists, often a file.
|
|
||||||
AlreadyExists,
|
|
||||||
/// The operation needs to block to complete, but the blocking operation was
|
|
||||||
/// requested to not occur.
|
|
||||||
WouldBlock,
|
|
||||||
/// A parameter was incorrect.
|
|
||||||
InvalidInput,
|
|
||||||
/// Data not valid for the operation were encountered.
|
|
||||||
///
|
|
||||||
/// Unlike [`InvalidInput`], this typically means that the operation
|
|
||||||
/// parameters were valid, however the error was caused by malformed
|
|
||||||
/// input data.
|
|
||||||
///
|
|
||||||
/// For example, a function that reads a file into a string will error with
|
|
||||||
/// `InvalidData` if the file's contents are not valid UTF-8.
|
|
||||||
///
|
|
||||||
/// [`InvalidInput`]: #variant.InvalidInput
|
|
||||||
InvalidData,
|
|
||||||
/// The I/O operation's timeout expired, causing it to be canceled.
|
|
||||||
TimedOut,
|
|
||||||
/// An error returned when an operation could not be completed because a
|
|
||||||
/// call to [`write`] returned [`Ok(0)`].
|
|
||||||
///
|
|
||||||
/// This typically means that an operation could only succeed if it wrote a
|
|
||||||
/// particular number of bytes but only a smaller number of bytes could be
|
|
||||||
/// written.
|
|
||||||
///
|
|
||||||
/// [`write`]: ../../std/io/trait.Write.html#tymethod.write
|
|
||||||
/// [`Ok(0)`]: ../../std/io/type.Result.html
|
|
||||||
WriteZero,
|
|
||||||
/// This operation was interrupted.
|
|
||||||
///
|
|
||||||
/// Interrupted operations can typically be retried.
|
|
||||||
Interrupted,
|
|
||||||
/// Any I/O error not part of this list.
|
|
||||||
Other,
|
|
||||||
|
|
||||||
/// An error returned when an operation could not be completed because an
|
|
||||||
/// "end of file" was reached prematurely.
|
|
||||||
///
|
|
||||||
/// This typically means that an operation could only succeed if it read a
|
|
||||||
/// particular number of bytes but only a smaller number of bytes could be
|
|
||||||
/// read.
|
|
||||||
UnexpectedEof,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ErrorKind {
|
|
||||||
pub(crate) fn as_str(&self) -> &'static str {
|
|
||||||
match *self {
|
|
||||||
ErrorKind::NotFound => "entity not found",
|
|
||||||
ErrorKind::PermissionDenied => "permission denied",
|
|
||||||
ErrorKind::ConnectionRefused => "connection refused",
|
|
||||||
ErrorKind::ConnectionReset => "connection reset",
|
|
||||||
ErrorKind::ConnectionAborted => "connection aborted",
|
|
||||||
ErrorKind::NotConnected => "not connected",
|
|
||||||
ErrorKind::AddrInUse => "address in use",
|
|
||||||
ErrorKind::AddrNotAvailable => "address not available",
|
|
||||||
ErrorKind::BrokenPipe => "broken pipe",
|
|
||||||
ErrorKind::AlreadyExists => "entity already exists",
|
|
||||||
ErrorKind::WouldBlock => "operation would block",
|
|
||||||
ErrorKind::InvalidInput => "invalid input parameter",
|
|
||||||
ErrorKind::InvalidData => "invalid data",
|
|
||||||
ErrorKind::TimedOut => "timed out",
|
|
||||||
ErrorKind::WriteZero => "write zero",
|
|
||||||
ErrorKind::Interrupted => "operation interrupted",
|
|
||||||
ErrorKind::Other => "other os error",
|
|
||||||
ErrorKind::UnexpectedEof => "unexpected end of file",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Intended for use for errors not exposed to the user, where allocating onto
|
|
||||||
/// the heap (for normal construction via Error::new) is too costly.
|
|
||||||
impl From<ErrorKind> for Error {
|
|
||||||
/// Converts an [`ErrorKind`] into an [`Error`].
|
|
||||||
///
|
|
||||||
/// This conversion allocates a new error with a simple representation of error kind.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use std::io::{Error, ErrorKind};
|
|
||||||
///
|
|
||||||
/// let not_found = ErrorKind::NotFound;
|
|
||||||
/// let error = Error::from(not_found);
|
|
||||||
/// assert_eq!("entity not found", format!("{}", error));
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// [`ErrorKind`]: ../../std/io/enum.ErrorKind.html
|
|
||||||
/// [`Error`]: ../../std/io/struct.Error.html
|
|
||||||
#[inline]
|
|
||||||
fn from(kind: ErrorKind) -> Error {
|
|
||||||
Error { repr: Repr::Simple(kind) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Error {
|
|
||||||
/// Creates a new I/O error from a known kind of error as well as an
|
|
||||||
/// arbitrary error payload.
|
|
||||||
///
|
|
||||||
/// This function is used to generically create I/O errors which do not
|
|
||||||
/// originate from the OS itself. The `error` argument is an arbitrary
|
|
||||||
/// payload which will be contained in this `Error`.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use std::io::{Error, ErrorKind};
|
|
||||||
///
|
|
||||||
/// // errors can be created from strings
|
|
||||||
/// let custom_error = Error::new(ErrorKind::Other, "oh no!");
|
|
||||||
///
|
|
||||||
/// // errors can also be created from other errors
|
|
||||||
/// let custom_error2 = Error::new(ErrorKind::Interrupted, custom_error);
|
|
||||||
/// ```
|
|
||||||
pub fn new<E>(kind: ErrorKind, error: E) -> Error
|
|
||||||
where
|
|
||||||
E: Into<String>,
|
|
||||||
{
|
|
||||||
Self::_new(kind, error.into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn _new(kind: ErrorKind, error: String) -> Error {
|
|
||||||
Error { repr: Repr::Custom(Box::new(Custom { kind, error })) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a new instance of an `Error` from a particular OS error code.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// On Linux:
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # if cfg!(target_os = "linux") {
|
|
||||||
/// use std::io;
|
|
||||||
///
|
|
||||||
/// let error = io::Error::from_raw_os_error(22);
|
|
||||||
/// assert_eq!(error.kind(), io::ErrorKind::InvalidInput);
|
|
||||||
/// # }
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// On Windows:
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # if cfg!(windows) {
|
|
||||||
/// use std::io;
|
|
||||||
///
|
|
||||||
/// let error = io::Error::from_raw_os_error(10022);
|
|
||||||
/// assert_eq!(error.kind(), io::ErrorKind::InvalidInput);
|
|
||||||
/// # }
|
|
||||||
/// ```
|
|
||||||
pub fn from_raw_os_error(code: i32) -> Error {
|
|
||||||
Error { repr: Repr::Os(code) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the OS error that this error represents (if any).
|
|
||||||
///
|
|
||||||
/// If this `Error` was constructed via `last_os_error` or
|
|
||||||
/// `from_raw_os_error`, then this function will return `Some`, otherwise
|
|
||||||
/// it will return `None`.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use std::io::{Error, ErrorKind};
|
|
||||||
///
|
|
||||||
/// fn print_os_error(err: &Error) {
|
|
||||||
/// if let Some(raw_os_err) = err.raw_os_error() {
|
|
||||||
/// println!("raw OS error: {:?}", raw_os_err);
|
|
||||||
/// } else {
|
|
||||||
/// println!("Not an OS error");
|
|
||||||
/// }
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// fn main() {
|
|
||||||
/// // Will print "raw OS error: ...".
|
|
||||||
/// print_os_error(&Error::last_os_error());
|
|
||||||
/// // Will print "Not an OS error".
|
|
||||||
/// print_os_error(&Error::new(ErrorKind::Other, "oh no!"));
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
pub fn raw_os_error(&self) -> Option<i32> {
|
|
||||||
match self.repr {
|
|
||||||
Repr::Os(i) => Some(i),
|
|
||||||
Repr::Custom(..) => None,
|
|
||||||
Repr::Simple(..) => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns a reference to the inner error wrapped by this error (if any).
|
|
||||||
///
|
|
||||||
/// If this `Error` was constructed via `new` then this function will
|
|
||||||
/// return `Some`, otherwise it will return `None`.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use std::io::{Error, ErrorKind};
|
|
||||||
///
|
|
||||||
/// fn print_error(err: &Error) {
|
|
||||||
/// if let Some(inner_err) = err.get_ref() {
|
|
||||||
/// println!("Inner error: {:?}", inner_err);
|
|
||||||
/// } else {
|
|
||||||
/// println!("No inner error");
|
|
||||||
/// }
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// fn main() {
|
|
||||||
/// // Will print "No inner error".
|
|
||||||
/// print_error(&Error::last_os_error());
|
|
||||||
/// // Will print "Inner error: ...".
|
|
||||||
/// print_error(&Error::new(ErrorKind::Other, "oh no!"));
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
pub fn get_ref(&self) -> Option<&String> {
|
|
||||||
match self.repr {
|
|
||||||
Repr::Os(..) => None,
|
|
||||||
Repr::Simple(..) => None,
|
|
||||||
Repr::Custom(ref c) => Some(&c.error),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns a mutable reference to the inner error wrapped by this error
|
|
||||||
/// (if any).
|
|
||||||
///
|
|
||||||
/// If this `Error` was constructed via `new` then this function will
|
|
||||||
/// return `Some`, otherwise it will return `None`.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use std::io::{Error, ErrorKind};
|
|
||||||
/// use std::{error, fmt};
|
|
||||||
/// use std::fmt::Display;
|
|
||||||
///
|
|
||||||
/// #[derive(Debug)]
|
|
||||||
/// struct MyError {
|
|
||||||
/// v: String,
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// impl MyError {
|
|
||||||
/// fn new() -> MyError {
|
|
||||||
/// MyError {
|
|
||||||
/// v: "oh no!".to_string()
|
|
||||||
/// }
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// fn change_message(&mut self, new_message: &str) {
|
|
||||||
/// self.v = new_message.to_string();
|
|
||||||
/// }
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// impl error::Error for MyError {}
|
|
||||||
///
|
|
||||||
/// impl Display for MyError {
|
|
||||||
/// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
/// write!(f, "MyError: {}", &self.v)
|
|
||||||
/// }
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// fn change_error(mut err: Error) -> Error {
|
|
||||||
/// if let Some(inner_err) = err.get_mut() {
|
|
||||||
/// inner_err.downcast_mut::<MyError>().unwrap().change_message("I've been changed!");
|
|
||||||
/// }
|
|
||||||
/// err
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// fn print_error(err: &Error) {
|
|
||||||
/// if let Some(inner_err) = err.get_ref() {
|
|
||||||
/// println!("Inner error: {}", inner_err);
|
|
||||||
/// } else {
|
|
||||||
/// println!("No inner error");
|
|
||||||
/// }
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// fn main() {
|
|
||||||
/// // Will print "No inner error".
|
|
||||||
/// print_error(&change_error(Error::last_os_error()));
|
|
||||||
/// // Will print "Inner error: ...".
|
|
||||||
/// print_error(&change_error(Error::new(ErrorKind::Other, MyError::new())));
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
pub fn get_mut(&mut self) -> Option<&mut String> {
|
|
||||||
match self.repr {
|
|
||||||
Repr::Os(..) => None,
|
|
||||||
Repr::Simple(..) => None,
|
|
||||||
Repr::Custom(ref mut c) => Some(&mut c.error),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Consumes the `Error`, returning its inner error (if any).
|
|
||||||
///
|
|
||||||
/// If this `Error` was constructed via `new` then this function will
|
|
||||||
/// return `Some`, otherwise it will return `None`.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use std::io::{Error, ErrorKind};
|
|
||||||
///
|
|
||||||
/// fn print_error(err: Error) {
|
|
||||||
/// if let Some(inner_err) = err.into_inner() {
|
|
||||||
/// println!("Inner error: {}", inner_err);
|
|
||||||
/// } else {
|
|
||||||
/// println!("No inner error");
|
|
||||||
/// }
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// fn main() {
|
|
||||||
/// // Will print "No inner error".
|
|
||||||
/// print_error(Error::last_os_error());
|
|
||||||
/// // Will print "Inner error: ...".
|
|
||||||
/// print_error(Error::new(ErrorKind::Other, "oh no!"));
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
pub fn into_inner(self) -> Option<String> {
|
|
||||||
match self.repr {
|
|
||||||
Repr::Os(..) => None,
|
|
||||||
Repr::Simple(..) => None,
|
|
||||||
Repr::Custom(c) => Some(c.error),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the corresponding `ErrorKind` for this error.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use std::io::{Error, ErrorKind};
|
|
||||||
///
|
|
||||||
/// fn print_error(err: Error) {
|
|
||||||
/// println!("{:?}", err.kind());
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// fn main() {
|
|
||||||
/// // Will print "No inner error".
|
|
||||||
/// print_error(Error::last_os_error());
|
|
||||||
/// // Will print "Inner error: ...".
|
|
||||||
/// print_error(Error::new(ErrorKind::AddrInUse, "oh no!"));
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
pub fn kind(&self) -> ErrorKind {
|
|
||||||
match self.repr {
|
|
||||||
Repr::Os(_code) => ErrorKind::Other,
|
|
||||||
Repr::Custom(ref c) => c.kind,
|
|
||||||
Repr::Simple(kind) => kind,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Debug for Repr {
|
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
match *self {
|
|
||||||
Repr::Os(code) => fmt
|
|
||||||
.debug_struct("Os")
|
|
||||||
.field("code", &code)
|
|
||||||
.finish(),
|
|
||||||
Repr::Custom(ref c) => fmt::Debug::fmt(&c, fmt),
|
|
||||||
Repr::Simple(kind) => fmt.debug_tuple("Kind").field(&kind).finish(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for Error {
|
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
match self.repr {
|
|
||||||
Repr::Os(code) => {
|
|
||||||
write!(fmt, "os error {}", code)
|
|
||||||
}
|
|
||||||
Repr::Custom(ref c) => c.error.fmt(fmt),
|
|
||||||
Repr::Simple(kind) => write!(fmt, "{}", kind.as_str()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn _assert_error_is_sync_send() {
|
|
||||||
fn _is_sync_send<T: Sync + Send>() {}
|
|
||||||
_is_sync_send::<Error>();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod test {
|
|
||||||
use super::{Custom, Error, ErrorKind, Repr};
|
|
||||||
use crate::error;
|
|
||||||
use crate::fmt;
|
|
||||||
use crate::sys::decode_error_kind;
|
|
||||||
use crate::sys::os::error_string;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_debug_error() {
|
|
||||||
let code = 6;
|
|
||||||
let msg = error_string(code);
|
|
||||||
let kind = decode_error_kind(code);
|
|
||||||
let err = Error {
|
|
||||||
repr: Repr::Custom(box Custom {
|
|
||||||
kind: ErrorKind::InvalidInput,
|
|
||||||
error: box Error { repr: super::Repr::Os(code) },
|
|
||||||
}),
|
|
||||||
};
|
|
||||||
let expected = format!(
|
|
||||||
"Custom {{ \
|
|
||||||
kind: InvalidInput, \
|
|
||||||
error: Os {{ \
|
|
||||||
code: {:?}, \
|
|
||||||
kind: {:?}, \
|
|
||||||
message: {:?} \
|
|
||||||
}} \
|
|
||||||
}}",
|
|
||||||
code, kind, msg
|
|
||||||
);
|
|
||||||
assert_eq!(format!("{:?}", err), expected);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_downcasting() {
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct TestError;
|
|
||||||
|
|
||||||
impl fmt::Display for TestError {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
f.write_str("asdf")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl error::Error for TestError {}
|
|
||||||
|
|
||||||
// we have to call all of these UFCS style right now since method
|
|
||||||
// resolution won't implicitly drop the Send+Sync bounds
|
|
||||||
let mut err = Error::new(ErrorKind::Other, TestError);
|
|
||||||
assert!(err.get_ref().unwrap().is::<TestError>());
|
|
||||||
assert_eq!("asdf", err.get_ref().unwrap().to_string());
|
|
||||||
assert!(err.get_mut().unwrap().is::<TestError>());
|
|
||||||
let extracted = err.into_inner().unwrap();
|
|
||||||
extracted.downcast::<TestError>().unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,378 +0,0 @@
|
||||||
use core::cmp;
|
|
||||||
use core::fmt;
|
|
||||||
use crate::io::{
|
|
||||||
self, Error, ErrorKind, Initializer, Read, Seek, SeekFrom, Write,
|
|
||||||
};
|
|
||||||
#[cfg(feature = "collections")] use crate::io::BufRead;
|
|
||||||
use core::mem;
|
|
||||||
|
|
||||||
#[cfg(feature="collections")]
|
|
||||||
use collections::{
|
|
||||||
vec::Vec,
|
|
||||||
string::String,
|
|
||||||
};
|
|
||||||
#[cfg(feature = "alloc")]
|
|
||||||
use alloc::boxed::Box;
|
|
||||||
|
|
||||||
// =============================================================================
|
|
||||||
// Forwarding implementations
|
|
||||||
|
|
||||||
impl<R: Read + ?Sized> Read for &mut R {
|
|
||||||
#[inline]
|
|
||||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
|
||||||
(**self).read(buf)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
unsafe fn initializer(&self) -> Initializer {
|
|
||||||
(**self).initializer()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature="collections")]
|
|
||||||
#[inline]
|
|
||||||
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
|
|
||||||
(**self).read_to_end(buf)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature="collections")]
|
|
||||||
#[inline]
|
|
||||||
fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
|
|
||||||
(**self).read_to_string(buf)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
|
|
||||||
(**self).read_exact(buf)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<W: Write + ?Sized> Write for &mut W {
|
|
||||||
#[inline]
|
|
||||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
|
||||||
(**self).write(buf)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn flush(&mut self) -> io::Result<()> {
|
|
||||||
(**self).flush()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
|
|
||||||
(**self).write_all(buf)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> {
|
|
||||||
(**self).write_fmt(fmt)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<S: Seek + ?Sized> Seek for &mut S {
|
|
||||||
#[inline]
|
|
||||||
fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
|
|
||||||
(**self).seek(pos)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[cfg(feature = "collections")]
|
|
||||||
impl<B: BufRead + ?Sized> BufRead for &mut B {
|
|
||||||
#[inline]
|
|
||||||
fn fill_buf(&mut self) -> io::Result<&[u8]> {
|
|
||||||
(**self).fill_buf()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn consume(&mut self, amt: usize) {
|
|
||||||
(**self).consume(amt)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature="collections")]
|
|
||||||
#[inline]
|
|
||||||
fn read_until(&mut self, byte: u8, buf: &mut Vec<u8>) -> io::Result<usize> {
|
|
||||||
(**self).read_until(byte, buf)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature="collections")]
|
|
||||||
#[inline]
|
|
||||||
fn read_line(&mut self, buf: &mut String) -> io::Result<usize> {
|
|
||||||
(**self).read_line(buf)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature="alloc")]
|
|
||||||
#[cfg(feature="collections")]
|
|
||||||
impl<R: Read + ?Sized> Read for Box<R> {
|
|
||||||
#[inline]
|
|
||||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
|
||||||
(**self).read(buf)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature="collections")]
|
|
||||||
#[inline]
|
|
||||||
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
|
|
||||||
(**self).read_to_end(buf)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature="collections")]
|
|
||||||
#[inline]
|
|
||||||
fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
|
|
||||||
(**self).read_to_string(buf)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
|
|
||||||
(**self).read_exact(buf)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[cfg(feature="alloc")]
|
|
||||||
#[cfg(feature="collections")]
|
|
||||||
impl<W: Write + ?Sized> Write for Box<W> {
|
|
||||||
#[inline]
|
|
||||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
|
||||||
(**self).write(buf)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn flush(&mut self) -> io::Result<()> {
|
|
||||||
(**self).flush()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
|
|
||||||
(**self).write_all(buf)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> {
|
|
||||||
(**self).write_fmt(fmt)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[cfg(feature="collections")]
|
|
||||||
impl<S: Seek + ?Sized> Seek for Box<S> {
|
|
||||||
#[inline]
|
|
||||||
fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
|
|
||||||
(**self).seek(pos)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[cfg(feature="collections")]
|
|
||||||
impl<B: BufRead + ?Sized> BufRead for Box<B> {
|
|
||||||
#[inline]
|
|
||||||
fn fill_buf(&mut self) -> io::Result<&[u8]> {
|
|
||||||
(**self).fill_buf()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn consume(&mut self, amt: usize) {
|
|
||||||
(**self).consume(amt)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn read_until(&mut self, byte: u8, buf: &mut Vec<u8>) -> io::Result<usize> {
|
|
||||||
(**self).read_until(byte, buf)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn read_line(&mut self, buf: &mut String) -> io::Result<usize> {
|
|
||||||
(**self).read_line(buf)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Used by panicking::default_hook
|
|
||||||
#[cfg(test)]
|
|
||||||
/// This impl is only used by printing logic, so any error returned is always
|
|
||||||
/// of kind `Other`, and should be ignored.
|
|
||||||
#[cfg(feature="collections")]
|
|
||||||
impl Write for Box<dyn (::realstd::io::Write) + Send> {
|
|
||||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
|
||||||
(**self).write(buf).map_err(|_| ErrorKind::Other.into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn flush(&mut self) -> io::Result<()> {
|
|
||||||
(**self).flush().map_err(|_| ErrorKind::Other.into())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// =============================================================================
|
|
||||||
// In-memory buffer implementations
|
|
||||||
|
|
||||||
/// Read is implemented for `&[u8]` by copying from the slice.
|
|
||||||
///
|
|
||||||
/// Note that reading updates the slice to point to the yet unread part.
|
|
||||||
/// The slice will be empty when EOF is reached.
|
|
||||||
impl Read for &[u8] {
|
|
||||||
#[inline]
|
|
||||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
|
||||||
let amt = cmp::min(buf.len(), self.len());
|
|
||||||
let (a, b) = self.split_at(amt);
|
|
||||||
|
|
||||||
// First check if the amount of bytes we want to read is small:
|
|
||||||
// `copy_from_slice` will generally expand to a call to `memcpy`, and
|
|
||||||
// for a single byte the overhead is significant.
|
|
||||||
if amt == 1 {
|
|
||||||
buf[0] = a[0];
|
|
||||||
} else {
|
|
||||||
buf[..amt].copy_from_slice(a);
|
|
||||||
}
|
|
||||||
|
|
||||||
*self = b;
|
|
||||||
Ok(amt)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
unsafe fn initializer(&self) -> Initializer {
|
|
||||||
Initializer::nop()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
|
|
||||||
if buf.len() > self.len() {
|
|
||||||
return Err(Error::new(ErrorKind::UnexpectedEof, "failed to fill whole buffer"));
|
|
||||||
}
|
|
||||||
let (a, b) = self.split_at(buf.len());
|
|
||||||
|
|
||||||
// First check if the amount of bytes we want to read is small:
|
|
||||||
// `copy_from_slice` will generally expand to a call to `memcpy`, and
|
|
||||||
// for a single byte the overhead is significant.
|
|
||||||
if buf.len() == 1 {
|
|
||||||
buf[0] = a[0];
|
|
||||||
} else {
|
|
||||||
buf.copy_from_slice(a);
|
|
||||||
}
|
|
||||||
|
|
||||||
*self = b;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature="collections")]
|
|
||||||
#[inline]
|
|
||||||
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
|
|
||||||
buf.extend_from_slice(*self);
|
|
||||||
let len = self.len();
|
|
||||||
*self = &self[len..];
|
|
||||||
Ok(len)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature="collections")]
|
|
||||||
impl BufRead for &[u8] {
|
|
||||||
#[inline]
|
|
||||||
fn fill_buf(&mut self) -> io::Result<&[u8]> {
|
|
||||||
Ok(*self)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn consume(&mut self, amt: usize) {
|
|
||||||
*self = &self[amt..];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Write is implemented for `&mut [u8]` by copying into the slice, overwriting
|
|
||||||
/// its data.
|
|
||||||
///
|
|
||||||
/// Note that writing updates the slice to point to the yet unwritten part.
|
|
||||||
/// The slice will be empty when it has been completely overwritten.
|
|
||||||
impl Write for &mut [u8] {
|
|
||||||
#[inline]
|
|
||||||
fn write(&mut self, data: &[u8]) -> io::Result<usize> {
|
|
||||||
let amt = cmp::min(data.len(), self.len());
|
|
||||||
let (a, b) = mem::replace(self, &mut []).split_at_mut(amt);
|
|
||||||
a.copy_from_slice(&data[..amt]);
|
|
||||||
*self = b;
|
|
||||||
Ok(amt)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn write_all(&mut self, data: &[u8]) -> io::Result<()> {
|
|
||||||
if self.write(data)? == data.len() {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(Error::new(ErrorKind::WriteZero, "failed to write whole buffer"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn flush(&mut self) -> io::Result<()> {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Write is implemented for `Vec<u8>` by appending to the vector.
|
|
||||||
/// The vector will grow as needed.
|
|
||||||
#[cfg(feature="collections")]
|
|
||||||
impl Write for Vec<u8> {
|
|
||||||
#[inline]
|
|
||||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
|
||||||
self.extend_from_slice(buf);
|
|
||||||
Ok(buf.len())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
|
|
||||||
self.extend_from_slice(buf);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn flush(&mut self) -> io::Result<()> {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use crate::io::prelude::*;
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn bench_read_slice(b: &mut test::Bencher) {
|
|
||||||
let buf = [5; 1024];
|
|
||||||
let mut dst = [0; 128];
|
|
||||||
|
|
||||||
b.iter(|| {
|
|
||||||
let mut rd = &buf[..];
|
|
||||||
for _ in 0..8 {
|
|
||||||
let _ = rd.read(&mut dst);
|
|
||||||
test::black_box(&dst);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn bench_write_slice(b: &mut test::Bencher) {
|
|
||||||
let mut buf = [0; 1024];
|
|
||||||
let src = [5; 128];
|
|
||||||
|
|
||||||
b.iter(|| {
|
|
||||||
let mut wr = &mut buf[..];
|
|
||||||
for _ in 0..8 {
|
|
||||||
let _ = wr.write_all(&src);
|
|
||||||
test::black_box(&wr);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn bench_read_vec(b: &mut test::Bencher) {
|
|
||||||
let buf = vec![5; 1024];
|
|
||||||
let mut dst = [0; 128];
|
|
||||||
|
|
||||||
b.iter(|| {
|
|
||||||
let mut rd = &buf[..];
|
|
||||||
for _ in 0..8 {
|
|
||||||
let _ = rd.read(&mut dst);
|
|
||||||
test::black_box(&dst);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn bench_write_vec(b: &mut test::Bencher) {
|
|
||||||
let mut buf = Vec::with_capacity(1024);
|
|
||||||
let src = [5; 128];
|
|
||||||
|
|
||||||
b.iter(|| {
|
|
||||||
let mut wr = &mut buf[..];
|
|
||||||
for _ in 0..8 {
|
|
||||||
let _ = wr.write_all(&src);
|
|
||||||
test::black_box(&wr);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,13 +0,0 @@
|
||||||
//! The I/O Prelude
|
|
||||||
//!
|
|
||||||
//! The purpose of this module is to alleviate imports of many common I/O traits
|
|
||||||
//! by adding a glob import to the top of I/O heavy modules:
|
|
||||||
//!
|
|
||||||
//! ```
|
|
||||||
//! # #![allow(unused_imports)]
|
|
||||||
//! use std::io::prelude::*;
|
|
||||||
//! ```
|
|
||||||
|
|
||||||
|
|
||||||
pub use super::{Read, Seek, Write};
|
|
||||||
#[cfg(feature = "collections")] pub use super::BufRead;
|
|
|
@ -1,269 +0,0 @@
|
||||||
#![allow(missing_copy_implementations)]
|
|
||||||
|
|
||||||
use core::fmt;
|
|
||||||
use core::mem;
|
|
||||||
use crate::io::{self, ErrorKind, Initializer, Read, Write};
|
|
||||||
#[cfg(feature = "collections")] use crate::io::BufRead;
|
|
||||||
|
|
||||||
/// Copies the entire contents of a reader into a writer.
|
|
||||||
///
|
|
||||||
/// This function will continuously read data from `reader` and then
|
|
||||||
/// write it into `writer` in a streaming fashion until `reader`
|
|
||||||
/// returns EOF.
|
|
||||||
///
|
|
||||||
/// On success, the total number of bytes that were copied from
|
|
||||||
/// `reader` to `writer` is returned.
|
|
||||||
///
|
|
||||||
/// If you’re wanting to copy the contents of one file to another and you’re
|
|
||||||
/// working with filesystem paths, see the [`fs::copy`] function.
|
|
||||||
///
|
|
||||||
/// [`fs::copy`]: ../fs/fn.copy.html
|
|
||||||
///
|
|
||||||
/// # Errors
|
|
||||||
///
|
|
||||||
/// This function will return an error immediately if any call to `read` or
|
|
||||||
/// `write` returns an error. All instances of `ErrorKind::Interrupted` are
|
|
||||||
/// handled by this function and the underlying operation is retried.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use std::io;
|
|
||||||
///
|
|
||||||
/// fn main() -> io::Result<()> {
|
|
||||||
/// let mut reader: &[u8] = b"hello";
|
|
||||||
/// let mut writer: Vec<u8> = vec![];
|
|
||||||
///
|
|
||||||
/// io::copy(&mut reader, &mut writer)?;
|
|
||||||
///
|
|
||||||
/// assert_eq!(&b"hello"[..], &writer[..]);
|
|
||||||
/// Ok(())
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
pub fn copy<R: ?Sized, W: ?Sized>(reader: &mut R, writer: &mut W) -> io::Result<u64>
|
|
||||||
where
|
|
||||||
R: Read,
|
|
||||||
W: Write,
|
|
||||||
{
|
|
||||||
let mut buf = unsafe {
|
|
||||||
#[allow(deprecated)]
|
|
||||||
let mut buf: [u8; super::DEFAULT_BUF_SIZE] = mem::uninitialized();
|
|
||||||
reader.initializer().initialize(&mut buf);
|
|
||||||
buf
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut written = 0;
|
|
||||||
loop {
|
|
||||||
let len = match reader.read(&mut buf) {
|
|
||||||
Ok(0) => return Ok(written),
|
|
||||||
Ok(len) => len,
|
|
||||||
Err(ref e) if e.kind() == ErrorKind::Interrupted => continue,
|
|
||||||
Err(e) => return Err(e),
|
|
||||||
};
|
|
||||||
writer.write_all(&buf[..len])?;
|
|
||||||
written += len as u64;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A reader which is always at EOF.
|
|
||||||
///
|
|
||||||
/// This struct is generally created by calling [`empty`]. Please see
|
|
||||||
/// the documentation of [`empty()`][`empty`] for more details.
|
|
||||||
///
|
|
||||||
/// [`empty`]: fn.empty.html
|
|
||||||
pub struct Empty {
|
|
||||||
_priv: (),
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Constructs a new handle to an empty reader.
|
|
||||||
///
|
|
||||||
/// All reads from the returned reader will return [`Ok`]`(0)`.
|
|
||||||
///
|
|
||||||
/// [`Ok`]: ../result/enum.Result.html#variant.Ok
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// A slightly sad example of not reading anything into a buffer:
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use std::io::{self, Read};
|
|
||||||
///
|
|
||||||
/// let mut buffer = String::new();
|
|
||||||
/// io::empty().read_to_string(&mut buffer).unwrap();
|
|
||||||
/// assert!(buffer.is_empty());
|
|
||||||
/// ```
|
|
||||||
pub fn empty() -> Empty {
|
|
||||||
Empty { _priv: () }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Read for Empty {
|
|
||||||
#[inline]
|
|
||||||
fn read(&mut self, _buf: &mut [u8]) -> io::Result<usize> {
|
|
||||||
Ok(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
unsafe fn initializer(&self) -> Initializer {
|
|
||||||
Initializer::nop()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature="collections")]
|
|
||||||
impl BufRead for Empty {
|
|
||||||
#[inline]
|
|
||||||
fn fill_buf(&mut self) -> io::Result<&[u8]> {
|
|
||||||
Ok(&[])
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
fn consume(&mut self, _n: usize) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Debug for Empty {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
f.pad("Empty { .. }")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A reader which yields one byte over and over and over and over and over and...
|
|
||||||
///
|
|
||||||
/// This struct is generally created by calling [`repeat`][repeat]. Please
|
|
||||||
/// see the documentation of `repeat()` for more details.
|
|
||||||
///
|
|
||||||
/// [repeat]: fn.repeat.html
|
|
||||||
pub struct Repeat {
|
|
||||||
byte: u8,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates an instance of a reader that infinitely repeats one byte.
|
|
||||||
///
|
|
||||||
/// All reads from this reader will succeed by filling the specified buffer with
|
|
||||||
/// the given byte.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use std::io::{self, Read};
|
|
||||||
///
|
|
||||||
/// let mut buffer = [0; 3];
|
|
||||||
/// io::repeat(0b101).read_exact(&mut buffer).unwrap();
|
|
||||||
/// assert_eq!(buffer, [0b101, 0b101, 0b101]);
|
|
||||||
/// ```
|
|
||||||
pub fn repeat(byte: u8) -> Repeat {
|
|
||||||
Repeat { byte }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Read for Repeat {
|
|
||||||
#[inline]
|
|
||||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
|
||||||
for slot in &mut *buf {
|
|
||||||
*slot = self.byte;
|
|
||||||
}
|
|
||||||
Ok(buf.len())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
unsafe fn initializer(&self) -> Initializer {
|
|
||||||
Initializer::nop()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Debug for Repeat {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
f.pad("Repeat { .. }")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A writer which will move data into the void.
|
|
||||||
///
|
|
||||||
/// This struct is generally created by calling [`sink`][sink]. Please
|
|
||||||
/// see the documentation of `sink()` for more details.
|
|
||||||
///
|
|
||||||
/// [sink]: fn.sink.html
|
|
||||||
pub struct Sink {
|
|
||||||
_priv: (),
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates an instance of a writer which will successfully consume all data.
|
|
||||||
///
|
|
||||||
/// All calls to `write` on the returned instance will return `Ok(buf.len())`
|
|
||||||
/// and the contents of the buffer will not be inspected.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// use std::io::{self, Write};
|
|
||||||
///
|
|
||||||
/// let buffer = vec![1, 2, 3, 5, 8];
|
|
||||||
/// let num_bytes = io::sink().write(&buffer).unwrap();
|
|
||||||
/// assert_eq!(num_bytes, 5);
|
|
||||||
/// ```
|
|
||||||
pub fn sink() -> Sink {
|
|
||||||
Sink { _priv: () }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Write for Sink {
|
|
||||||
#[inline]
|
|
||||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
|
||||||
Ok(buf.len())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn flush(&mut self) -> io::Result<()> {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Debug for Sink {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
f.pad("Sink { .. }")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use crate::io::prelude::*;
|
|
||||||
use crate::io::{copy, empty, repeat, sink};
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn copy_copies() {
|
|
||||||
let mut r = repeat(0).take(4);
|
|
||||||
let mut w = sink();
|
|
||||||
assert_eq!(copy(&mut r, &mut w).unwrap(), 4);
|
|
||||||
|
|
||||||
let mut r = repeat(0).take(1 << 17);
|
|
||||||
assert_eq!(copy(&mut r as &mut dyn Read, &mut w as &mut dyn Write).unwrap(), 1 << 17);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn sink_sinks() {
|
|
||||||
let mut s = sink();
|
|
||||||
assert_eq!(s.write(&[]).unwrap(), 0);
|
|
||||||
assert_eq!(s.write(&[0]).unwrap(), 1);
|
|
||||||
assert_eq!(s.write(&[0; 1024]).unwrap(), 1024);
|
|
||||||
assert_eq!(s.by_ref().write(&[0; 1024]).unwrap(), 1024);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn empty_reads() {
|
|
||||||
let mut e = empty();
|
|
||||||
assert_eq!(e.read(&mut []).unwrap(), 0);
|
|
||||||
assert_eq!(e.read(&mut [0]).unwrap(), 0);
|
|
||||||
assert_eq!(e.read(&mut [0; 1024]).unwrap(), 0);
|
|
||||||
assert_eq!(e.by_ref().read(&mut [0; 1024]).unwrap(), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn repeat_repeats() {
|
|
||||||
let mut r = repeat(4);
|
|
||||||
let mut b = [0; 1024];
|
|
||||||
assert_eq!(r.read(&mut b).unwrap(), 1024);
|
|
||||||
assert!(b.iter().all(|b| *b == 4));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn take_some_bytes() {
|
|
||||||
assert_eq!(repeat(4).take(100).bytes().count(), 100);
|
|
||||||
assert_eq!(repeat(4).take(100).bytes().next().unwrap().unwrap(), 4);
|
|
||||||
assert_eq!(repeat(1).take(10).chain(repeat(2).take(10)).bytes().count(), 20);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,51 +0,0 @@
|
||||||
//! <p id="core_io-show-docblock"></p>
|
|
||||||
//! This is just a listing of the functionality available in this crate. See
|
|
||||||
//! the [std documentation](https://doc.rust-lang.org/nightly/std/io/index.html)
|
|
||||||
//! for a full description of the functionality.
|
|
||||||
#![allow(stable_features,unused_features)]
|
|
||||||
#![feature(question_mark,const_fn,copy_from_slice,try_from,str_internals,align_offset,slice_internals)]
|
|
||||||
#![cfg_attr(any(feature="alloc",feature="collections"),feature(alloc))]
|
|
||||||
#![cfg_attr(pattern_guards,feature(bind_by_move_pattern_guards,nll))]
|
|
||||||
#![cfg_attr(non_exhaustive,feature(non_exhaustive))]
|
|
||||||
#![cfg_attr(unicode,feature(str_char))]
|
|
||||||
#![cfg_attr(unicode,feature(unicode))]
|
|
||||||
#![no_std]
|
|
||||||
|
|
||||||
#[cfg_attr(feature="collections",macro_use)]
|
|
||||||
#[cfg_attr(feature="collections",allow(unused_imports))]
|
|
||||||
#[cfg(feature="collections")] extern crate alloc as collections;
|
|
||||||
#[cfg(feature="alloc")] extern crate alloc;
|
|
||||||
#[cfg(rustc_unicode)]
|
|
||||||
extern crate rustc_unicode;
|
|
||||||
#[cfg(std_unicode)]
|
|
||||||
extern crate std_unicode;
|
|
||||||
|
|
||||||
#[cfg(not(feature="collections"))]
|
|
||||||
pub type ErrorString = &'static str;
|
|
||||||
|
|
||||||
// Provide Box::new wrapper
|
|
||||||
#[cfg(not(feature="alloc"))]
|
|
||||||
struct FakeBox<T>(core::marker::PhantomData<T>);
|
|
||||||
#[cfg(not(feature="alloc"))]
|
|
||||||
impl<T> FakeBox<T> {
|
|
||||||
fn new(val: T) -> T {
|
|
||||||
val
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Needed for older compilers, to ignore vec!/format! macros in tests
|
|
||||||
#[cfg(not(feature="collections"))]
|
|
||||||
#[allow(unused)]
|
|
||||||
macro_rules! vec (
|
|
||||||
( $ elem : expr ; $ n : expr ) => { () };
|
|
||||||
( $ ( $ x : expr ) , * ) => { () };
|
|
||||||
( $ ( $ x : expr , ) * ) => { () };
|
|
||||||
);
|
|
||||||
#[cfg(not(feature="collections"))]
|
|
||||||
#[allow(unused)]
|
|
||||||
macro_rules! format {
|
|
||||||
( $ ( $ arg : tt ) * ) => { () };
|
|
||||||
}
|
|
||||||
|
|
||||||
mod io;
|
|
||||||
pub use io::*;
|
|
|
@ -1,14 +1,12 @@
|
||||||
[package]
|
[package]
|
||||||
name = "libcortex_a9"
|
name = "libcortex_a9"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
authors = ["M-Labs"]
|
authors = ["Astro <astro@spaceboyz.net>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
target_zc706 = []
|
target_zc706 = []
|
||||||
target_cora_z7_10 = []
|
target_cora_z7_10 = []
|
||||||
target_redpitaya = []
|
|
||||||
power_saving = []
|
|
||||||
default = ["target_zc706"]
|
default = ["target_zc706"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
|
|
@ -33,44 +33,3 @@ pub fn dsb() {
|
||||||
pub fn isb() {
|
pub fn isb() {
|
||||||
unsafe { llvm_asm!("isb" :::: "volatile") }
|
unsafe { llvm_asm!("isb" :::: "volatile") }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Enable IRQ
|
|
||||||
#[inline]
|
|
||||||
pub unsafe fn enable_irq() {
|
|
||||||
llvm_asm!("cpsie i":::: "volatile");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Disable IRQ, return if IRQ was originally enabled.
|
|
||||||
#[inline]
|
|
||||||
pub unsafe fn enter_critical() -> bool {
|
|
||||||
let mut cpsr: u32;
|
|
||||||
llvm_asm!(
|
|
||||||
"mrs $0, cpsr
|
|
||||||
cpsid i"
|
|
||||||
: "=r"(cpsr) ::: "volatile");
|
|
||||||
(cpsr & (1 << 7)) == 0
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub unsafe fn exit_critical(enable: bool) {
|
|
||||||
// https://stackoverflow.com/questions/40019929/temporarily-disable-interrupts-on-arm
|
|
||||||
let mask: u32 = if enable {
|
|
||||||
1 << 7
|
|
||||||
} else {
|
|
||||||
0
|
|
||||||
};
|
|
||||||
llvm_asm!(
|
|
||||||
"mrs r1, cpsr
|
|
||||||
bic r1, r1, $0
|
|
||||||
msr cpsr_c, r1"
|
|
||||||
:: "r"(mask) : "r1");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Exiting IRQ
|
|
||||||
#[inline]
|
|
||||||
pub unsafe fn exit_irq() {
|
|
||||||
llvm_asm!("
|
|
||||||
mrs r0, SPSR
|
|
||||||
msr CPSR, r0
|
|
||||||
" ::: "r0");
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
use super::asm::{dmb, dsb};
|
use super::asm::{dmb, dsb};
|
||||||
use super::l2c::*;
|
|
||||||
|
|
||||||
/// Invalidate TLBs
|
/// Invalidate TLBs
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
@ -53,9 +52,10 @@ pub fn dccisw(setway: u32) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// A made-up "instruction": invalidate all of the L1 D-Cache
|
/// A made-up "instruction": invalidate all of the L1 D-Cache
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn dciall_l1() {
|
pub fn dciall() {
|
||||||
// the cache associativity could be read from a register, but will
|
// the cache associativity could be read from a register, but will
|
||||||
// always be 4 in L1 data cache of a cortex a9
|
// always be 4 in L1 data cache of a cortex a9
|
||||||
let ways = 4;
|
let ways = 4;
|
||||||
|
@ -80,17 +80,9 @@ pub fn dciall_l1() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A made-up "instruction": invalidate all of the L1 L2 D-Cache
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn dciall() {
|
|
||||||
dmb();
|
|
||||||
l2_cache_invalidate_all();
|
|
||||||
dciall_l1();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A made-up "instruction": flush and invalidate all of the L1 D-Cache
|
/// A made-up "instruction": flush and invalidate all of the L1 D-Cache
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn dcciall_l1() {
|
pub fn dcciall() {
|
||||||
// the cache associativity could be read from a register, but will
|
// the cache associativity could be read from a register, but will
|
||||||
// always be 4 in L1 data cache of a cortex a9
|
// always be 4 in L1 data cache of a cortex a9
|
||||||
let ways = 4;
|
let ways = 4;
|
||||||
|
@ -115,15 +107,6 @@ pub fn dcciall_l1() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn dcciall() {
|
|
||||||
dmb();
|
|
||||||
dcciall_l1();
|
|
||||||
dsb();
|
|
||||||
l2_cache_clean_invalidate_all();
|
|
||||||
dcciall_l1();
|
|
||||||
dsb();
|
|
||||||
}
|
|
||||||
|
|
||||||
const CACHE_LINE: usize = 0x20;
|
const CACHE_LINE: usize = 0x20;
|
||||||
const CACHE_LINE_MASK: usize = CACHE_LINE - 1;
|
const CACHE_LINE_MASK: usize = CACHE_LINE - 1;
|
||||||
|
@ -162,16 +145,7 @@ pub fn dccimvac(addr: usize) {
|
||||||
|
|
||||||
/// Data cache clean and invalidate for an object.
|
/// Data cache clean and invalidate for an object.
|
||||||
pub fn dcci<T>(object: &T) {
|
pub fn dcci<T>(object: &T) {
|
||||||
// ref: L2C310 TRM 3.3.10
|
|
||||||
dmb();
|
dmb();
|
||||||
for addr in object_cache_line_addrs(object) {
|
|
||||||
dccmvac(addr);
|
|
||||||
}
|
|
||||||
dsb();
|
|
||||||
for addr in object_cache_line_addrs(object) {
|
|
||||||
l2_cache_clean_invalidate(addr);
|
|
||||||
}
|
|
||||||
l2_cache_sync();
|
|
||||||
for addr in object_cache_line_addrs(object) {
|
for addr in object_cache_line_addrs(object) {
|
||||||
dccimvac(addr);
|
dccimvac(addr);
|
||||||
}
|
}
|
||||||
|
@ -180,14 +154,6 @@ pub fn dcci<T>(object: &T) {
|
||||||
|
|
||||||
pub fn dcci_slice<T>(slice: &[T]) {
|
pub fn dcci_slice<T>(slice: &[T]) {
|
||||||
dmb();
|
dmb();
|
||||||
for addr in slice_cache_line_addrs(slice) {
|
|
||||||
dccmvac(addr);
|
|
||||||
}
|
|
||||||
dsb();
|
|
||||||
for addr in slice_cache_line_addrs(slice) {
|
|
||||||
l2_cache_clean_invalidate(addr);
|
|
||||||
}
|
|
||||||
l2_cache_sync();
|
|
||||||
for addr in slice_cache_line_addrs(slice) {
|
for addr in slice_cache_line_addrs(slice) {
|
||||||
dccimvac(addr);
|
dccimvac(addr);
|
||||||
}
|
}
|
||||||
|
@ -209,28 +175,17 @@ pub fn dcc<T>(object: &T) {
|
||||||
dccmvac(addr);
|
dccmvac(addr);
|
||||||
}
|
}
|
||||||
dsb();
|
dsb();
|
||||||
for addr in object_cache_line_addrs(object) {
|
|
||||||
l2_cache_clean(addr);
|
|
||||||
}
|
|
||||||
l2_cache_sync();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Data cache clean for an object. Panics if not properly
|
/// Data cache clean for an object. Panics if not properly
|
||||||
/// aligned and properly sized to be contained in an exact number of
|
/// aligned and properly sized to be contained in an exact number of
|
||||||
/// cache lines.
|
/// cache lines.
|
||||||
pub fn dcc_slice<T>(slice: &[T]) {
|
pub fn dcc_slice<T>(slice: &[T]) {
|
||||||
if slice.len() == 0 {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
dmb();
|
dmb();
|
||||||
for addr in slice_cache_line_addrs(slice) {
|
for addr in slice_cache_line_addrs(slice) {
|
||||||
dccmvac(addr);
|
dccmvac(addr);
|
||||||
}
|
}
|
||||||
dsb();
|
dsb();
|
||||||
for addr in slice_cache_line_addrs(slice) {
|
|
||||||
l2_cache_clean(addr);
|
|
||||||
}
|
|
||||||
l2_cache_sync();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Data cache invalidate by memory virtual address. This and
|
/// Data cache invalidate by memory virtual address. This and
|
||||||
|
@ -242,7 +197,7 @@ pub unsafe fn dcimvac(addr: usize) {
|
||||||
llvm_asm!("mcr p15, 0, $0, c7, c6, 1" :: "r" (addr) :: "volatile");
|
llvm_asm!("mcr p15, 0, $0, c7, c6, 1" :: "r" (addr) :: "volatile");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Data cache clean and invalidate for an object.
|
/// Data cache invalidate for an object.
|
||||||
pub unsafe fn dci<T>(object: &mut T) {
|
pub unsafe fn dci<T>(object: &mut T) {
|
||||||
let first_addr = object as *const _ as usize;
|
let first_addr = object as *const _ as usize;
|
||||||
let beyond_addr = (object as *const _ as usize) + core::mem::size_of_val(object);
|
let beyond_addr = (object as *const _ as usize) + core::mem::size_of_val(object);
|
||||||
|
@ -250,10 +205,6 @@ pub unsafe fn dci<T>(object: &mut T) {
|
||||||
assert_eq!(beyond_addr & CACHE_LINE_MASK, 0, "dci object beyond_addr must be aligned");
|
assert_eq!(beyond_addr & CACHE_LINE_MASK, 0, "dci object beyond_addr must be aligned");
|
||||||
|
|
||||||
dmb();
|
dmb();
|
||||||
for addr in (first_addr..beyond_addr).step_by(CACHE_LINE) {
|
|
||||||
l2_cache_invalidate(addr);
|
|
||||||
}
|
|
||||||
l2_cache_sync();
|
|
||||||
for addr in (first_addr..beyond_addr).step_by(CACHE_LINE) {
|
for addr in (first_addr..beyond_addr).step_by(CACHE_LINE) {
|
||||||
dcimvac(addr);
|
dcimvac(addr);
|
||||||
}
|
}
|
||||||
|
@ -268,10 +219,6 @@ pub unsafe fn dci_slice<T>(slice: &mut [T]) {
|
||||||
assert_eq!(beyond_addr & CACHE_LINE_MASK, 0, "dci slice beyond_addr must be aligned");
|
assert_eq!(beyond_addr & CACHE_LINE_MASK, 0, "dci slice beyond_addr must be aligned");
|
||||||
|
|
||||||
dmb();
|
dmb();
|
||||||
for addr in (first_addr..beyond_addr).step_by(CACHE_LINE) {
|
|
||||||
l2_cache_invalidate(addr);
|
|
||||||
}
|
|
||||||
l2_cache_sync();
|
|
||||||
for addr in (first_addr..beyond_addr).step_by(CACHE_LINE) {
|
for addr in (first_addr..beyond_addr).step_by(CACHE_LINE) {
|
||||||
dcimvac(addr);
|
dcimvac(addr);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +0,0 @@
|
||||||
/// Enable FPU in the current core.
|
|
||||||
pub fn enable_fpu() {
|
|
||||||
unsafe {
|
|
||||||
llvm_asm!("
|
|
||||||
mrc p15, 0, r1, c1, c0, 2
|
|
||||||
orr r1, r1, (0b1111<<20)
|
|
||||||
mcr p15, 0, r1, c1, c0, 2
|
|
||||||
|
|
||||||
vmrs r1, fpexc
|
|
||||||
orr r1, r1, (1<<30)
|
|
||||||
vmsr fpexc, r1
|
|
||||||
":::"r1");
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,328 +0,0 @@
|
||||||
use libregister::{register, register_at, register_bit, register_bits, RegisterRW, RegisterR, RegisterW};
|
|
||||||
use super::asm::dmb;
|
|
||||||
use volatile_register::RW;
|
|
||||||
|
|
||||||
pub fn enable_l2_cache() {
|
|
||||||
dmb();
|
|
||||||
let regs = RegisterBlock::new();
|
|
||||||
// disable L2 cache
|
|
||||||
regs.reg1_control.modify(|_, w| w.l2_enable(false));
|
|
||||||
|
|
||||||
regs.reg15_prefetch_ctrl.modify(|_, w|
|
|
||||||
w.instr_prefetch_en(true)
|
|
||||||
.data_prefetch_en(true)
|
|
||||||
.double_linefill_en(true)
|
|
||||||
.incr_double_linefill_en(true)
|
|
||||||
.pref_drop_en(true)
|
|
||||||
);
|
|
||||||
regs.reg1_aux_control.modify(|_, w| {
|
|
||||||
w.early_bresp_en(true)
|
|
||||||
.instr_prefetch_en(true)
|
|
||||||
.data_prefetch_en(true)
|
|
||||||
.cache_replace_policy(true)
|
|
||||||
.way_size(3)
|
|
||||||
});
|
|
||||||
regs.reg1_tag_ram_control.modify(|_, w| w.ram_wr_access_lat(1).ram_rd_access_lat(1).ram_setup_lat(1));
|
|
||||||
regs.reg1_data_ram_control.modify(|_, w| w.ram_wr_access_lat(1).ram_rd_access_lat(2).ram_setup_lat(1));
|
|
||||||
// invalidate L2 ways
|
|
||||||
unsafe {
|
|
||||||
regs.reg7_inv_way.write(0xFFFF);
|
|
||||||
}
|
|
||||||
// poll for completion
|
|
||||||
while regs.reg7_cache_sync.read().c() {}
|
|
||||||
// write to a magic memory location with a magic sequence
|
|
||||||
// required in UG585 Section 3.4.10 Initialization Sequence
|
|
||||||
unsafe {
|
|
||||||
core::ptr::write_volatile(0xF8000008usize as *mut u32, 0xDF0D);
|
|
||||||
core::ptr::write_volatile(0xF8000A1Cusize as *mut u32, 0x020202);
|
|
||||||
core::ptr::write_volatile(0xF8000004usize as *mut u32, 0x767B);
|
|
||||||
}
|
|
||||||
regs.reg1_control.modify(|_, w| w.l2_enable(true));
|
|
||||||
dmb();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn l2_cache_invalidate_all() {
|
|
||||||
let regs = RegisterBlock::new();
|
|
||||||
unsafe {
|
|
||||||
regs.reg7_inv_way.write(0xFFFF);
|
|
||||||
}
|
|
||||||
// poll for completion
|
|
||||||
while regs.reg7_cache_sync.read().c() {}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn l2_cache_clean_all() {
|
|
||||||
let regs = RegisterBlock::new();
|
|
||||||
unsafe {
|
|
||||||
regs.reg7_clean_way.write(0xFFFF);
|
|
||||||
}
|
|
||||||
// poll for completion
|
|
||||||
while regs.reg7_cache_sync.read().c() {}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn l2_cache_clean_invalidate_all() {
|
|
||||||
let regs = RegisterBlock::new();
|
|
||||||
unsafe {
|
|
||||||
regs.reg7_clean_inv_way.write(0xFFFF);
|
|
||||||
}
|
|
||||||
// poll for completion
|
|
||||||
while regs.reg7_cache_sync.read().c() {}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// L2 cache sync, similar to dsb for L1 cache
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn l2_cache_sync() {
|
|
||||||
let regs = RegisterBlock::new();
|
|
||||||
regs.reg7_cache_sync.write(Reg7CacheSync::zeroed().c(false));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn l2_cache_clean(addr: usize) {
|
|
||||||
let regs = RegisterBlock::new();
|
|
||||||
unsafe {
|
|
||||||
regs.reg7_clean_pa.write(addr as u32);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn l2_cache_invalidate(addr: usize) {
|
|
||||||
let regs = RegisterBlock::new();
|
|
||||||
unsafe {
|
|
||||||
regs.reg7_inv_pa.write(addr as u32);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn l2_cache_clean_invalidate(addr: usize) {
|
|
||||||
let regs = RegisterBlock::new();
|
|
||||||
unsafe {
|
|
||||||
regs.reg7_clean_inv_pa.write(addr as u32);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[repr(C)]
|
|
||||||
struct RegisterBlock {
|
|
||||||
/// cache ID register, Returns the 32-bit device ID code it reads off the CACHEID input bus.
|
|
||||||
/// The value is specified by the system integrator. Reset value: 0x410000c8
|
|
||||||
pub reg0_cache_id: Reg0CacheId,
|
|
||||||
/// cache type register, Returns the 32-bit cache type. Reset value: 0x1c100100
|
|
||||||
pub reg0_cache_type: Reg0CacheType,
|
|
||||||
unused0: [u32; 62],
|
|
||||||
/// control register, reset value: 0x0
|
|
||||||
pub reg1_control: Reg1Control,
|
|
||||||
/// auxilary control register, reset value: 0x02020000
|
|
||||||
pub reg1_aux_control: Reg1AuxControl,
|
|
||||||
/// Configures Tag RAM latencies
|
|
||||||
pub reg1_tag_ram_control: Reg1TagRamControl,
|
|
||||||
/// configures data RAM latencies
|
|
||||||
pub reg1_data_ram_control: Reg1DataRamControl,
|
|
||||||
unused1: [u32; 60],
|
|
||||||
/// Permits the event counters to be enabled and reset.
|
|
||||||
pub reg2_ev_counter_ctrl: Reg2EvCounterCtrl,
|
|
||||||
/// Enables event counter 1 to be driven by a specific event. Counter 1 increments when the
|
|
||||||
/// event occurs.
|
|
||||||
pub reg2_ev_counter1_cfg: Reg2EvCounter1Cfg,
|
|
||||||
/// Enables event counter 0 to be driven by a specific event. Counter 0 increments when the
|
|
||||||
/// event occurs.
|
|
||||||
pub reg2_ev_counter0_cfg: Reg2EvCounter0Cfg,
|
|
||||||
/// Enable the programmer to read off the counter value. The counter counts an event as
|
|
||||||
/// specified by the Counter Configuration Registers. The counter can be preloaded if counting
|
|
||||||
/// is disabled and reset by the Event Counter Control Register.
|
|
||||||
pub reg2_ev_counter1: RW<u32>,
|
|
||||||
/// Enable the programmer to read off the counter value. The counter counts an event as
|
|
||||||
/// specified by the Counter Configuration Registers. The counter can be preloaded if counting
|
|
||||||
/// is disabled and reset by the Event Counter Control Register.
|
|
||||||
pub reg2_ev_counter0: RW<u32>,
|
|
||||||
/// This register enables or masks interrupts from being triggered on the external pins of the
|
|
||||||
/// cache controller. Figure 3-8 on page 3-17 shows the register bit assignments. The bit
|
|
||||||
/// assignments enables the masking of the interrupts on both their individual outputs and the
|
|
||||||
/// combined L2CCINTR line. Clearing a bit by writing a 0, disables the interrupt triggering on
|
|
||||||
/// that pin. All bits are cleared by a reset. You must write to the register bits with a 1 to
|
|
||||||
/// enable the generation of interrupts. 1 = Enabled. 0 = Masked. This is the default.
|
|
||||||
pub reg2_int_mask: Reg2IntMask,
|
|
||||||
/// This register is a read-only.It returns the masked interrupt status. This register can be
|
|
||||||
/// accessed by secure and non-secure operations. The register gives an AND function of the raw
|
|
||||||
/// interrupt status with the values of the interrupt mask register. All the bits are cleared
|
|
||||||
/// by a reset. A write to this register is ignored. Bits read can be HIGH or LOW: HIGH If the
|
|
||||||
/// bits read HIGH, they reflect the status of the input lines triggering an interrupt. LOW If
|
|
||||||
/// the bits read LOW, either no interrupt has been generated, or the interrupt is masked.
|
|
||||||
pub reg2_int_mask_status: Reg2IntMaskStatus,
|
|
||||||
/// The Raw Interrupt Status Register enables the interrupt status that excludes the masking
|
|
||||||
/// logic. Bits read can be HIGH or LOW: HIGH If the bits read HIGH, they reflect the status of
|
|
||||||
/// the input lines triggering an interrupt. LOW If the bits read LOW, no interrupt has been
|
|
||||||
/// generated.
|
|
||||||
pub reg2_int_raw_status: Reg2IntRawStatus,
|
|
||||||
/// Clears the Raw Interrupt Status Register bits. When a bit is written as 1, it clears the
|
|
||||||
/// corresponding bit in the Raw Interrupt Status Register. When a bit is written as 0, it has
|
|
||||||
/// no effect
|
|
||||||
pub reg2_int_clear: Reg2IntClear,
|
|
||||||
unused2: [u32; 323],
|
|
||||||
/// Drain the STB. Operation complete when all buffers, LRB, LFB, STB, and EB, are empty
|
|
||||||
pub reg7_cache_sync: Reg7CacheSync,
|
|
||||||
unused3: [u32; 15],
|
|
||||||
/// Invalidate Line by PA: Specific L2 cache line is marked as not valid
|
|
||||||
pub reg7_inv_pa: RW<u32>,
|
|
||||||
unused4: [u32; 2],
|
|
||||||
/// Invalidate by Way Invalidate all data in specified ways, including dirty data. An
|
|
||||||
/// Invalidate by way while selecting all cache ways is equivalent to invalidating all cache
|
|
||||||
/// entries. Completes as a background task with the way, or ways, locked, preventing
|
|
||||||
/// allocation.
|
|
||||||
pub reg7_inv_way: RW<u32>,
|
|
||||||
unused5: [u32; 12],
|
|
||||||
/// Clean Line by PA Write the specific L2 cache line to L3 main memory if the line is marked
|
|
||||||
/// as valid and dirty. The line is marked as not dirty. The valid bit is unchanged
|
|
||||||
pub reg7_clean_pa: RW<u32>,
|
|
||||||
unused6: [u32; 1],
|
|
||||||
/// Clean Line by Set/Way Write the specific L2 cache line within the specified way to L3 main
|
|
||||||
/// memory if the line is marked as valid and dirty. The line is marked as not dirty. The valid
|
|
||||||
/// bit is unchanged
|
|
||||||
pub reg7_clean_index: Reg7CleanIndex,
|
|
||||||
/// Clean by Way Writes each line of the specified L2 cache ways to L3 main memory if the line
|
|
||||||
/// is marked as valid and dirty. The lines are marked as not dirty. The valid bits are
|
|
||||||
/// unchanged. Completes as a background task with the way, or ways, locked, preventing
|
|
||||||
/// allocation.
|
|
||||||
pub reg7_clean_way: RW<u32>,
|
|
||||||
unused7: [u32; 12],
|
|
||||||
/// Clean and Invalidate Line by PA Write the specific L2 cache line to L3 main memory if the
|
|
||||||
/// line is marked as valid and dirty. The line is marked as not valid
|
|
||||||
pub reg7_clean_inv_pa: RW<u32>,
|
|
||||||
unused8: [u32; 1],
|
|
||||||
/// Clean and Invalidate Line by Set/Way Write the specific L2 cache line within the specified
|
|
||||||
/// way to L3 main memory if the line is marked as valid and dirty. The line is marked as not
|
|
||||||
/// valid
|
|
||||||
pub reg7_clean_inv_index: Reg7CleanInvIndex,
|
|
||||||
/// Clean and Invalidate by Way Writes each line of the specified L2 cache ways to L3 main
|
|
||||||
/// memory if the line is marked as valid and dirty. The lines are marked as not valid.
|
|
||||||
/// Completes as a background task with the way, or ways, locked, preventing allocation.
|
|
||||||
pub reg7_clean_inv_way: RW<u32>,
|
|
||||||
unused9: [u32; 0x1D8],
|
|
||||||
pub reg15_prefetch_ctrl: Reg15PrefetechCtrl,
|
|
||||||
}
|
|
||||||
|
|
||||||
register_at!(RegisterBlock, 0xF8F02000, new);
|
|
||||||
|
|
||||||
register!(reg0_cache_id, Reg0CacheId, RW, u32);
|
|
||||||
register_bits!(reg0_cache_id, implementer, u8, 24, 31);
|
|
||||||
register_bits!(reg0_cache_id, cache_id, u8, 10, 15);
|
|
||||||
register_bits!(reg0_cache_id, part_num, u8, 6, 9);
|
|
||||||
register_bits!(reg0_cache_id, rtl_release, u8, 0, 5);
|
|
||||||
|
|
||||||
register!(reg0_cache_type, Reg0CacheType, RW, u32);
|
|
||||||
register_bit!(reg0_cache_type, data_banking, 31);
|
|
||||||
register_bits!(reg0_cache_type, ctype, u8, 25, 28);
|
|
||||||
register_bit!(reg0_cache_type, h, 24);
|
|
||||||
register_bits!(reg0_cache_type, dsize_middsize_19, u8, 20, 22);
|
|
||||||
register_bit!(reg0_cache_type, l2_assoc_d, 18);
|
|
||||||
register_bits!(reg0_cache_type, l2cache_line_len_disize_11, u8, 12, 13);
|
|
||||||
register_bits!(reg0_cache_type, isize_midisize_7, u8, 8, 10);
|
|
||||||
register_bit!(reg0_cache_type, l2_assoc_i, 6);
|
|
||||||
register_bits!(reg0_cache_type, l2cache_line_len_i, u8, 0, 1);
|
|
||||||
|
|
||||||
register!(reg1_control, Reg1Control, RW, u32);
|
|
||||||
register_bit!(reg1_control, l2_enable, 0);
|
|
||||||
|
|
||||||
register!(reg1_aux_control, Reg1AuxControl, RW, u32);
|
|
||||||
register_bit!(reg1_aux_control, early_bresp_en, 30);
|
|
||||||
register_bit!(reg1_aux_control, instr_prefetch_en, 29);
|
|
||||||
register_bit!(reg1_aux_control, data_prefetch_en, 28);
|
|
||||||
register_bit!(reg1_aux_control, nonsec_inte_access_ctrl, 27);
|
|
||||||
register_bit!(reg1_aux_control, nonsec_lockdown_en, 26);
|
|
||||||
register_bit!(reg1_aux_control, cache_replace_policy, 25);
|
|
||||||
register_bits!(reg1_aux_control, force_write_alloc, u8, 23, 24);
|
|
||||||
register_bit!(reg1_aux_control, shared_attr_override_en, 22);
|
|
||||||
register_bit!(reg1_aux_control, parity_en, 21);
|
|
||||||
register_bit!(reg1_aux_control, event_mon_bus_en, 20);
|
|
||||||
register_bits!(reg1_aux_control, way_size, u8, 17, 19);
|
|
||||||
register_bit!(reg1_aux_control, associativity, 16);
|
|
||||||
register_bit!(reg1_aux_control, shared_attr_inva_en, 13);
|
|
||||||
register_bit!(reg1_aux_control, ex_cache_config, 12);
|
|
||||||
register_bit!(reg1_aux_control, store_buff_dev_lim_en, 11);
|
|
||||||
register_bit!(reg1_aux_control, high_pr_so_dev_rd_en, 10);
|
|
||||||
register_bit!(reg1_aux_control, full_line_zero_enable, 0);
|
|
||||||
|
|
||||||
register!(reg1_tag_ram_control, Reg1TagRamControl, RW, u32);
|
|
||||||
register_bits!(reg1_tag_ram_control, ram_wr_access_lat, u8, 8, 10);
|
|
||||||
register_bits!(reg1_tag_ram_control, ram_rd_access_lat, u8, 4, 6);
|
|
||||||
register_bits!(reg1_tag_ram_control, ram_setup_lat, u8, 0, 2);
|
|
||||||
|
|
||||||
register!(reg1_data_ram_control, Reg1DataRamControl, RW, u32);
|
|
||||||
register_bits!(reg1_data_ram_control, ram_wr_access_lat, u8, 8, 10);
|
|
||||||
register_bits!(reg1_data_ram_control, ram_rd_access_lat, u8, 4, 6);
|
|
||||||
register_bits!(reg1_data_ram_control, ram_setup_lat, u8, 0, 2);
|
|
||||||
|
|
||||||
register!(reg2_ev_counter_ctrl, Reg2EvCounterCtrl, RW, u32);
|
|
||||||
register_bit!(reg2_ev_counter_ctrl, ev_ctr_en, 0);
|
|
||||||
|
|
||||||
register!(reg2_ev_counter1_cfg, Reg2EvCounter1Cfg, RW, u32);
|
|
||||||
register_bits!(reg2_ev_counter1_cfg, ctr_ev_src, u8, 2, 5);
|
|
||||||
register_bits!(reg2_ev_counter1_cfg, ev_ctr_intr_gen, u8, 0, 1);
|
|
||||||
|
|
||||||
register!(reg2_ev_counter0_cfg, Reg2EvCounter0Cfg, RW, u32);
|
|
||||||
register_bits!(reg2_ev_counter0_cfg, ctr_ev_src, u8, 2, 5);
|
|
||||||
register_bits!(reg2_ev_counter0_cfg, ev_ctr_intr_gen, u8, 0, 1);
|
|
||||||
|
|
||||||
register!(reg2_int_mask, Reg2IntMask, RW, u32);
|
|
||||||
register_bit!(reg2_int_mask, decerr, 8);
|
|
||||||
register_bit!(reg2_int_mask, slverr, 7);
|
|
||||||
register_bit!(reg2_int_mask, errrd, 6);
|
|
||||||
register_bit!(reg2_int_mask, errrt, 5);
|
|
||||||
register_bit!(reg2_int_mask, errwd, 4);
|
|
||||||
register_bit!(reg2_int_mask, errwt, 3);
|
|
||||||
register_bit!(reg2_int_mask, parrd, 2);
|
|
||||||
register_bit!(reg2_int_mask, parrt, 1);
|
|
||||||
register_bit!(reg2_int_mask, ecntr, 0);
|
|
||||||
|
|
||||||
register!(reg2_int_mask_status, Reg2IntMaskStatus, RW, u32);
|
|
||||||
register_bit!(reg2_int_mask_status, decerr, 8);
|
|
||||||
register_bit!(reg2_int_mask_status, slverr, 7);
|
|
||||||
register_bit!(reg2_int_mask_status, errrd, 6);
|
|
||||||
register_bit!(reg2_int_mask_status, errrt, 5);
|
|
||||||
register_bit!(reg2_int_mask_status, errwd, 4);
|
|
||||||
register_bit!(reg2_int_mask_status, errwt, 3);
|
|
||||||
register_bit!(reg2_int_mask_status, parrd, 2);
|
|
||||||
register_bit!(reg2_int_mask_status, parrt, 1);
|
|
||||||
register_bit!(reg2_int_mask_status, ecntr, 0);
|
|
||||||
|
|
||||||
register!(reg2_int_raw_status, Reg2IntRawStatus, RW, u32);
|
|
||||||
register_bit!(reg2_int_raw_status, decerr, 8);
|
|
||||||
register_bit!(reg2_int_raw_status, slverr, 7);
|
|
||||||
register_bit!(reg2_int_raw_status, errrd, 6);
|
|
||||||
register_bit!(reg2_int_raw_status, errrt, 5);
|
|
||||||
register_bit!(reg2_int_raw_status, errwd, 4);
|
|
||||||
register_bit!(reg2_int_raw_status, errwt, 3);
|
|
||||||
register_bit!(reg2_int_raw_status, parrd, 2);
|
|
||||||
register_bit!(reg2_int_raw_status, parrt, 1);
|
|
||||||
register_bit!(reg2_int_raw_status, ecntr, 0);
|
|
||||||
|
|
||||||
register!(reg2_int_clear, Reg2IntClear, RW, u32, 0);
|
|
||||||
register_bit!(reg2_int_clear, decerr, 8, WTC);
|
|
||||||
register_bit!(reg2_int_clear, slverr, 7, WTC);
|
|
||||||
register_bit!(reg2_int_clear, errrd, 6, WTC);
|
|
||||||
register_bit!(reg2_int_clear, errrt, 5, WTC);
|
|
||||||
register_bit!(reg2_int_clear, errwd, 4, WTC);
|
|
||||||
register_bit!(reg2_int_clear, errwt, 3, WTC);
|
|
||||||
register_bit!(reg2_int_clear, parrd, 2, WTC);
|
|
||||||
register_bit!(reg2_int_clear, parrt, 1, WTC);
|
|
||||||
register_bit!(reg2_int_clear, ecntr, 0, WTC);
|
|
||||||
|
|
||||||
register!(reg7_cache_sync, Reg7CacheSync, RW, u32);
|
|
||||||
register_bit!(reg7_cache_sync, c, 0);
|
|
||||||
|
|
||||||
register!(reg7_clean_index, Reg7CleanIndex, RW, u32);
|
|
||||||
register_bits!(reg7_clean_index, way, u8, 28, 30);
|
|
||||||
register_bits!(reg7_clean_index, index, u8, 5, 11);
|
|
||||||
register_bit!(reg7_clean_index, c, 0);
|
|
||||||
|
|
||||||
register!(reg7_clean_inv_index, Reg7CleanInvIndex, RW, u32);
|
|
||||||
register_bits!(reg7_clean_inv_index, way, u8, 28, 30);
|
|
||||||
register_bits!(reg7_clean_inv_index, index, u8, 5, 11);
|
|
||||||
register_bit!(reg7_clean_inv_index, c, 0);
|
|
||||||
|
|
||||||
register!(reg15_prefetch_ctrl, Reg15PrefetechCtrl, RW, u32);
|
|
||||||
register_bit!(reg15_prefetch_ctrl, double_linefill_en, 30);
|
|
||||||
register_bit!(reg15_prefetch_ctrl, instr_prefetch_en, 29);
|
|
||||||
register_bit!(reg15_prefetch_ctrl, data_prefetch_en, 28);
|
|
||||||
register_bit!(reg15_prefetch_ctrl, pref_drop_en, 24);
|
|
||||||
register_bit!(reg15_prefetch_ctrl, incr_double_linefill_en, 23);
|
|
|
@ -1,7 +1,6 @@
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![feature(llvm_asm, global_asm)]
|
#![feature(llvm_asm, global_asm)]
|
||||||
#![feature(never_type)]
|
#![feature(never_type)]
|
||||||
#![feature(const_fn)]
|
|
||||||
|
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
|
@ -11,27 +10,8 @@ pub mod cache;
|
||||||
pub mod mmu;
|
pub mod mmu;
|
||||||
pub mod mutex;
|
pub mod mutex;
|
||||||
pub mod sync_channel;
|
pub mod sync_channel;
|
||||||
pub mod semaphore;
|
|
||||||
pub mod l2c;
|
|
||||||
mod uncached;
|
mod uncached;
|
||||||
mod fpu;
|
|
||||||
pub use uncached::UncachedSlice;
|
pub use uncached::UncachedSlice;
|
||||||
pub use fpu::enable_fpu;
|
pub mod pl310;
|
||||||
|
|
||||||
global_asm!(include_str!("exceptions.s"));
|
global_asm!(include_str!("exceptions.s"));
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn spin_lock_yield() {
|
|
||||||
#[cfg(feature = "power_saving")]
|
|
||||||
asm::wfe();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn notify_spin_lock() {
|
|
||||||
#[cfg(feature = "power_saving")]
|
|
||||||
{
|
|
||||||
asm::dsb();
|
|
||||||
asm::sev();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -158,7 +158,7 @@ impl L1Table {
|
||||||
global: true,
|
global: true,
|
||||||
shareable: true,
|
shareable: true,
|
||||||
access: AccessPermissions::FullAccess,
|
access: AccessPermissions::FullAccess,
|
||||||
tex: 0b0,
|
tex: 0b111,
|
||||||
domain: 0b1111,
|
domain: 0b1111,
|
||||||
exec: true,
|
exec: true,
|
||||||
cacheable: true,
|
cacheable: true,
|
||||||
|
@ -213,7 +213,7 @@ impl L1Table {
|
||||||
access: AccessPermissions::FullAccess,
|
access: AccessPermissions::FullAccess,
|
||||||
tex: 0,
|
tex: 0,
|
||||||
domain: 0,
|
domain: 0,
|
||||||
exec: false,
|
exec: true,
|
||||||
cacheable: false,
|
cacheable: false,
|
||||||
bufferable: true,
|
bufferable: true,
|
||||||
});
|
});
|
||||||
|
@ -338,7 +338,7 @@ impl L1Table {
|
||||||
/* 0xfff00000 - 0xffffffff (256K OCM when mapped to high address space) */
|
/* 0xfff00000 - 0xffffffff (256K OCM when mapped to high address space) */
|
||||||
self.direct_mapped_section(0xfff, L1Section {
|
self.direct_mapped_section(0xfff, L1Section {
|
||||||
global: true,
|
global: true,
|
||||||
shareable: true,
|
shareable: false,
|
||||||
access: AccessPermissions::FullAccess,
|
access: AccessPermissions::FullAccess,
|
||||||
tex: 0b100,
|
tex: 0b100,
|
||||||
domain: 0,
|
domain: 0,
|
||||||
|
@ -410,7 +410,6 @@ pub fn with_mmu<F: FnMut() -> !>(l1table: &L1Table, mut f: F) -> ! {
|
||||||
.a(false)
|
.a(false)
|
||||||
.c(true)
|
.c(true)
|
||||||
.i(true)
|
.i(true)
|
||||||
.z(true)
|
|
||||||
.unaligned(true)
|
.unaligned(true)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,20 @@
|
||||||
use core::ops::{Deref, DerefMut};
|
use core::ops::{Deref, DerefMut};
|
||||||
use core::sync::atomic::{AtomicU32, Ordering};
|
use core::sync::atomic::{AtomicU32, Ordering};
|
||||||
use core::cell::UnsafeCell;
|
use core::cell::UnsafeCell;
|
||||||
use super::{
|
use super::asm::*;
|
||||||
spin_lock_yield, notify_spin_lock,
|
|
||||||
asm::{enter_critical, exit_critical}
|
/// [Power-saving features](http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dht0008a/ch01s03s02.html)
|
||||||
};
|
#[inline]
|
||||||
|
fn wait_for_update() {
|
||||||
|
wfe();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// [Power-saving features](http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dht0008a/ch01s03s02.html)
|
||||||
|
#[inline]
|
||||||
|
fn signal_update() {
|
||||||
|
dsb();
|
||||||
|
sev();
|
||||||
|
}
|
||||||
|
|
||||||
const LOCKED: u32 = 1;
|
const LOCKED: u32 = 1;
|
||||||
const UNLOCKED: u32 = 0;
|
const UNLOCKED: u32 = 0;
|
||||||
|
@ -31,31 +41,18 @@ impl<T> Mutex<T> {
|
||||||
|
|
||||||
/// Lock the Mutex, blocks when already locked
|
/// Lock the Mutex, blocks when already locked
|
||||||
pub fn lock(&self) -> MutexGuard<T> {
|
pub fn lock(&self) -> MutexGuard<T> {
|
||||||
let mut irq = unsafe { enter_critical() };
|
while self.locked.compare_and_swap(UNLOCKED, LOCKED, Ordering::Acquire) != UNLOCKED {
|
||||||
while self.locked.compare_and_swap(UNLOCKED, LOCKED, Ordering::AcqRel) != UNLOCKED {
|
wait_for_update();
|
||||||
unsafe {
|
|
||||||
exit_critical(irq);
|
|
||||||
spin_lock_yield();
|
|
||||||
irq = enter_critical();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
MutexGuard { mutex: self, irq }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn try_lock(&self) -> Option<MutexGuard<T>> {
|
|
||||||
let irq = unsafe { enter_critical() };
|
|
||||||
if self.locked.compare_and_swap(UNLOCKED, LOCKED, Ordering::AcqRel) != UNLOCKED {
|
|
||||||
unsafe { exit_critical(irq) };
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(MutexGuard { mutex: self, irq })
|
|
||||||
}
|
}
|
||||||
|
dmb();
|
||||||
|
MutexGuard { mutex: self }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unlock(&self) {
|
fn unlock(&self) {
|
||||||
|
dmb();
|
||||||
self.locked.store(UNLOCKED, Ordering::Release);
|
self.locked.store(UNLOCKED, Ordering::Release);
|
||||||
|
|
||||||
notify_spin_lock();
|
signal_update();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,7 +60,6 @@ impl<T> Mutex<T> {
|
||||||
/// `Deref`/`DerefMutx`
|
/// `Deref`/`DerefMutx`
|
||||||
pub struct MutexGuard<'a, T> {
|
pub struct MutexGuard<'a, T> {
|
||||||
mutex: &'a Mutex<T>,
|
mutex: &'a Mutex<T>,
|
||||||
irq: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T> Deref for MutexGuard<'a, T> {
|
impl<'a, T> Deref for MutexGuard<'a, T> {
|
||||||
|
@ -83,6 +79,5 @@ impl<'a, T> DerefMut for MutexGuard<'a, T> {
|
||||||
impl<'a, T> Drop for MutexGuard<'a, T> {
|
impl<'a, T> Drop for MutexGuard<'a, T> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
self.mutex.unlock();
|
self.mutex.unlock();
|
||||||
unsafe { exit_critical(self.irq) };
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,166 @@
|
||||||
|
//! L2 cache controller
|
||||||
|
|
||||||
|
use libregister::RegisterW;
|
||||||
|
use crate::asm::*;
|
||||||
|
|
||||||
|
mod regs;
|
||||||
|
|
||||||
|
const CACHE_LINE: usize = 0x20;
|
||||||
|
const CACHE_LINE_MASK: usize = CACHE_LINE - 1;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn cache_line_addrs(first_addr: usize, beyond_addr: usize) -> impl Iterator<Item = usize> {
|
||||||
|
let first_addr = first_addr & !CACHE_LINE_MASK;
|
||||||
|
let beyond_addr = (beyond_addr | CACHE_LINE_MASK) + 1;
|
||||||
|
|
||||||
|
(first_addr..beyond_addr).step_by(CACHE_LINE)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn object_cache_line_addrs<T>(object: &T) -> impl Iterator<Item = usize> {
|
||||||
|
let first_addr = object as *const _ as usize;
|
||||||
|
let beyond_addr = (object as *const _ as usize) + core::mem::size_of_val(object);
|
||||||
|
cache_line_addrs(first_addr, beyond_addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn slice_cache_line_addrs<T>(slice: &[T]) -> impl Iterator<Item = usize> {
|
||||||
|
let first_addr = &slice[0] as *const _ as usize;
|
||||||
|
let beyond_addr = (&slice[slice.len() - 1] as *const _ as usize) +
|
||||||
|
core::mem::size_of_val(&slice[slice.len() - 1]);
|
||||||
|
cache_line_addrs(first_addr, beyond_addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct L2Cache {
|
||||||
|
pub regs: &'static mut regs::RegisterBlock,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl L2Cache {
|
||||||
|
pub fn new(register_baseaddr: usize) -> Self {
|
||||||
|
let regs = unsafe {
|
||||||
|
regs::RegisterBlock::new_at(register_baseaddr)
|
||||||
|
};
|
||||||
|
L2Cache { regs }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_tag_ram_latencies(&mut self, setup_lat: u8, rd_access_lat: u8, wr_access_lat: u8) {
|
||||||
|
self.regs.tag_ram_control.write(
|
||||||
|
regs::RamControl::zeroed()
|
||||||
|
.setup_lat(setup_lat)
|
||||||
|
.rd_access_lat(rd_access_lat)
|
||||||
|
.wr_access_lat(wr_access_lat)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_data_ram_latencies(&mut self, setup_lat: u8, rd_access_lat: u8, wr_access_lat: u8) {
|
||||||
|
self.regs.data_ram_control.write(
|
||||||
|
regs::RamControl::zeroed()
|
||||||
|
.setup_lat(setup_lat)
|
||||||
|
.rd_access_lat(rd_access_lat)
|
||||||
|
.wr_access_lat(wr_access_lat)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn disable_interrupts(&mut self) {
|
||||||
|
self.regs.int_mask.write(
|
||||||
|
regs::Interrupts::zeroed()
|
||||||
|
.ecntr(true)
|
||||||
|
.parrt(true)
|
||||||
|
.parrd(true)
|
||||||
|
.errwt(true)
|
||||||
|
.errwd(true)
|
||||||
|
.errrt(true)
|
||||||
|
.errrd(true)
|
||||||
|
.slverr(true)
|
||||||
|
.decerr(true)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn reset_interrupts(&mut self) {
|
||||||
|
self.regs.int_clear.write(
|
||||||
|
regs::Interrupts::zeroed()
|
||||||
|
.ecntr(true)
|
||||||
|
.parrt(true)
|
||||||
|
.parrd(true)
|
||||||
|
.errwt(true)
|
||||||
|
.errwd(true)
|
||||||
|
.errrt(true)
|
||||||
|
.errrd(true)
|
||||||
|
.slverr(true)
|
||||||
|
.decerr(true)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn invalidate_all(&mut self) {
|
||||||
|
unsafe { self.regs.inv_way.write(0xFFFF); }
|
||||||
|
unsafe { self.regs.cache_sync.write(1); }
|
||||||
|
while self.regs.cache_sync.read() != 0 {}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn enable(&mut self) {
|
||||||
|
dmb();
|
||||||
|
self.regs.control.write(
|
||||||
|
regs::Control::zeroed()
|
||||||
|
.l2_enable(true)
|
||||||
|
);
|
||||||
|
dsb();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clean_invalidate<T>(&mut self, obj: &T) {
|
||||||
|
dmb();
|
||||||
|
for addr in object_cache_line_addrs(obj) {
|
||||||
|
unsafe {
|
||||||
|
self.regs.clean_inv_pa.write(addr as u32);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dsb();
|
||||||
|
unsafe { self.regs.cache_sync.write(1); }
|
||||||
|
while self.regs.cache_sync.read() != 0 {}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clean_invalidate_slice<T>(&mut self, slice: &[T]) {
|
||||||
|
dmb();
|
||||||
|
for addr in slice_cache_line_addrs(slice) {
|
||||||
|
unsafe {
|
||||||
|
self.regs.clean_inv_pa.write(addr as u32);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dsb();
|
||||||
|
unsafe { self.regs.cache_sync.write(1); }
|
||||||
|
while self.regs.cache_sync.read() != 0 {}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clean_slice<T>(&mut self, slice: &[T]) {
|
||||||
|
dmb();
|
||||||
|
for addr in slice_cache_line_addrs(slice) {
|
||||||
|
unsafe {
|
||||||
|
self.regs.clean_pa.write(addr as u32);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dsb();
|
||||||
|
unsafe { self.regs.cache_sync.write(1); }
|
||||||
|
while self.regs.cache_sync.read() != 0 {}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn invalidate<T>(&mut self, obj: &mut T) {
|
||||||
|
dmb();
|
||||||
|
for addr in object_cache_line_addrs(obj) {
|
||||||
|
unsafe {
|
||||||
|
self.regs.inv_pa.write(addr as u32);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dsb();
|
||||||
|
unsafe { self.regs.cache_sync.write(1); }
|
||||||
|
while self.regs.cache_sync.read() != 0 {}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn invalidate_slice<T>(&mut self, slice: &mut [T]) {
|
||||||
|
dmb();
|
||||||
|
for addr in slice_cache_line_addrs(slice) {
|
||||||
|
unsafe {
|
||||||
|
self.regs.inv_pa.write(addr as u32);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dsb();
|
||||||
|
unsafe { self.regs.cache_sync.write(1); }
|
||||||
|
while self.regs.cache_sync.read() != 0 {}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,93 @@
|
||||||
|
use volatile_register::{RO, WO, RW};
|
||||||
|
use libregister::{register, register_bit, register_bits, RegisterW};
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct RegisterBlock {
|
||||||
|
pub cache_id: RW<u32>,
|
||||||
|
pub cache_type: RW<u32>,
|
||||||
|
pub _unused1: [RO<u32>; 62],
|
||||||
|
pub control: Control,
|
||||||
|
pub aux_control: RW<u32>,
|
||||||
|
pub tag_ram_control: RamControl,
|
||||||
|
pub data_ram_control: RamControl,
|
||||||
|
pub _unused2: [RO<u32>; 60],
|
||||||
|
pub ev_counter_ctrl: RW<u32>,
|
||||||
|
pub ev_counter1_cfg: RW<u32>,
|
||||||
|
pub ev_counter2_cfg: RW<u32>,
|
||||||
|
pub ev_counter1: RW<u32>,
|
||||||
|
pub ev_counter2: RW<u32>,
|
||||||
|
pub int_mask: Interrupts,
|
||||||
|
pub int_mask_status: Interrupts,
|
||||||
|
pub int_raw_status: Interrupts,
|
||||||
|
pub int_clear: Interrupts,
|
||||||
|
pub _unused3: [RO<u32>; 323],
|
||||||
|
pub cache_sync: RW<u32>,
|
||||||
|
pub _unused4: [RO<u32>; 15],
|
||||||
|
pub inv_pa: RW<u32>,
|
||||||
|
pub _unused5: [RO<u32>; 2],
|
||||||
|
pub inv_way: RW<u32>,
|
||||||
|
pub _unused6: [RO<u32>; 12],
|
||||||
|
pub clean_pa: RW<u32>,
|
||||||
|
pub _unused7: [RO<u32>; 1],
|
||||||
|
pub clean_index: RW<u32>,
|
||||||
|
pub clean_way: RW<u32>,
|
||||||
|
pub _unused8: [RO<u32>; 12],
|
||||||
|
pub clean_inv_pa: RW<u32>,
|
||||||
|
pub _unused9: [RO<u32>; 1],
|
||||||
|
pub clean_inv_index: RW<u32>,
|
||||||
|
pub clean_inv_way: RW<u32>,
|
||||||
|
pub _unused10: [RO<u32>; 64],
|
||||||
|
pub d_lockdown0: RW<u32>,
|
||||||
|
pub i_lockdown0: RW<u32>,
|
||||||
|
pub d_lockdown1: RW<u32>,
|
||||||
|
pub i_lockdown1: RW<u32>,
|
||||||
|
pub d_lockdown2: RW<u32>,
|
||||||
|
pub i_lockdown2: RW<u32>,
|
||||||
|
pub d_lockdown3: RW<u32>,
|
||||||
|
pub i_lockdown3: RW<u32>,
|
||||||
|
pub d_lockdown4: RW<u32>,
|
||||||
|
pub i_lockdown4: RW<u32>,
|
||||||
|
pub d_lockdown5: RW<u32>,
|
||||||
|
pub i_lockdown5: RW<u32>,
|
||||||
|
pub d_lockdown6: RW<u32>,
|
||||||
|
pub i_lockdown6: RW<u32>,
|
||||||
|
pub d_lockdown7: RW<u32>,
|
||||||
|
pub i_lockdown7: RW<u32>,
|
||||||
|
pub _unused11: [RO<u32>; 4],
|
||||||
|
pub lock_line_en: RW<u32>,
|
||||||
|
pub unlock_way: RW<u32>,
|
||||||
|
pub _unused12: [RO<u32>; 170],
|
||||||
|
pub addr_filtering_start: RW<u32>,
|
||||||
|
pub addr_filtering_end: RW<u32>,
|
||||||
|
pub _unused13: [RO<u32>; 206],
|
||||||
|
pub debug_ctrl: RW<u32>,
|
||||||
|
pub _unused14: [RO<u32>; 7],
|
||||||
|
pub prefetch_ctrl: RW<u32>,
|
||||||
|
pub _unused15: [RO<u32>; 7],
|
||||||
|
pub power_ctrl: RW<u32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RegisterBlock {
|
||||||
|
pub unsafe fn new_at(baseaddr: usize) -> &'static mut Self {
|
||||||
|
&mut *(baseaddr as *mut _)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
register!(control, Control, RW, u32);
|
||||||
|
register_bit!(control, l2_enable, 0);
|
||||||
|
|
||||||
|
register!(ram_control, RamControl, RW, u32);
|
||||||
|
register_bits!(ram_control, setup_lat, u8, 0, 2);
|
||||||
|
register_bits!(ram_control, rd_access_lat, u8, 4, 6);
|
||||||
|
register_bits!(ram_control, wr_access_lat, u8, 8, 10);
|
||||||
|
|
||||||
|
register!(interrupts, Interrupts, RW, u32);
|
||||||
|
register_bit!(interrupts, ecntr, 0);
|
||||||
|
register_bit!(interrupts, parrt, 1);
|
||||||
|
register_bit!(interrupts, parrd, 2);
|
||||||
|
register_bit!(interrupts, errwt, 3);
|
||||||
|
register_bit!(interrupts, errwd, 4);
|
||||||
|
register_bit!(interrupts, errrt, 5);
|
||||||
|
register_bit!(interrupts, errrd, 6);
|
||||||
|
register_bit!(interrupts, slverr, 7);
|
||||||
|
register_bit!(interrupts, decerr, 8);
|
|
@ -91,19 +91,8 @@ pub struct HVBAR;
|
||||||
def_reg_r!(HVBAR, u32, "mrc p15, 4, $0, c12, c0, 0");
|
def_reg_r!(HVBAR, u32, "mrc p15, 4, $0, c12, c0, 0");
|
||||||
def_reg_w!(HVBAR, u32, "mcr p15, 4, $0, c12, c0, 0");
|
def_reg_w!(HVBAR, u32, "mcr p15, 4, $0, c12, c0, 0");
|
||||||
|
|
||||||
/// Multiprocess Affinity Register
|
|
||||||
pub struct MPIDR;
|
pub struct MPIDR;
|
||||||
def_reg_r!(MPIDR, mpidr::Read, "mrc p15, 0, $0, c0, c0, 5");
|
def_reg_r!(MPIDR, u32, "mrc p15, 0, $0, c0, c0, 5");
|
||||||
wrap_reg!(mpidr);
|
|
||||||
register_bits!(mpidr,
|
|
||||||
/// CPU core index
|
|
||||||
cpu_id, u8, 0, 1);
|
|
||||||
register_bits!(mpidr,
|
|
||||||
/// Processor index in "multi-socket" systems
|
|
||||||
cluster_id, u8, 8, 11);
|
|
||||||
register_bit!(mpidr,
|
|
||||||
/// true if part of uniprocessor system
|
|
||||||
u, 30);
|
|
||||||
|
|
||||||
pub struct DFAR;
|
pub struct DFAR;
|
||||||
def_reg_r!(DFAR, u32, "mrc p15, 0, $0, c6, c0, 0");
|
def_reg_r!(DFAR, u32, "mrc p15, 0, $0, c6, c0, 0");
|
||||||
|
@ -149,15 +138,12 @@ pub struct ACTLR;
|
||||||
wrap_reg!(actlr);
|
wrap_reg!(actlr);
|
||||||
def_reg_r!(ACTLR, actlr::Read, "mrc p15, 0, $0, c1, c0, 1");
|
def_reg_r!(ACTLR, actlr::Read, "mrc p15, 0, $0, c1, c0, 1");
|
||||||
def_reg_w!(ACTLR, actlr::Write, "mcr p15, 0, $0, c1, c0, 1");
|
def_reg_w!(ACTLR, actlr::Write, "mcr p15, 0, $0, c1, c0, 1");
|
||||||
// SMP bit
|
|
||||||
register_bit!(actlr, parity_on, 9);
|
register_bit!(actlr, parity_on, 9);
|
||||||
register_bit!(actlr, alloc_one_way, 8);
|
register_bit!(actlr, alloc_one_way, 8);
|
||||||
register_bit!(actlr, excl, 7);
|
register_bit!(actlr, excl, 7);
|
||||||
register_bit!(actlr, smp, 6);
|
register_bit!(actlr, smp, 6);
|
||||||
register_bit!(actlr, write_full_line_of_zeros, 3);
|
register_bit!(actlr, write_full_line_of_zeros, 3);
|
||||||
register_bit!(actlr, l1_prefetch_enable, 2);
|
register_bit!(actlr, l1_prefetch_enable, 2);
|
||||||
// L2 cache prefetch hint, in UG585 section 3.4.8
|
|
||||||
register_bit!(actlr, l2_prefetch_enable, 1);
|
|
||||||
// Cache/TLB maintenance broadcast
|
// Cache/TLB maintenance broadcast
|
||||||
register_bit!(actlr, fw, 0);
|
register_bit!(actlr, fw, 0);
|
||||||
|
|
||||||
|
@ -175,10 +161,6 @@ impl ACTLR {
|
||||||
pub fn enable_smp(&mut self) {
|
pub fn enable_smp(&mut self) {
|
||||||
self.modify(|_, w| w.smp(true).fw(true));
|
self.modify(|_, w| w.smp(true).fw(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn enable_prefetch(&mut self) {
|
|
||||||
self.modify(|_, w| w.l1_prefetch_enable(true).l2_prefetch_enable(true))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Domain Access Control Register
|
/// Domain Access Control Register
|
||||||
|
|
|
@ -1,71 +0,0 @@
|
||||||
use super::{spin_lock_yield, notify_spin_lock};
|
|
||||||
use core::{
|
|
||||||
task::{Context, Poll},
|
|
||||||
pin::Pin,
|
|
||||||
future::Future,
|
|
||||||
sync::atomic::{AtomicI32, Ordering}
|
|
||||||
};
|
|
||||||
|
|
||||||
pub struct Semaphore {
|
|
||||||
value: AtomicI32,
|
|
||||||
max: i32
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Semaphore {
|
|
||||||
pub const fn new(value: i32, max: i32) -> Self {
|
|
||||||
Semaphore { value: AtomicI32::new(value), max}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn try_wait(&self) -> Option<()> {
|
|
||||||
loop {
|
|
||||||
let value = self.value.load(Ordering::Relaxed);
|
|
||||||
if value > 0 {
|
|
||||||
if self.value.compare_and_swap(value, value - 1, Ordering::SeqCst) == value {
|
|
||||||
return Some(());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn wait(&self) {
|
|
||||||
while self.try_wait().is_none() {
|
|
||||||
spin_lock_yield();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn async_wait(&self) {
|
|
||||||
struct Fut<'a>(&'a Semaphore);
|
|
||||||
|
|
||||||
impl Future for Fut<'_> {
|
|
||||||
type Output = ();
|
|
||||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
|
||||||
match self.0.try_wait() {
|
|
||||||
Some(_) => Poll::Ready(()),
|
|
||||||
None => {
|
|
||||||
cx.waker().wake_by_ref();
|
|
||||||
Poll::Pending
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Fut(&self).await
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn signal(&self) {
|
|
||||||
loop {
|
|
||||||
let value = self.value.load(Ordering::Relaxed);
|
|
||||||
if value < self.max {
|
|
||||||
if self.value.compare_and_swap(value, value + 1, Ordering::SeqCst) == value {
|
|
||||||
notify_spin_lock();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,72 +1,115 @@
|
||||||
use core::{
|
use core::{
|
||||||
pin::Pin,
|
|
||||||
future::Future,
|
future::Future,
|
||||||
sync::atomic::{AtomicPtr, AtomicUsize, Ordering},
|
pin::Pin,
|
||||||
|
ptr::null_mut,
|
||||||
|
sync::atomic::{AtomicPtr, Ordering},
|
||||||
task::{Context, Poll},
|
task::{Context, Poll},
|
||||||
};
|
};
|
||||||
use alloc::boxed::Box;
|
use alloc::{
|
||||||
use super::{spin_lock_yield, notify_spin_lock};
|
boxed::Box,
|
||||||
|
sync::Arc,
|
||||||
|
vec::Vec,
|
||||||
|
};
|
||||||
|
use super::asm::*;
|
||||||
|
|
||||||
pub struct Sender<'a, T> where T: Clone {
|
|
||||||
list: &'a [AtomicPtr<T>],
|
|
||||||
write: &'a AtomicUsize,
|
|
||||||
read: &'a AtomicUsize,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Receiver<'a, T> where T: Clone {
|
type Channel<T> = Vec<AtomicPtr<T>>;
|
||||||
list: &'a [AtomicPtr<T>],
|
|
||||||
write: &'a AtomicUsize,
|
|
||||||
read: &'a AtomicUsize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, T> Sender<'a, T> where T: Clone {
|
/// Create a bounded channel
|
||||||
pub const fn new(list: &'static [AtomicPtr<T>], write: &'static AtomicUsize, read: &'static AtomicUsize) -> Self {
|
///
|
||||||
Sender {list, write, read}
|
/// Returns `(tx, rx)` where one should be used one the local core,
|
||||||
|
/// and the other is to be shared with another core.
|
||||||
|
pub fn sync_channel<T>(bound: usize) -> (Sender<T>, Receiver<T>) {
|
||||||
|
// allow for bound=0
|
||||||
|
let len = bound + 1;
|
||||||
|
let mut channel = Vec::with_capacity(len);
|
||||||
|
for _ in 0..len {
|
||||||
|
channel.push(AtomicPtr::default());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn try_send<B: Into<Box<T>>>(&mut self, content: B) -> Result<(), B> {
|
let channel = Arc::new(channel);
|
||||||
let write = self.write.load(Ordering::Relaxed);
|
let sender = Sender {
|
||||||
if (write + 1) % self.list.len() == self.read.load(Ordering::Acquire) {
|
channel: channel.clone(),
|
||||||
Err(content)
|
pos: 0,
|
||||||
} else {
|
};
|
||||||
let ptr = Box::into_raw(content.into());
|
let receiver = Receiver {
|
||||||
let entry = &self.list[write];
|
channel: channel,
|
||||||
let prev = entry.swap(ptr, Ordering::Relaxed);
|
pos: 0,
|
||||||
// we allow other end get it first
|
};
|
||||||
self.write.store((write + 1) % self.list.len(), Ordering::Release);
|
(sender, receiver)
|
||||||
notify_spin_lock();
|
}
|
||||||
if !prev.is_null() {
|
|
||||||
unsafe {
|
/// Sending half of a channel
|
||||||
Box::from_raw(prev);
|
pub struct Sender<T> {
|
||||||
}
|
channel: Arc<Channel<T>>,
|
||||||
}
|
pos: usize,
|
||||||
Ok(())
|
}
|
||||||
|
|
||||||
|
impl<T> Sender<T> {
|
||||||
|
/// Blocking send
|
||||||
|
pub fn send<B: Into<Box<T>>>(&mut self, content: B) {
|
||||||
|
let ptr = Box::into_raw(content.into());
|
||||||
|
let entry = &self.channel[self.pos];
|
||||||
|
// try to write the new pointer if the current pointer is
|
||||||
|
// NULL, retrying while it is not NULL
|
||||||
|
while entry.compare_and_swap(null_mut(), ptr, Ordering::Acquire) != null_mut() {
|
||||||
|
// power-saving
|
||||||
|
wfe();
|
||||||
|
}
|
||||||
|
dsb();
|
||||||
|
// wake power-saving receivers
|
||||||
|
sev();
|
||||||
|
|
||||||
|
// advance
|
||||||
|
self.pos += 1;
|
||||||
|
// wrap
|
||||||
|
if self.pos >= self.channel.len() {
|
||||||
|
self.pos = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send<B: Into<Box<T>>>(&mut self, content: B) {
|
/// Non-blocking send, handing you back ownership of the content on **failure**
|
||||||
let mut content = content;
|
pub fn try_send<B: Into<Box<T>>>(&mut self, content: B) -> Option<Box<T>> {
|
||||||
while let Err(back) = self.try_send(content) {
|
let ptr = Box::into_raw(content.into());
|
||||||
content = back;
|
let entry = &self.channel[self.pos];
|
||||||
spin_lock_yield();
|
// try to write the new pointer if the current pointer is
|
||||||
|
// NULL
|
||||||
|
if entry.compare_and_swap(null_mut(), ptr, Ordering::Acquire) == null_mut() {
|
||||||
|
dsb();
|
||||||
|
// wake power-saving receivers
|
||||||
|
sev();
|
||||||
|
|
||||||
|
// advance
|
||||||
|
self.pos += 1;
|
||||||
|
// wrap
|
||||||
|
if self.pos >= self.channel.len() {
|
||||||
|
self.pos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// success
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
let content = unsafe { Box::from_raw(ptr) };
|
||||||
|
// failure
|
||||||
|
Some(content)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn async_send<B: Into<Box<T>>>(&mut self, content: B) {
|
pub async fn async_send<B: Into<Box<T>>>(&mut self, content: B) {
|
||||||
struct Send<'a, 'b, T> where T: Clone, 'b: 'a {
|
struct Send<'a, T> {
|
||||||
sender: &'a mut Sender<'b, T>,
|
sender: &'a mut Sender<T>,
|
||||||
content: Result<(), Box<T>>,
|
content: Option<Box<T>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Future for Send<'_, '_, T> where T: Clone {
|
impl<T> Future for Send<'_, T> {
|
||||||
type Output = ();
|
type Output = ();
|
||||||
|
|
||||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||||
match core::mem::replace(&mut self.content, Ok(())) {
|
match self.content.take() {
|
||||||
Err(content) => {
|
Some(content) => {
|
||||||
if let Err(content) = self.sender.try_send(content) {
|
if let Some(content) = self.sender.try_send(content) {
|
||||||
// failure
|
// failure
|
||||||
self.content = Err(content);
|
self.content = Some(content);
|
||||||
cx.waker().wake_by_ref();
|
cx.waker().wake_by_ref();
|
||||||
Poll::Pending
|
Poll::Pending
|
||||||
} else {
|
} else {
|
||||||
|
@ -74,80 +117,93 @@ impl<'a, T> Sender<'a, T> where T: Clone {
|
||||||
Poll::Ready(())
|
Poll::Ready(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(_) => panic!("Send future polled after success"),
|
None => panic!("Send future polled after success"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Send {
|
Send {
|
||||||
sender: self,
|
sender: self,
|
||||||
content: Err(content.into()),
|
content: Some(content.into()),
|
||||||
}.await
|
}.await
|
||||||
}
|
}
|
||||||
|
|
||||||
/// free all items in the queue. It is the user's responsibility to
|
|
||||||
/// ensure no reader is trying to copy the data.
|
|
||||||
pub unsafe fn drop_elements(&mut self) {
|
|
||||||
for v in self.list.iter() {
|
|
||||||
let original = v.swap(core::ptr::null_mut(), Ordering::Relaxed);
|
|
||||||
if !original.is_null() {
|
|
||||||
Box::from_raw(original);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Reset the `sync_channel`, *forget* all items in the queue. Affects both the sender and
|
|
||||||
/// receiver.
|
|
||||||
pub unsafe fn reset(&mut self) {
|
|
||||||
self.write.store(0, Ordering::Relaxed);
|
|
||||||
self.read.store(0, Ordering::Relaxed);
|
|
||||||
for v in self.list.iter() {
|
|
||||||
v.store(core::ptr::null_mut(), Ordering::Relaxed);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T> Receiver<'a, T> where T: Clone {
|
|
||||||
pub const fn new(list: &'static [AtomicPtr<T>], write: &'static AtomicUsize, read: &'static AtomicUsize) -> Self {
|
|
||||||
Receiver {list, write, read}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn try_recv(&mut self) -> Result<T, ()> {
|
|
||||||
let read = self.read.load(Ordering::Relaxed);
|
|
||||||
if read == self.write.load(Ordering::Acquire) {
|
|
||||||
Err(())
|
|
||||||
} else {
|
|
||||||
let entry = &self.list[read];
|
|
||||||
let data = unsafe {
|
|
||||||
// we cannot deallocate the box
|
|
||||||
Box::leak(Box::from_raw(entry.load(Ordering::Relaxed)))
|
|
||||||
};
|
|
||||||
let result = data.clone();
|
|
||||||
self.read.store((read + 1) % self.list.len(), Ordering::Release);
|
|
||||||
notify_spin_lock();
|
|
||||||
Ok(result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn recv(&mut self) -> T {
|
|
||||||
|
/// Receiving half of a channel
|
||||||
|
pub struct Receiver<T> {
|
||||||
|
channel: Arc<Channel<T>>,
|
||||||
|
pos: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Receiver<T> {
|
||||||
|
/// Blocking receive
|
||||||
|
pub fn recv(&mut self) -> Box<T> {
|
||||||
|
let entry = &self.channel[self.pos];
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
if let Ok(data) = self.try_recv() {
|
dmb();
|
||||||
return data;
|
let ptr = entry.swap(null_mut(), Ordering::Release);
|
||||||
|
if ptr != null_mut() {
|
||||||
|
dsb();
|
||||||
|
// wake power-saving senders
|
||||||
|
sev();
|
||||||
|
|
||||||
|
let content = unsafe { Box::from_raw(ptr) };
|
||||||
|
|
||||||
|
// advance
|
||||||
|
self.pos += 1;
|
||||||
|
// wrap
|
||||||
|
if self.pos >= self.channel.len() {
|
||||||
|
self.pos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return content;
|
||||||
}
|
}
|
||||||
spin_lock_yield();
|
|
||||||
|
// power-saving
|
||||||
|
wfe();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn async_recv(&mut self) -> T {
|
/// Non-blocking receive
|
||||||
struct Recv<'a, 'b, T> where T: Clone, 'b: 'a {
|
pub fn try_recv(&mut self) -> Option<Box<T>> {
|
||||||
receiver: &'a mut Receiver<'b, T>,
|
let entry = &self.channel[self.pos];
|
||||||
|
|
||||||
|
dmb();
|
||||||
|
let ptr = entry.swap(null_mut(), Ordering::Release);
|
||||||
|
if ptr != null_mut() {
|
||||||
|
dsb();
|
||||||
|
// wake power-saving senders
|
||||||
|
sev();
|
||||||
|
|
||||||
|
let content = unsafe { Box::from_raw(ptr) };
|
||||||
|
|
||||||
|
// advance
|
||||||
|
self.pos += 1;
|
||||||
|
// wrap
|
||||||
|
if self.pos >= self.channel.len() {
|
||||||
|
self.pos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(content)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn async_recv(&mut self) -> Box<T> {
|
||||||
|
struct Recv<'a, T> {
|
||||||
|
receiver: &'a mut Receiver<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Future for Recv<'_, '_, T> where T: Clone {
|
impl<T> Future for Recv<'_, T> {
|
||||||
type Output = T;
|
type Output = Box<T>;
|
||||||
|
|
||||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||||
if let Ok(content) = self.receiver.try_recv() {
|
if let Some(content) = self.receiver.try_recv() {
|
||||||
Poll::Ready(content)
|
Poll::Ready(content)
|
||||||
} else {
|
} else {
|
||||||
cx.waker().wake_by_ref();
|
cx.waker().wake_by_ref();
|
||||||
|
@ -162,26 +218,10 @@ impl<'a, T> Receiver<'a, T> where T: Clone {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T> Iterator for Receiver<'a, T> where T: Clone {
|
impl<T> Iterator for Receiver<T> {
|
||||||
type Item = T;
|
type Item = Box<T>;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
Some(self.recv())
|
Some(self.recv())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[macro_export]
|
|
||||||
/// Macro for initializing the sync_channel with static buffer and indexes.
|
|
||||||
/// Note that this requires `#![feature(const_in_array_repeat_expressions)]`
|
|
||||||
macro_rules! sync_channel {
|
|
||||||
($t: ty, $cap: expr) => {
|
|
||||||
{
|
|
||||||
use core::sync::atomic::{AtomicUsize, AtomicPtr};
|
|
||||||
use $crate::sync_channel::{Sender, Receiver};
|
|
||||||
static LIST: [AtomicPtr<$t>; $cap + 1] = [AtomicPtr::new(core::ptr::null_mut()); $cap + 1];
|
|
||||||
static WRITE: AtomicUsize = AtomicUsize::new(0);
|
|
||||||
static READ: AtomicUsize = AtomicUsize::new(0);
|
|
||||||
(Sender::new(&LIST, &WRITE, &READ), Receiver::new(&LIST, &WRITE, &READ))
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
|
@ -23,12 +23,12 @@ impl<T> UncachedSlice<T> {
|
||||||
assert_eq!(start & (L1_PAGE_SIZE - 1), 0);
|
assert_eq!(start & (L1_PAGE_SIZE - 1), 0);
|
||||||
|
|
||||||
for page_start in (start..(start + size)).step_by(L1_PAGE_SIZE) {
|
for page_start in (start..(start + size)).step_by(L1_PAGE_SIZE) {
|
||||||
// non-shareable device
|
|
||||||
L1Table::get()
|
L1Table::get()
|
||||||
.update(page_start as *const (), |l1_section| {
|
.update(page_start as *const (), |l1_section| {
|
||||||
l1_section.tex = 0b10;
|
// Shareable Device
|
||||||
l1_section.cacheable = true;
|
l1_section.tex = 0b000;
|
||||||
l1_section.bufferable = false;
|
l1_section.cacheable = false;
|
||||||
|
l1_section.bufferable = true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
[package]
|
[package]
|
||||||
name = "libregister"
|
name = "libregister"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
authors = ["M-Labs"]
|
authors = ["Astro <astro@spaceboyz.net>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
|
|
@ -2,18 +2,12 @@
|
||||||
name = "libsupport_zynq"
|
name = "libsupport_zynq"
|
||||||
description = "Software support for running in the Zynq PS"
|
description = "Software support for running in the Zynq PS"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
authors = ["M-Labs"]
|
authors = ["Astro <astro@spaceboyz.net>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
target_zc706 = ["libboard_zynq/target_zc706"]
|
target_zc706 = ["libboard_zynq/target_zc706"]
|
||||||
target_cora_z7_10 = ["libboard_zynq/target_cora_z7_10"]
|
target_cora_z7_10 = ["libboard_zynq/target_cora_z7_10"]
|
||||||
target_redpitaya = ["libboard_zynq/target_redpitaya"]
|
|
||||||
panic_handler = []
|
|
||||||
dummy_irq_handler = []
|
|
||||||
alloc_core = []
|
|
||||||
|
|
||||||
default = ["panic_handler", "dummy_irq_handler"]
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
r0 = "1"
|
r0 = "1"
|
||||||
|
|
|
@ -1,70 +1,24 @@
|
||||||
use libregister::RegisterR;
|
use libregister::RegisterR;
|
||||||
use libcortex_a9::regs::{DFSR, MPIDR};
|
use libcortex_a9::regs::DFSR;
|
||||||
use libboard_zynq::{println, stdio};
|
use libboard_zynq::{println, slcr, stdio};
|
||||||
|
|
||||||
#[link_section = ".text.boot"]
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
#[naked]
|
|
||||||
pub unsafe extern "C" fn UndefinedInstruction() {
|
|
||||||
stdio::drop_uart();
|
|
||||||
println!("UndefinedInstruction");
|
|
||||||
loop {}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[link_section = ".text.boot"]
|
|
||||||
#[no_mangle]
|
|
||||||
#[naked]
|
|
||||||
pub unsafe extern "C" fn SoftwareInterrupt() {
|
|
||||||
stdio::drop_uart();
|
|
||||||
println!("SoftwareInterrupt");
|
|
||||||
loop {}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[link_section = ".text.boot"]
|
|
||||||
#[no_mangle]
|
|
||||||
#[naked]
|
|
||||||
pub unsafe extern "C" fn PrefetchAbort() {
|
pub unsafe extern "C" fn PrefetchAbort() {
|
||||||
stdio::drop_uart();
|
stdio::drop_uart();
|
||||||
|
|
||||||
println!("PrefetchAbort");
|
println!("PrefetchAbort");
|
||||||
|
|
||||||
|
slcr::RegisterBlock::unlocked(|slcr| slcr.soft_reset());
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[link_section = ".text.boot"]
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
#[naked]
|
|
||||||
pub unsafe extern "C" fn DataAbort() {
|
pub unsafe extern "C" fn DataAbort() {
|
||||||
stdio::drop_uart();
|
stdio::drop_uart();
|
||||||
|
|
||||||
println!("DataAbort on core {}", MPIDR.read().cpu_id());
|
println!("DataAbort");
|
||||||
println!("DFSR: {:03X}", DFSR.read());
|
println!("DFSR: {:03X}", DFSR.read());
|
||||||
|
|
||||||
loop {}
|
slcr::RegisterBlock::unlocked(|slcr| slcr.soft_reset());
|
||||||
}
|
|
||||||
|
|
||||||
#[link_section = ".text.boot"]
|
|
||||||
#[no_mangle]
|
|
||||||
#[naked]
|
|
||||||
pub unsafe extern "C" fn ReservedException() {
|
|
||||||
stdio::drop_uart();
|
|
||||||
println!("ReservedException");
|
|
||||||
loop {}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[link_section = ".text.boot"]
|
|
||||||
#[no_mangle]
|
|
||||||
#[naked]
|
|
||||||
#[cfg(feature = "dummy_irq_handler")]
|
|
||||||
pub unsafe extern "C" fn IRQ() {
|
|
||||||
stdio::drop_uart();
|
|
||||||
println!("IRQ");
|
|
||||||
loop {}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[link_section = ".text.boot"]
|
|
||||||
#[no_mangle]
|
|
||||||
#[naked]
|
|
||||||
pub unsafe extern "C" fn FIQ() {
|
|
||||||
stdio::drop_uart();
|
|
||||||
println!("FIQ");
|
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ use libregister::{
|
||||||
VolatileCell,
|
VolatileCell,
|
||||||
RegisterR, RegisterW, RegisterRW,
|
RegisterR, RegisterW, RegisterRW,
|
||||||
};
|
};
|
||||||
use libcortex_a9::{asm, l2c, regs::*, cache, mmu, spin_lock_yield, notify_spin_lock};
|
use libcortex_a9::{asm, regs::*, cache, mmu};
|
||||||
use libboard_zynq::{slcr, mpcore};
|
use libboard_zynq::{slcr, mpcore};
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
@ -21,15 +21,17 @@ static mut CORE1_ENABLED: VolatileCell<bool> = VolatileCell::new(false);
|
||||||
#[link_section = ".text.boot"]
|
#[link_section = ".text.boot"]
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
#[naked]
|
#[naked]
|
||||||
pub unsafe extern "C" fn Reset() -> ! {
|
pub unsafe extern "C" fn _boot_cores() -> ! {
|
||||||
match MPIDR.read().cpu_id() {
|
const CORE_MASK: u32 = 0x3;
|
||||||
|
|
||||||
|
match MPIDR.read() & CORE_MASK {
|
||||||
0 => {
|
0 => {
|
||||||
SP.write(&mut __stack0_start as *mut _ as u32);
|
SP.write(&mut __stack0_start as *mut _ as u32);
|
||||||
boot_core0();
|
boot_core0();
|
||||||
}
|
}
|
||||||
1 => {
|
1 => {
|
||||||
while !CORE1_ENABLED.get() {
|
while !CORE1_ENABLED.get() {
|
||||||
spin_lock_yield();
|
asm::wfe();
|
||||||
}
|
}
|
||||||
SP.write(&mut __stack1_start as *mut _ as u32);
|
SP.write(&mut __stack1_start as *mut _ as u32);
|
||||||
boot_core1();
|
boot_core1();
|
||||||
|
@ -43,7 +45,7 @@ pub unsafe extern "C" fn Reset() -> ! {
|
||||||
unsafe fn boot_core0() -> ! {
|
unsafe fn boot_core0() -> ! {
|
||||||
l1_cache_init();
|
l1_cache_init();
|
||||||
|
|
||||||
let mpcore = mpcore::RegisterBlock::mpcore();
|
let mpcore = mpcore::RegisterBlock::new();
|
||||||
mpcore.scu_invalidate.invalidate_all_cores();
|
mpcore.scu_invalidate.invalidate_all_cores();
|
||||||
|
|
||||||
zero_bss(&mut __bss_start, &mut __bss_end);
|
zero_bss(&mut __bss_start, &mut __bss_end);
|
||||||
|
@ -53,12 +55,10 @@ unsafe fn boot_core0() -> ! {
|
||||||
mmu::with_mmu(mmu_table, || {
|
mmu::with_mmu(mmu_table, || {
|
||||||
mpcore.scu_control.start();
|
mpcore.scu_control.start();
|
||||||
ACTLR.enable_smp();
|
ACTLR.enable_smp();
|
||||||
ACTLR.enable_prefetch();
|
|
||||||
// TODO: Barriers reqd when core1 is not yet starting?
|
// TODO: Barriers reqd when core1 is not yet starting?
|
||||||
asm::dmb();
|
asm::dmb();
|
||||||
asm::dsb();
|
asm::dsb();
|
||||||
|
|
||||||
asm::enable_irq();
|
|
||||||
main_core0();
|
main_core0();
|
||||||
panic!("return from main");
|
panic!("return from main");
|
||||||
});
|
});
|
||||||
|
@ -69,18 +69,16 @@ unsafe fn boot_core0() -> ! {
|
||||||
unsafe fn boot_core1() -> ! {
|
unsafe fn boot_core1() -> ! {
|
||||||
l1_cache_init();
|
l1_cache_init();
|
||||||
|
|
||||||
let mpcore = mpcore::RegisterBlock::mpcore();
|
let mpcore = mpcore::RegisterBlock::new();
|
||||||
mpcore.scu_invalidate.invalidate_core1();
|
mpcore.scu_invalidate.invalidate_core1();
|
||||||
|
|
||||||
let mmu_table = mmu::L1Table::get();
|
let mmu_table = mmu::L1Table::get();
|
||||||
mmu::with_mmu(mmu_table, || {
|
mmu::with_mmu(mmu_table, || {
|
||||||
ACTLR.enable_smp();
|
ACTLR.enable_smp();
|
||||||
ACTLR.enable_prefetch();
|
|
||||||
// TODO: Barriers reqd when core1 is not yet starting?
|
// TODO: Barriers reqd when core1 is not yet starting?
|
||||||
asm::dmb();
|
asm::dmb();
|
||||||
asm::dsb();
|
asm::dsb();
|
||||||
|
|
||||||
asm::enable_irq();
|
|
||||||
main_core1();
|
main_core1();
|
||||||
panic!("return from main_core1");
|
panic!("return from main_core1");
|
||||||
});
|
});
|
||||||
|
@ -103,7 +101,7 @@ fn l1_cache_init() {
|
||||||
// for all of the L1 data cache rather than a (previously
|
// for all of the L1 data cache rather than a (previously
|
||||||
// unspecified) combination of one cache set and one cache
|
// unspecified) combination of one cache set and one cache
|
||||||
// way.
|
// way.
|
||||||
dciall_l1();
|
dciall();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Core1 {
|
pub struct Core1 {
|
||||||
|
@ -133,13 +131,12 @@ impl Core1 {
|
||||||
unsafe {
|
unsafe {
|
||||||
CORE1_ENABLED.set(true);
|
CORE1_ENABLED.set(true);
|
||||||
}
|
}
|
||||||
|
// Ensure values have been written to cache
|
||||||
|
asm::dmb();
|
||||||
// Flush cache-line
|
// Flush cache-line
|
||||||
cache::dcc(unsafe { &CORE1_ENABLED });
|
cache::dccmvac(unsafe { &CORE1_ENABLED } as *const _ as usize);
|
||||||
if sdram {
|
if sdram {
|
||||||
cache::dccmvac(0);
|
cache::dccmvac(0);
|
||||||
asm::dsb();
|
|
||||||
l2c::l2_cache_clean(0);
|
|
||||||
l2c::l2_cache_sync();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// wake up core1
|
// wake up core1
|
||||||
|
@ -147,7 +144,6 @@ impl Core1 {
|
||||||
slcr.a9_cpu_rst_ctrl.modify(|_, w| w.a9_rst1(false));
|
slcr.a9_cpu_rst_ctrl.modify(|_, w| w.a9_rst1(false));
|
||||||
slcr.a9_cpu_rst_ctrl.modify(|_, w| w.a9_clkstop1(false));
|
slcr.a9_cpu_rst_ctrl.modify(|_, w| w.a9_clkstop1(false));
|
||||||
});
|
});
|
||||||
notify_spin_lock();
|
|
||||||
|
|
||||||
Core1 {}
|
Core1 {}
|
||||||
}
|
}
|
||||||
|
@ -155,8 +151,6 @@ impl Core1 {
|
||||||
pub fn disable(&self) {
|
pub fn disable(&self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
CORE1_ENABLED.set(false);
|
CORE1_ENABLED.set(false);
|
||||||
cache::dccmvac(&CORE1_ENABLED as *const _ as usize);
|
|
||||||
asm::dsb();
|
|
||||||
}
|
}
|
||||||
self.restart();
|
self.restart();
|
||||||
}
|
}
|
||||||
|
@ -164,9 +158,7 @@ impl Core1 {
|
||||||
pub fn restart(&self) {
|
pub fn restart(&self) {
|
||||||
slcr::RegisterBlock::unlocked(|slcr| {
|
slcr::RegisterBlock::unlocked(|slcr| {
|
||||||
slcr.a9_cpu_rst_ctrl.modify(|_, w| w.a9_rst1(true));
|
slcr.a9_cpu_rst_ctrl.modify(|_, w| w.a9_rst1(true));
|
||||||
slcr.a9_cpu_rst_ctrl.modify(|_, w| w.a9_clkstop1(true));
|
|
||||||
slcr.a9_cpu_rst_ctrl.modify(|_, w| w.a9_rst1(false));
|
slcr.a9_cpu_rst_ctrl.modify(|_, w| w.a9_rst1(false));
|
||||||
slcr.a9_cpu_rst_ctrl.modify(|_, w| w.a9_clkstop1(false));
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,5 @@ pub extern crate compiler_builtins;
|
||||||
|
|
||||||
pub mod boot;
|
pub mod boot;
|
||||||
mod abort;
|
mod abort;
|
||||||
#[cfg(feature = "panic_handler")]
|
|
||||||
mod panic;
|
mod panic;
|
||||||
pub mod ram;
|
pub mod ram;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use libboard_zynq::{print, println};
|
use libboard_zynq::{slcr, print, println};
|
||||||
|
|
||||||
#[panic_handler]
|
#[panic_handler]
|
||||||
fn panic(info: &core::panic::PanicInfo) -> ! {
|
fn panic(info: &core::panic::PanicInfo) -> ! {
|
||||||
|
@ -14,5 +14,6 @@ fn panic(info: &core::panic::PanicInfo) -> ! {
|
||||||
println!("");
|
println!("");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
slcr::RegisterBlock::unlocked(|slcr| slcr.soft_reset());
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,100 +1,55 @@
|
||||||
use alloc::alloc::Layout;
|
|
||||||
use core::alloc::GlobalAlloc;
|
use core::alloc::GlobalAlloc;
|
||||||
use core::ptr::NonNull;
|
use core::ptr::NonNull;
|
||||||
use libcortex_a9::{
|
use alloc::alloc::Layout;
|
||||||
mutex::Mutex,
|
|
||||||
regs::MPIDR
|
|
||||||
};
|
|
||||||
use libregister::RegisterR;
|
|
||||||
use linked_list_allocator::Heap;
|
use linked_list_allocator::Heap;
|
||||||
#[cfg(not(feature = "alloc_core"))]
|
use libcortex_a9::mutex::Mutex;
|
||||||
use libboard_zynq::ddr::DdrRam;
|
use libboard_zynq::ddr::DdrRam;
|
||||||
|
|
||||||
#[global_allocator]
|
#[global_allocator]
|
||||||
static ALLOCATOR: CortexA9Alloc = CortexA9Alloc(
|
static ALLOCATOR: CortexA9Alloc = CortexA9Alloc(Mutex::new(Heap::empty()));
|
||||||
Mutex::new(Heap::empty()),
|
|
||||||
Mutex::new(Heap::empty()),
|
|
||||||
);
|
|
||||||
|
|
||||||
struct CortexA9Alloc(Mutex<Heap>, Mutex<Heap>);
|
/// LockedHeap doesn't lock properly
|
||||||
|
struct CortexA9Alloc(Mutex<Heap>);
|
||||||
|
|
||||||
unsafe impl Sync for CortexA9Alloc {}
|
unsafe impl Sync for CortexA9Alloc {}
|
||||||
|
|
||||||
unsafe impl GlobalAlloc for CortexA9Alloc {
|
unsafe impl GlobalAlloc for CortexA9Alloc {
|
||||||
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
|
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
|
||||||
if cfg!(not(feature = "alloc_core")) || MPIDR.read().cpu_id() == 0 {
|
self.0.lock()
|
||||||
&self.0
|
.allocate_first_fit(layout)
|
||||||
} else {
|
.ok()
|
||||||
&self.1
|
.map_or(0 as *mut u8, |allocation| allocation.as_ptr())
|
||||||
}
|
|
||||||
.lock()
|
|
||||||
.allocate_first_fit(layout)
|
|
||||||
.ok()
|
|
||||||
.map_or(0 as *mut u8, |allocation| allocation.as_ptr())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
|
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
|
||||||
if cfg!(not(feature = "alloc_core"))
|
self.0.lock()
|
||||||
|| ((&__heap0_start as *const usize as usize <= ptr as usize)
|
.deallocate(NonNull::new_unchecked(ptr), layout)
|
||||||
&& ((ptr as usize) < &__heap0_end as *const usize as usize))
|
|
||||||
{
|
|
||||||
&self.0
|
|
||||||
} else {
|
|
||||||
&self.1
|
|
||||||
}
|
|
||||||
.lock()
|
|
||||||
.deallocate(NonNull::new_unchecked(ptr), layout)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "alloc_core"))]
|
|
||||||
pub fn init_alloc_ddr(ddr: &mut DdrRam) {
|
pub fn init_alloc_ddr(ddr: &mut DdrRam) {
|
||||||
unsafe {
|
unsafe {
|
||||||
ALLOCATOR
|
ALLOCATOR.0.lock()
|
||||||
.0
|
|
||||||
.lock()
|
|
||||||
.init(ddr.ptr::<u8>() as usize, ddr.size());
|
.init(ddr.ptr::<u8>() as usize, ddr.size());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
static __heap0_start: usize;
|
static __heap_start: usize;
|
||||||
static __heap0_end: usize;
|
static __heap_end: usize;
|
||||||
#[cfg(feature = "alloc_core")]
|
|
||||||
static __heap1_start: usize;
|
|
||||||
#[cfg(feature = "alloc_core")]
|
|
||||||
static __heap1_end: usize;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init_alloc_core0() {
|
pub fn init_alloc_linker() {
|
||||||
unsafe {
|
unsafe {
|
||||||
let start = &__heap0_start as *const usize as usize;
|
let start = &__heap_start as *const usize as usize;
|
||||||
let end = &__heap0_end as *const usize as usize;
|
let end = &__heap_end as *const usize as usize;
|
||||||
ALLOCATOR.0.lock().init(start, end - start);
|
ALLOCATOR.0.lock()
|
||||||
|
.init(start, end - start);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "alloc_core")]
|
|
||||||
pub fn init_alloc_core1() {
|
|
||||||
unsafe {
|
|
||||||
let start = &__heap1_start as *const usize as usize;
|
|
||||||
let end = &__heap1_end as *const usize as usize;
|
|
||||||
ALLOCATOR.1.lock().init(start, end - start);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[alloc_error_handler]
|
#[alloc_error_handler]
|
||||||
fn alloc_error(layout: core::alloc::Layout) -> ! {
|
fn alloc_error(_: core::alloc::Layout) -> ! {
|
||||||
let id = MPIDR.read().cpu_id();
|
panic!("alloc_error")
|
||||||
let used = if cfg!(not(feature = "alloc_core")) || id == 0 {
|
|
||||||
ALLOCATOR.0.lock().used()
|
|
||||||
} else {
|
|
||||||
ALLOCATOR.1.lock().used()
|
|
||||||
};
|
|
||||||
panic!(
|
|
||||||
"Core {} alloc_error, layout: {:?}, used memory: {}",
|
|
||||||
id,
|
|
||||||
layout,
|
|
||||||
used
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
37
nix/fsbl.nix
37
nix/fsbl.nix
|
@ -1,37 +0,0 @@
|
||||||
{ pkgs, board ? "zc706" }:
|
|
||||||
let
|
|
||||||
gnutoolchain = import ./gnutoolchain.nix { inherit pkgs; };
|
|
||||||
in
|
|
||||||
pkgs.stdenv.mkDerivation {
|
|
||||||
name = "${board}-fsbl";
|
|
||||||
src = pkgs.fetchFromGitHub {
|
|
||||||
owner = "Xilinx";
|
|
||||||
repo = "embeddedsw";
|
|
||||||
rev = "65c849ed46c88c67457e1fc742744f96db968ff1";
|
|
||||||
sha256 = "1rvl06ha40dzd6s9aa4sylmksh4xb9dqaxq462lffv1fdk342pda";
|
|
||||||
};
|
|
||||||
patches = [ ./fsbl.patch ];
|
|
||||||
nativeBuildInputs = [
|
|
||||||
pkgs.gnumake
|
|
||||||
gnutoolchain.binutils
|
|
||||||
gnutoolchain.gcc
|
|
||||||
];
|
|
||||||
patchPhase =
|
|
||||||
''
|
|
||||||
patch -p1 -i ${./fsbl.patch}
|
|
||||||
patchShebangs lib/sw_apps/zynq_fsbl/misc/copy_bsp.sh
|
|
||||||
echo 'SEARCH_DIR("${gnutoolchain.newlib}/arm-none-eabi/lib");' >> lib/sw_apps/zynq_fsbl/src/lscript.ld
|
|
||||||
'';
|
|
||||||
buildPhase =
|
|
||||||
''
|
|
||||||
cd lib/sw_apps/zynq_fsbl/src
|
|
||||||
make BOARD=${board} "CFLAGS=-DFSBL_DEBUG_INFO -g"
|
|
||||||
'';
|
|
||||||
installPhase =
|
|
||||||
''
|
|
||||||
mkdir $out
|
|
||||||
cp fsbl.elf $out
|
|
||||||
'';
|
|
||||||
doCheck = false;
|
|
||||||
dontFixup = true;
|
|
||||||
}
|
|
|
@ -1,31 +0,0 @@
|
||||||
diff --git a/lib/sw_apps/zynq_fsbl/src/Makefile b/lib/sw_apps/zynq_fsbl/src/Makefile
|
|
||||||
index 0e3ccdf1c5..a5b02f386e 100644
|
|
||||||
--- a/lib/sw_apps/zynq_fsbl/src/Makefile
|
|
||||||
+++ b/lib/sw_apps/zynq_fsbl/src/Makefile
|
|
||||||
@@ -71,11 +71,14 @@ endif
|
|
||||||
all: $(EXEC)
|
|
||||||
|
|
||||||
$(EXEC): $(LIBS) $(OBJS) $(INCLUDES)
|
|
||||||
- cp $(BSP_DIR)/$(BOARD)/ps7_init.* .
|
|
||||||
$(LINKER) $(LD1FLAGS) -o $@ $(OBJS) $(LDFLAGS)
|
|
||||||
rm -rf $(OBJS)
|
|
||||||
-
|
|
||||||
-
|
|
||||||
+
|
|
||||||
+.PHONY: ps7_init
|
|
||||||
+
|
|
||||||
+ps7_init:
|
|
||||||
+ cp $(BSP_DIR)/$(BOARD)/ps7_init.* .
|
|
||||||
+
|
|
||||||
$(LIBS):
|
|
||||||
echo "Copying BSP files"
|
|
||||||
$(BSP_DIR)/copy_bsp.sh $(BOARD) $(CC)
|
|
||||||
@@ -86,7 +89,7 @@ $(LIBS):
|
|
||||||
make -C $(BSP_DIR) -k all "CC=armcc" "AR=armar" "C_FLAGS= -O2 -c" "EC_FLAGS=--debug --wchar32"; \
|
|
||||||
fi;
|
|
||||||
|
|
||||||
-%.o:%.c
|
|
||||||
+%.o:%.c ps7_init
|
|
||||||
$(CC) $(CC_FLAGS) $(CFLAGS) $(ECFLAGS) -c $< -o $@ $(INCLUDEPATH)
|
|
||||||
|
|
||||||
%.o:%.S
|
|
|
@ -1,134 +0,0 @@
|
||||||
{ pkgs ? import <nixpkgs> }:
|
|
||||||
let
|
|
||||||
|
|
||||||
platform = "arm-none-eabi";
|
|
||||||
|
|
||||||
binutils-pkg = { stdenv, buildPackages
|
|
||||||
, fetchurl, zlib
|
|
||||||
, extraConfigureFlags ? []
|
|
||||||
}:
|
|
||||||
|
|
||||||
stdenv.mkDerivation rec {
|
|
||||||
basename = "binutils";
|
|
||||||
version = "2.30";
|
|
||||||
name = "${basename}-${platform}-${version}";
|
|
||||||
src = fetchurl {
|
|
||||||
url = "https://ftp.gnu.org/gnu/binutils/binutils-${version}.tar.bz2";
|
|
||||||
sha256 = "028cklfqaab24glva1ks2aqa1zxa6w6xmc8q34zs1sb7h22dxspg";
|
|
||||||
};
|
|
||||||
configureFlags = [
|
|
||||||
"--enable-deterministic-archives"
|
|
||||||
"--target=${platform}"
|
|
||||||
"--with-cpu=cortex-a9"
|
|
||||||
"--with-fpu=vfpv3"
|
|
||||||
"--with-float=hard"
|
|
||||||
"--with-mode=thumb"
|
|
||||||
] ++ extraConfigureFlags;
|
|
||||||
outputs = [ "out" "info" "man" ];
|
|
||||||
depsBuildBuild = [ buildPackages.stdenv.cc ];
|
|
||||||
buildInputs = [ zlib ];
|
|
||||||
enableParallelBuilding = true;
|
|
||||||
meta = {
|
|
||||||
description = "Tools for manipulating binaries (linker, assembler, etc.)";
|
|
||||||
longDescription = ''
|
|
||||||
The GNU Binutils are a collection of binary tools. The main
|
|
||||||
ones are `ld' (the GNU linker) and `as' (the GNU assembler).
|
|
||||||
They also include the BFD (Binary File Descriptor) library,
|
|
||||||
`gprof', `nm', `strip', etc.
|
|
||||||
'';
|
|
||||||
homepage = http://www.gnu.org/software/binutils/;
|
|
||||||
license = stdenv.lib.licenses.gpl3Plus;
|
|
||||||
/* Give binutils a lower priority than gcc-wrapper to prevent a
|
|
||||||
collision due to the ld/as wrappers/symlinks in the latter. */
|
|
||||||
priority = "10";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
gcc-pkg = { stdenv, buildPackages
|
|
||||||
, fetchurl, gmp, mpfr, libmpc, platform-binutils
|
|
||||||
, extraConfigureFlags ? []
|
|
||||||
}:
|
|
||||||
|
|
||||||
stdenv.mkDerivation rec {
|
|
||||||
basename = "gcc";
|
|
||||||
version = "9.1.0";
|
|
||||||
name = "${basename}-${platform}-${version}";
|
|
||||||
src = fetchurl {
|
|
||||||
url = "https://ftp.gnu.org/gnu/gcc/gcc-${version}/gcc-${version}.tar.xz";
|
|
||||||
sha256 = "1817nc2bqdc251k0lpc51cimna7v68xjrnvqzvc50q3ax4s6i9kr";
|
|
||||||
};
|
|
||||||
preConfigure =
|
|
||||||
''
|
|
||||||
mkdir build
|
|
||||||
cd build
|
|
||||||
'';
|
|
||||||
configureScript = "../configure";
|
|
||||||
configureFlags =
|
|
||||||
[ "--target=${platform}"
|
|
||||||
"--with-arch=armv7-a"
|
|
||||||
"--with-tune=cortex-a9"
|
|
||||||
"--with-fpu=vfpv3"
|
|
||||||
"--with-float=hard"
|
|
||||||
"--disable-libssp"
|
|
||||||
"--enable-languages=c"
|
|
||||||
"--with-as=${platform-binutils}/bin/${platform}-as"
|
|
||||||
"--with-ld=${platform-binutils}/bin/${platform}-ld" ] ++ extraConfigureFlags;
|
|
||||||
outputs = [ "out" "info" "man" ];
|
|
||||||
hardeningDisable = [ "format" "pie" ];
|
|
||||||
propagatedBuildInputs = [ gmp mpfr libmpc platform-binutils ];
|
|
||||||
enableParallelBuilding = true;
|
|
||||||
dontFixup = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
newlib-pkg = { stdenv, fetchurl, buildPackages, platform-binutils, platform-gcc }:
|
|
||||||
|
|
||||||
stdenv.mkDerivation rec {
|
|
||||||
pname = "newlib";
|
|
||||||
version = "3.1.0";
|
|
||||||
src = fetchurl {
|
|
||||||
url = "ftp://sourceware.org/pub/newlib/newlib-${version}.tar.gz";
|
|
||||||
sha256 = "0ahh3n079zjp7d9wynggwrnrs27440aac04340chf1p9476a2kzv";
|
|
||||||
};
|
|
||||||
|
|
||||||
nativeBuildInputs = [ platform-binutils platform-gcc ];
|
|
||||||
|
|
||||||
configureFlags = [
|
|
||||||
"--target=${platform}"
|
|
||||||
|
|
||||||
"--with-cpu=cortex-a9"
|
|
||||||
"--with-fpu=vfpv3"
|
|
||||||
"--with-float=hard"
|
|
||||||
"--with-mode=thumb"
|
|
||||||
"--enable-interwork"
|
|
||||||
"--disable-multilib"
|
|
||||||
|
|
||||||
"--disable-newlib-supplied-syscalls"
|
|
||||||
"--with-gnu-ld"
|
|
||||||
"--with-gnu-as"
|
|
||||||
"--disable-newlib-io-float"
|
|
||||||
"--disable-werror"
|
|
||||||
];
|
|
||||||
dontFixup = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
in rec {
|
|
||||||
binutils-bootstrap = pkgs.callPackage binutils-pkg { };
|
|
||||||
gcc-bootstrap = pkgs.callPackage gcc-pkg {
|
|
||||||
platform-binutils = binutils-bootstrap;
|
|
||||||
extraConfigureFlags = [ "--disable-libgcc" ];
|
|
||||||
};
|
|
||||||
newlib = pkgs.callPackage newlib-pkg {
|
|
||||||
platform-binutils = binutils-bootstrap;
|
|
||||||
platform-gcc = gcc-bootstrap;
|
|
||||||
};
|
|
||||||
binutils = pkgs.callPackage binutils-pkg {
|
|
||||||
extraConfigureFlags = [ "--with-lib-path=${newlib}/arm-none-eabi/lib" ];
|
|
||||||
};
|
|
||||||
gcc = pkgs.callPackage gcc-pkg {
|
|
||||||
platform-binutils = binutils;
|
|
||||||
extraConfigureFlags = [ "--enable-newlib" "--with-headers=${newlib}/arm-none-eabi/include" ];
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -1,24 +0,0 @@
|
||||||
{ pkgs }:
|
|
||||||
|
|
||||||
pkgs.stdenv.mkDerivation {
|
|
||||||
pname = "mkbootimage";
|
|
||||||
version = "2.2";
|
|
||||||
|
|
||||||
src = pkgs.fetchFromGitHub {
|
|
||||||
owner = "antmicro";
|
|
||||||
repo = "zynq-mkbootimage";
|
|
||||||
rev = "4ee42d782a9ba65725ed165a4916853224a8edf7";
|
|
||||||
sha256 = "1k1mbsngqadqihzjgvwvsrkvryxy5ladpxd9yh9iqn2s7fxqwqa9";
|
|
||||||
};
|
|
||||||
|
|
||||||
propagatedBuildInputs = [ pkgs.libelf pkgs.pcre ];
|
|
||||||
patchPhase =
|
|
||||||
''
|
|
||||||
substituteInPlace Makefile --replace "git rev-parse --short HEAD" "echo nix"
|
|
||||||
'';
|
|
||||||
installPhase =
|
|
||||||
''
|
|
||||||
mkdir -p $out/bin
|
|
||||||
cp mkbootimage $out/bin
|
|
||||||
'';
|
|
||||||
}
|
|
|
@ -1,10 +0,0 @@
|
||||||
let
|
|
||||||
pkgs = import <nixpkgs> {};
|
|
||||||
overlay = pkgs.fetchFromGitHub {
|
|
||||||
owner = "mozilla";
|
|
||||||
repo = "nixpkgs-mozilla";
|
|
||||||
rev = "efda5b357451dbb0431f983cca679ae3cd9b9829";
|
|
||||||
sha256 = "11wqrg86g3qva67vnk81ynvqyfj0zxk83cbrf0p9hsvxiwxs8469";
|
|
||||||
};
|
|
||||||
in
|
|
||||||
import overlay
|
|
|
@ -1,24 +0,0 @@
|
||||||
{ pkgs }:
|
|
||||||
|
|
||||||
let
|
|
||||||
rustcSrc = pkgs.fetchgit {
|
|
||||||
url = "https://github.com/rust-lang/rust.git";
|
|
||||||
# sync with git_commit_hash from pkg.rust in channel-rust-nightly.toml
|
|
||||||
rev = "5ef299eb9805b4c86b227b718b39084e8bf24454";
|
|
||||||
sha256 = "0gc9hmb1sfkaf3ba8fsynl1n6bs8nk65hbhhx7ss89dfkrsxrn0x";
|
|
||||||
fetchSubmodules = true;
|
|
||||||
};
|
|
||||||
rustManifest = ./channel-rust-nightly.toml;
|
|
||||||
|
|
||||||
targets = [];
|
|
||||||
rustChannelOfTargets = _channel: _date: targets:
|
|
||||||
(pkgs.lib.rustLib.fromManifestFile rustManifest {
|
|
||||||
inherit (pkgs) stdenv fetchurl patchelf;
|
|
||||||
}).rust.override { inherit targets; };
|
|
||||||
rust =
|
|
||||||
rustChannelOfTargets "nightly" null targets;
|
|
||||||
in
|
|
||||||
pkgs.recurseIntoAttrs (pkgs.makeRustPlatform {
|
|
||||||
rustc = rust // { src = rustcSrc; };
|
|
||||||
cargo = rust;
|
|
||||||
})
|
|
|
@ -6,6 +6,7 @@ set SMP 1
|
||||||
|
|
||||||
source ./zynq-7000.cfg
|
source ./zynq-7000.cfg
|
||||||
source ./xilinx-tcl.cfg
|
source ./xilinx-tcl.cfg
|
||||||
|
source ./ps7_init.tcl
|
||||||
|
|
||||||
reset_config srst_only srst_push_pull
|
reset_config srst_only srst_push_pull
|
||||||
|
|
||||||
|
@ -30,10 +31,11 @@ pld device virtex2 zynq.tap 1
|
||||||
init
|
init
|
||||||
xc7_program zynq.tap
|
xc7_program zynq.tap
|
||||||
|
|
||||||
reset halt
|
xilinx_ps7_init
|
||||||
|
|
||||||
# Disable MMU
|
# Disable MMU
|
||||||
targets $_TARGETNAME_1
|
targets $_TARGETNAME_1
|
||||||
arm mcr 15 0 1 0 0 [expr [arm mrc 15 0 1 0 0] & ~0xd]
|
arm mcr 15 0 1 0 0 [expr [arm mrc 15 0 1 0 0] & ~0xd]
|
||||||
targets $_TARGETNAME_0
|
targets $_TARGETNAME_0
|
||||||
arm mcr 15 0 1 0 0 [expr [arm mrc 15 0 1 0 0] & ~0xd]
|
arm mcr 15 0 1 0 0 [expr [arm mrc 15 0 1 0 0] & ~0xd]
|
||||||
|
|
||||||
|
|
|
@ -1,12 +0,0 @@
|
||||||
# this is the original file from OpenOCD, but with ftdi_device_desc
|
|
||||||
# removed because some cables don't have it programmed.
|
|
||||||
|
|
||||||
# this supports JTAG-HS2 (and apparently Nexys4 as well)
|
|
||||||
|
|
||||||
interface ftdi
|
|
||||||
ftdi_vid_pid 0x0403 0x6014
|
|
||||||
|
|
||||||
ftdi_channel 0
|
|
||||||
ftdi_layout_init 0x00e8 0x60eb
|
|
||||||
|
|
||||||
reset_config none
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
#
|
||||||
|
# Digilent JTAG-SMT2-NC
|
||||||
|
#
|
||||||
|
# http://store.digilentinc.com/jtag-smt2-nc-surface-mount-programming-module/
|
||||||
|
# https://reference.digilentinc.com/_media/jtag_smt2nc/jtag-smt2-nc_rm.pdf
|
||||||
|
#
|
||||||
|
# Based on reference sheet (above) and Xilinx KCU105 schematics
|
||||||
|
# https://www.xilinx.com/products/boards-and-kits/kcu105.html#documentation
|
||||||
|
#
|
||||||
|
# Note that the digilent_jtag_smt2 layout does not work and hangs while
|
||||||
|
# the ftdi_device_desc from digilent_hs2 is wrong.
|
||||||
|
|
||||||
|
interface ftdi
|
||||||
|
ftdi_device_desc "Digilent USB Device"
|
||||||
|
ftdi_vid_pid 0x0403 0x6014
|
||||||
|
ftdi_channel 0
|
||||||
|
ftdi_layout_init 0x00e8 0x60eb
|
||||||
|
ftdi_layout_signal nSRST -data 0x2000
|
|
@ -0,0 +1,28 @@
|
||||||
|
def zynq-connect
|
||||||
|
target remote :3333
|
||||||
|
end
|
||||||
|
|
||||||
|
def zynq-fsbl-restart
|
||||||
|
mon xilinx_ps7_init
|
||||||
|
end
|
||||||
|
|
||||||
|
def zynq-restart
|
||||||
|
mon xilinx_ps7_init
|
||||||
|
load
|
||||||
|
end
|
||||||
|
|
||||||
|
# easily typed shortcuts
|
||||||
|
# device connect
|
||||||
|
def dc
|
||||||
|
zynq-connect
|
||||||
|
end
|
||||||
|
# device restart
|
||||||
|
def dr
|
||||||
|
zynq-restart
|
||||||
|
end
|
||||||
|
|
||||||
|
def dfr
|
||||||
|
zynq-fsbl-restart
|
||||||
|
end
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,771 @@
|
||||||
|
proc ps7_pll_init_data_3_0 {} {
|
||||||
|
mwr -force 0XF8000008 0x0000DF0D
|
||||||
|
mask_write 0XF8000110 0x003FFFF0 0x000FA220
|
||||||
|
mask_write 0XF8000100 0x0007F000 0x00028000
|
||||||
|
mask_write 0XF8000100 0x00000010 0x00000010
|
||||||
|
mask_write 0XF8000100 0x00000001 0x00000001
|
||||||
|
mask_write 0XF8000100 0x00000001 0x00000000
|
||||||
|
mask_poll 0XF800010C 0x00000001
|
||||||
|
mask_write 0XF8000100 0x00000010 0x00000000
|
||||||
|
mask_write 0XF8000120 0x1F003F30 0x1F000200
|
||||||
|
mask_write 0XF8000114 0x003FFFF0 0x0012C220
|
||||||
|
mask_write 0XF8000104 0x0007F000 0x00020000
|
||||||
|
mask_write 0XF8000104 0x00000010 0x00000010
|
||||||
|
mask_write 0XF8000104 0x00000001 0x00000001
|
||||||
|
mask_write 0XF8000104 0x00000001 0x00000000
|
||||||
|
mask_poll 0XF800010C 0x00000002
|
||||||
|
mask_write 0XF8000104 0x00000010 0x00000000
|
||||||
|
mask_write 0XF8000124 0xFFF00003 0x0C200003
|
||||||
|
mask_write 0XF8000118 0x003FFFF0 0x001452C0
|
||||||
|
mask_write 0XF8000108 0x0007F000 0x0001E000
|
||||||
|
mask_write 0XF8000108 0x00000010 0x00000010
|
||||||
|
mask_write 0XF8000108 0x00000001 0x00000001
|
||||||
|
mask_write 0XF8000108 0x00000001 0x00000000
|
||||||
|
mask_poll 0XF800010C 0x00000004
|
||||||
|
mask_write 0XF8000108 0x00000010 0x00000000
|
||||||
|
mwr -force 0XF8000004 0x0000767B
|
||||||
|
}
|
||||||
|
proc ps7_clock_init_data_3_0 {} {
|
||||||
|
mwr -force 0XF8000008 0x0000DF0D
|
||||||
|
mask_write 0XF8000128 0x03F03F01 0x00700F01
|
||||||
|
mask_write 0XF8000138 0x00000011 0x00000001
|
||||||
|
mask_write 0XF8000140 0x03F03F71 0x00100801
|
||||||
|
mask_write 0XF800014C 0x00003F31 0x00000501
|
||||||
|
mask_write 0XF8000150 0x00003F33 0x00001401
|
||||||
|
mask_write 0XF8000154 0x00003F33 0x00001402
|
||||||
|
mask_write 0XF8000168 0x00003F31 0x00000501
|
||||||
|
mask_write 0XF8000170 0x03F03F30 0x00200500
|
||||||
|
mask_write 0XF80001C4 0x00000001 0x00000001
|
||||||
|
mask_write 0XF800012C 0x01FFCCCD 0x01EC044D
|
||||||
|
mwr -force 0XF8000004 0x0000767B
|
||||||
|
}
|
||||||
|
proc ps7_ddr_init_data_3_0 {} {
|
||||||
|
mask_write 0XF8006000 0x0001FFFF 0x00000080
|
||||||
|
mask_write 0XF8006004 0x0007FFFF 0x00001081
|
||||||
|
mask_write 0XF8006008 0x03FFFFFF 0x03C0780F
|
||||||
|
mask_write 0XF800600C 0x03FFFFFF 0x02001001
|
||||||
|
mask_write 0XF8006010 0x03FFFFFF 0x00014001
|
||||||
|
mask_write 0XF8006014 0x001FFFFF 0x0004159B
|
||||||
|
mask_write 0XF8006018 0xF7FFFFFF 0x452460D2
|
||||||
|
mask_write 0XF800601C 0xFFFFFFFF 0x720238E5
|
||||||
|
mask_write 0XF8006020 0x7FDFFFFC 0x270872D0
|
||||||
|
mask_write 0XF8006024 0x0FFFFFC3 0x00000000
|
||||||
|
mask_write 0XF8006028 0x00003FFF 0x00002007
|
||||||
|
mask_write 0XF800602C 0xFFFFFFFF 0x00000008
|
||||||
|
mask_write 0XF8006030 0xFFFFFFFF 0x00040930
|
||||||
|
mask_write 0XF8006034 0x13FF3FFF 0x000116D4
|
||||||
|
mask_write 0XF8006038 0x00000003 0x00000000
|
||||||
|
mask_write 0XF800603C 0x000FFFFF 0x00000777
|
||||||
|
mask_write 0XF8006040 0xFFFFFFFF 0xFFF00000
|
||||||
|
mask_write 0XF8006044 0x0FFFFFFF 0x0FF66666
|
||||||
|
mask_write 0XF8006048 0x0003F03F 0x0003C008
|
||||||
|
mask_write 0XF8006050 0xFF0F8FFF 0x77010800
|
||||||
|
mask_write 0XF8006058 0x00010000 0x00000000
|
||||||
|
mask_write 0XF800605C 0x0000FFFF 0x00005003
|
||||||
|
mask_write 0XF8006060 0x000017FF 0x0000003E
|
||||||
|
mask_write 0XF8006064 0x00021FE0 0x00020000
|
||||||
|
mask_write 0XF8006068 0x03FFFFFF 0x00284141
|
||||||
|
mask_write 0XF800606C 0x0000FFFF 0x00001610
|
||||||
|
mask_write 0XF8006078 0x03FFFFFF 0x00466111
|
||||||
|
mask_write 0XF800607C 0x000FFFFF 0x00032222
|
||||||
|
mask_write 0XF80060A4 0xFFFFFFFF 0x10200802
|
||||||
|
mask_write 0XF80060A8 0x0FFFFFFF 0x0690CB73
|
||||||
|
mask_write 0XF80060AC 0x000001FF 0x000001FE
|
||||||
|
mask_write 0XF80060B0 0x1FFFFFFF 0x1CFFFFFF
|
||||||
|
mask_write 0XF80060B4 0x00000200 0x00000200
|
||||||
|
mask_write 0XF80060B8 0x01FFFFFF 0x00200066
|
||||||
|
mask_write 0XF80060C4 0x00000003 0x00000000
|
||||||
|
mask_write 0XF80060C8 0x000000FF 0x00000000
|
||||||
|
mask_write 0XF80060DC 0x00000001 0x00000000
|
||||||
|
mask_write 0XF80060F0 0x0000FFFF 0x00000000
|
||||||
|
mask_write 0XF80060F4 0x0000000F 0x00000008
|
||||||
|
mask_write 0XF8006114 0x000000FF 0x00000000
|
||||||
|
mask_write 0XF8006118 0x7FFFFFCF 0x40000001
|
||||||
|
mask_write 0XF800611C 0x7FFFFFCF 0x40000001
|
||||||
|
mask_write 0XF8006120 0x7FFFFFCF 0x40000001
|
||||||
|
mask_write 0XF8006124 0x7FFFFFCF 0x40000001
|
||||||
|
mask_write 0XF800612C 0x000FFFFF 0x00033C03
|
||||||
|
mask_write 0XF8006130 0x000FFFFF 0x00034003
|
||||||
|
mask_write 0XF8006134 0x000FFFFF 0x0002F400
|
||||||
|
mask_write 0XF8006138 0x000FFFFF 0x00030400
|
||||||
|
mask_write 0XF8006140 0x000FFFFF 0x00000035
|
||||||
|
mask_write 0XF8006144 0x000FFFFF 0x00000035
|
||||||
|
mask_write 0XF8006148 0x000FFFFF 0x00000035
|
||||||
|
mask_write 0XF800614C 0x000FFFFF 0x00000035
|
||||||
|
mask_write 0XF8006154 0x000FFFFF 0x00000083
|
||||||
|
mask_write 0XF8006158 0x000FFFFF 0x00000083
|
||||||
|
mask_write 0XF800615C 0x000FFFFF 0x00000080
|
||||||
|
mask_write 0XF8006160 0x000FFFFF 0x00000080
|
||||||
|
mask_write 0XF8006168 0x001FFFFF 0x00000124
|
||||||
|
mask_write 0XF800616C 0x001FFFFF 0x00000125
|
||||||
|
mask_write 0XF8006170 0x001FFFFF 0x00000112
|
||||||
|
mask_write 0XF8006174 0x001FFFFF 0x00000116
|
||||||
|
mask_write 0XF800617C 0x000FFFFF 0x000000C3
|
||||||
|
mask_write 0XF8006180 0x000FFFFF 0x000000C3
|
||||||
|
mask_write 0XF8006184 0x000FFFFF 0x000000C0
|
||||||
|
mask_write 0XF8006188 0x000FFFFF 0x000000C0
|
||||||
|
mask_write 0XF8006190 0x6FFFFEFE 0x00040080
|
||||||
|
mask_write 0XF8006194 0x000FFFFF 0x0001FC82
|
||||||
|
mask_write 0XF8006204 0xFFFFFFFF 0x00000000
|
||||||
|
mask_write 0XF8006208 0x000703FF 0x000003FF
|
||||||
|
mask_write 0XF800620C 0x000703FF 0x000003FF
|
||||||
|
mask_write 0XF8006210 0x000703FF 0x000003FF
|
||||||
|
mask_write 0XF8006214 0x000703FF 0x000003FF
|
||||||
|
mask_write 0XF8006218 0x000F03FF 0x000003FF
|
||||||
|
mask_write 0XF800621C 0x000F03FF 0x000003FF
|
||||||
|
mask_write 0XF8006220 0x000F03FF 0x000003FF
|
||||||
|
mask_write 0XF8006224 0x000F03FF 0x000003FF
|
||||||
|
mask_write 0XF80062A8 0x00000FF5 0x00000000
|
||||||
|
mask_write 0XF80062AC 0xFFFFFFFF 0x00000000
|
||||||
|
mask_write 0XF80062B0 0x003FFFFF 0x00005125
|
||||||
|
mask_write 0XF80062B4 0x0003FFFF 0x000012A8
|
||||||
|
mask_poll 0XF8000B74 0x00002000
|
||||||
|
mask_write 0XF8006000 0x0001FFFF 0x00000081
|
||||||
|
mask_poll 0XF8006054 0x00000007
|
||||||
|
}
|
||||||
|
proc ps7_mio_init_data_3_0 {} {
|
||||||
|
mwr -force 0XF8000008 0x0000DF0D
|
||||||
|
mask_write 0XF8000B40 0x00000FFF 0x00000600
|
||||||
|
mask_write 0XF8000B44 0x00000FFF 0x00000600
|
||||||
|
mask_write 0XF8000B48 0x00000FFF 0x00000672
|
||||||
|
mask_write 0XF8000B4C 0x00000FFF 0x00000672
|
||||||
|
mask_write 0XF8000B50 0x00000FFF 0x00000674
|
||||||
|
mask_write 0XF8000B54 0x00000FFF 0x00000674
|
||||||
|
mask_write 0XF8000B58 0x00000FFF 0x00000600
|
||||||
|
mask_write 0XF8000B5C 0xFFFFFFFF 0x0018C61C
|
||||||
|
mask_write 0XF8000B60 0xFFFFFFFF 0x00F9861C
|
||||||
|
mask_write 0XF8000B64 0xFFFFFFFF 0x00F9861C
|
||||||
|
mask_write 0XF8000B68 0xFFFFFFFF 0x00F9861C
|
||||||
|
mask_write 0XF8000B6C 0x00007FFF 0x00000209
|
||||||
|
mask_write 0XF8000B70 0x00000001 0x00000001
|
||||||
|
mask_write 0XF8000B70 0x00000021 0x00000020
|
||||||
|
mask_write 0XF8000B70 0x07FEFFFF 0x00000823
|
||||||
|
mask_write 0XF8000700 0x00003FFF 0x00000600
|
||||||
|
mask_write 0XF8000704 0x00003FFF 0x00000702
|
||||||
|
mask_write 0XF8000708 0x00003FFF 0x00000702
|
||||||
|
mask_write 0XF800070C 0x00003FFF 0x00000702
|
||||||
|
mask_write 0XF8000710 0x00003FFF 0x00000702
|
||||||
|
mask_write 0XF8000714 0x00003FFF 0x00000702
|
||||||
|
mask_write 0XF8000718 0x00003FFF 0x00000702
|
||||||
|
mask_write 0XF800071C 0x00003FFF 0x00000600
|
||||||
|
mask_write 0XF8000720 0x00003FFF 0x00000700
|
||||||
|
mask_write 0XF8000724 0x00003FFF 0x00000600
|
||||||
|
mask_write 0XF8000728 0x00003FFF 0x00000600
|
||||||
|
mask_write 0XF800072C 0x00003FFF 0x00000600
|
||||||
|
mask_write 0XF8000730 0x00003FFF 0x00000600
|
||||||
|
mask_write 0XF8000734 0x00003FFF 0x00000600
|
||||||
|
mask_write 0XF8000738 0x00003FFF 0x00000600
|
||||||
|
mask_write 0XF800073C 0x00003FFF 0x00000600
|
||||||
|
mask_write 0XF8000740 0x00003FFF 0x00000302
|
||||||
|
mask_write 0XF8000744 0x00003FFF 0x00000302
|
||||||
|
mask_write 0XF8000748 0x00003FFF 0x00000302
|
||||||
|
mask_write 0XF800074C 0x00003FFF 0x00000302
|
||||||
|
mask_write 0XF8000750 0x00003FFF 0x00000302
|
||||||
|
mask_write 0XF8000754 0x00003FFF 0x00000302
|
||||||
|
mask_write 0XF8000758 0x00003FFF 0x00000303
|
||||||
|
mask_write 0XF800075C 0x00003FFF 0x00000303
|
||||||
|
mask_write 0XF8000760 0x00003FFF 0x00000303
|
||||||
|
mask_write 0XF8000764 0x00003FFF 0x00000303
|
||||||
|
mask_write 0XF8000768 0x00003FFF 0x00000303
|
||||||
|
mask_write 0XF800076C 0x00003FFF 0x00000303
|
||||||
|
mask_write 0XF8000770 0x00003FFF 0x00000304
|
||||||
|
mask_write 0XF8000774 0x00003FFF 0x00000305
|
||||||
|
mask_write 0XF8000778 0x00003FFF 0x00000304
|
||||||
|
mask_write 0XF800077C 0x00003FFF 0x00000305
|
||||||
|
mask_write 0XF8000780 0x00003FFF 0x00000304
|
||||||
|
mask_write 0XF8000784 0x00003FFF 0x00000304
|
||||||
|
mask_write 0XF8000788 0x00003FFF 0x00000304
|
||||||
|
mask_write 0XF800078C 0x00003FFF 0x00000304
|
||||||
|
mask_write 0XF8000790 0x00003FFF 0x00000305
|
||||||
|
mask_write 0XF8000794 0x00003FFF 0x00000304
|
||||||
|
mask_write 0XF8000798 0x00003FFF 0x00000304
|
||||||
|
mask_write 0XF800079C 0x00003FFF 0x00000304
|
||||||
|
mask_write 0XF80007A0 0x00003FFF 0x00000380
|
||||||
|
mask_write 0XF80007A4 0x00003FFF 0x00000380
|
||||||
|
mask_write 0XF80007A8 0x00003FFF 0x00000380
|
||||||
|
mask_write 0XF80007AC 0x00003FFF 0x00000380
|
||||||
|
mask_write 0XF80007B0 0x00003FFF 0x00000380
|
||||||
|
mask_write 0XF80007B4 0x00003FFF 0x00000380
|
||||||
|
mask_write 0XF80007B8 0x00003F01 0x00000201
|
||||||
|
mask_write 0XF80007BC 0x00003F01 0x00000201
|
||||||
|
mask_write 0XF80007C0 0x00003FFF 0x000002E0
|
||||||
|
mask_write 0XF80007C4 0x00003FFF 0x000002E1
|
||||||
|
mask_write 0XF80007C8 0x00003FFF 0x00000200
|
||||||
|
mask_write 0XF80007CC 0x00003FFF 0x00000200
|
||||||
|
mask_write 0XF80007D0 0x00003FFF 0x00000280
|
||||||
|
mask_write 0XF80007D4 0x00003FFF 0x00000280
|
||||||
|
mask_write 0XF8000830 0x003F003F 0x002F002E
|
||||||
|
mwr -force 0XF8000004 0x0000767B
|
||||||
|
}
|
||||||
|
proc ps7_peripherals_init_data_3_0 {} {
|
||||||
|
mwr -force 0XF8000008 0x0000DF0D
|
||||||
|
mask_write 0XF8000B48 0x00000180 0x00000180
|
||||||
|
mask_write 0XF8000B4C 0x00000180 0x00000180
|
||||||
|
mask_write 0XF8000B50 0x00000180 0x00000180
|
||||||
|
mask_write 0XF8000B54 0x00000180 0x00000180
|
||||||
|
mwr -force 0XF8000004 0x0000767B
|
||||||
|
mask_write 0XE0001034 0x000000FF 0x00000006
|
||||||
|
mask_write 0XE0001018 0x0000FFFF 0x0000003E
|
||||||
|
mask_write 0XE0001000 0x000001FF 0x00000017
|
||||||
|
mask_write 0XE0001004 0x000003FF 0x00000020
|
||||||
|
mask_write 0XE000D000 0x00080000 0x00080000
|
||||||
|
mask_write 0XF8007000 0x20000000 0x00000000
|
||||||
|
}
|
||||||
|
proc ps7_post_config_3_0 {} {
|
||||||
|
mwr -force 0XF8000008 0x0000DF0D
|
||||||
|
mask_write 0XF8000900 0x0000000F 0x0000000F
|
||||||
|
mask_write 0XF8000240 0xFFFFFFFF 0x00000000
|
||||||
|
mwr -force 0XF8000004 0x0000767B
|
||||||
|
}
|
||||||
|
proc ps7_debug_3_0 {} {
|
||||||
|
mwr -force 0XF8898FB0 0xC5ACCE55
|
||||||
|
mwr -force 0XF8899FB0 0xC5ACCE55
|
||||||
|
mwr -force 0XF8809FB0 0xC5ACCE55
|
||||||
|
}
|
||||||
|
proc ps7_pll_init_data_2_0 {} {
|
||||||
|
mwr -force 0XF8000008 0x0000DF0D
|
||||||
|
mask_write 0XF8000110 0x003FFFF0 0x000FA220
|
||||||
|
mask_write 0XF8000100 0x0007F000 0x00028000
|
||||||
|
mask_write 0XF8000100 0x00000010 0x00000010
|
||||||
|
mask_write 0XF8000100 0x00000001 0x00000001
|
||||||
|
mask_write 0XF8000100 0x00000001 0x00000000
|
||||||
|
mask_poll 0XF800010C 0x00000001
|
||||||
|
mask_write 0XF8000100 0x00000010 0x00000000
|
||||||
|
mask_write 0XF8000120 0x1F003F30 0x1F000200
|
||||||
|
mask_write 0XF8000114 0x003FFFF0 0x0012C220
|
||||||
|
mask_write 0XF8000104 0x0007F000 0x00020000
|
||||||
|
mask_write 0XF8000104 0x00000010 0x00000010
|
||||||
|
mask_write 0XF8000104 0x00000001 0x00000001
|
||||||
|
mask_write 0XF8000104 0x00000001 0x00000000
|
||||||
|
mask_poll 0XF800010C 0x00000002
|
||||||
|
mask_write 0XF8000104 0x00000010 0x00000000
|
||||||
|
mask_write 0XF8000124 0xFFF00003 0x0C200003
|
||||||
|
mask_write 0XF8000118 0x003FFFF0 0x001452C0
|
||||||
|
mask_write 0XF8000108 0x0007F000 0x0001E000
|
||||||
|
mask_write 0XF8000108 0x00000010 0x00000010
|
||||||
|
mask_write 0XF8000108 0x00000001 0x00000001
|
||||||
|
mask_write 0XF8000108 0x00000001 0x00000000
|
||||||
|
mask_poll 0XF800010C 0x00000004
|
||||||
|
mask_write 0XF8000108 0x00000010 0x00000000
|
||||||
|
mwr -force 0XF8000004 0x0000767B
|
||||||
|
}
|
||||||
|
proc ps7_clock_init_data_2_0 {} {
|
||||||
|
mwr -force 0XF8000008 0x0000DF0D
|
||||||
|
mask_write 0XF8000128 0x03F03F01 0x00700F01
|
||||||
|
mask_write 0XF8000138 0x00000011 0x00000001
|
||||||
|
mask_write 0XF8000140 0x03F03F71 0x00100801
|
||||||
|
mask_write 0XF800014C 0x00003F31 0x00000501
|
||||||
|
mask_write 0XF8000150 0x00003F33 0x00001401
|
||||||
|
mask_write 0XF8000154 0x00003F33 0x00001402
|
||||||
|
mask_write 0XF8000168 0x00003F31 0x00000501
|
||||||
|
mask_write 0XF8000170 0x03F03F30 0x00200500
|
||||||
|
mask_write 0XF80001C4 0x00000001 0x00000001
|
||||||
|
mask_write 0XF800012C 0x01FFCCCD 0x01EC044D
|
||||||
|
mwr -force 0XF8000004 0x0000767B
|
||||||
|
}
|
||||||
|
proc ps7_ddr_init_data_2_0 {} {
|
||||||
|
mask_write 0XF8006000 0x0001FFFF 0x00000080
|
||||||
|
mask_write 0XF8006004 0x1FFFFFFF 0x00081081
|
||||||
|
mask_write 0XF8006008 0x03FFFFFF 0x03C0780F
|
||||||
|
mask_write 0XF800600C 0x03FFFFFF 0x02001001
|
||||||
|
mask_write 0XF8006010 0x03FFFFFF 0x00014001
|
||||||
|
mask_write 0XF8006014 0x001FFFFF 0x0004159B
|
||||||
|
mask_write 0XF8006018 0xF7FFFFFF 0x452460D2
|
||||||
|
mask_write 0XF800601C 0xFFFFFFFF 0x720238E5
|
||||||
|
mask_write 0XF8006020 0xFFFFFFFC 0x272872D0
|
||||||
|
mask_write 0XF8006024 0x0FFFFFFF 0x0000003C
|
||||||
|
mask_write 0XF8006028 0x00003FFF 0x00002007
|
||||||
|
mask_write 0XF800602C 0xFFFFFFFF 0x00000008
|
||||||
|
mask_write 0XF8006030 0xFFFFFFFF 0x00040930
|
||||||
|
mask_write 0XF8006034 0x13FF3FFF 0x000116D4
|
||||||
|
mask_write 0XF8006038 0x00001FC3 0x00000000
|
||||||
|
mask_write 0XF800603C 0x000FFFFF 0x00000777
|
||||||
|
mask_write 0XF8006040 0xFFFFFFFF 0xFFF00000
|
||||||
|
mask_write 0XF8006044 0x0FFFFFFF 0x0FF66666
|
||||||
|
mask_write 0XF8006048 0x3FFFFFFF 0x0003C248
|
||||||
|
mask_write 0XF8006050 0xFF0F8FFF 0x77010800
|
||||||
|
mask_write 0XF8006058 0x0001FFFF 0x00000101
|
||||||
|
mask_write 0XF800605C 0x0000FFFF 0x00005003
|
||||||
|
mask_write 0XF8006060 0x000017FF 0x0000003E
|
||||||
|
mask_write 0XF8006064 0x00021FE0 0x00020000
|
||||||
|
mask_write 0XF8006068 0x03FFFFFF 0x00284141
|
||||||
|
mask_write 0XF800606C 0x0000FFFF 0x00001610
|
||||||
|
mask_write 0XF8006078 0x03FFFFFF 0x00466111
|
||||||
|
mask_write 0XF800607C 0x000FFFFF 0x00032222
|
||||||
|
mask_write 0XF80060A0 0x00FFFFFF 0x00008000
|
||||||
|
mask_write 0XF80060A4 0xFFFFFFFF 0x10200802
|
||||||
|
mask_write 0XF80060A8 0x0FFFFFFF 0x0690CB73
|
||||||
|
mask_write 0XF80060AC 0x000001FF 0x000001FE
|
||||||
|
mask_write 0XF80060B0 0x1FFFFFFF 0x1CFFFFFF
|
||||||
|
mask_write 0XF80060B4 0x000007FF 0x00000200
|
||||||
|
mask_write 0XF80060B8 0x01FFFFFF 0x00200066
|
||||||
|
mask_write 0XF80060C4 0x00000003 0x00000000
|
||||||
|
mask_write 0XF80060C8 0x000000FF 0x00000000
|
||||||
|
mask_write 0XF80060DC 0x00000001 0x00000000
|
||||||
|
mask_write 0XF80060F0 0x0000FFFF 0x00000000
|
||||||
|
mask_write 0XF80060F4 0x0000000F 0x00000008
|
||||||
|
mask_write 0XF8006114 0x000000FF 0x00000000
|
||||||
|
mask_write 0XF8006118 0x7FFFFFFF 0x40000001
|
||||||
|
mask_write 0XF800611C 0x7FFFFFFF 0x40000001
|
||||||
|
mask_write 0XF8006120 0x7FFFFFFF 0x40000001
|
||||||
|
mask_write 0XF8006124 0x7FFFFFFF 0x40000001
|
||||||
|
mask_write 0XF800612C 0x000FFFFF 0x00033C03
|
||||||
|
mask_write 0XF8006130 0x000FFFFF 0x00034003
|
||||||
|
mask_write 0XF8006134 0x000FFFFF 0x0002F400
|
||||||
|
mask_write 0XF8006138 0x000FFFFF 0x00030400
|
||||||
|
mask_write 0XF8006140 0x000FFFFF 0x00000035
|
||||||
|
mask_write 0XF8006144 0x000FFFFF 0x00000035
|
||||||
|
mask_write 0XF8006148 0x000FFFFF 0x00000035
|
||||||
|
mask_write 0XF800614C 0x000FFFFF 0x00000035
|
||||||
|
mask_write 0XF8006154 0x000FFFFF 0x00000083
|
||||||
|
mask_write 0XF8006158 0x000FFFFF 0x00000083
|
||||||
|
mask_write 0XF800615C 0x000FFFFF 0x00000080
|
||||||
|
mask_write 0XF8006160 0x000FFFFF 0x00000080
|
||||||
|
mask_write 0XF8006168 0x001FFFFF 0x00000124
|
||||||
|
mask_write 0XF800616C 0x001FFFFF 0x00000125
|
||||||
|
mask_write 0XF8006170 0x001FFFFF 0x00000112
|
||||||
|
mask_write 0XF8006174 0x001FFFFF 0x00000116
|
||||||
|
mask_write 0XF800617C 0x000FFFFF 0x000000C3
|
||||||
|
mask_write 0XF8006180 0x000FFFFF 0x000000C3
|
||||||
|
mask_write 0XF8006184 0x000FFFFF 0x000000C0
|
||||||
|
mask_write 0XF8006188 0x000FFFFF 0x000000C0
|
||||||
|
mask_write 0XF8006190 0xFFFFFFFF 0x10040080
|
||||||
|
mask_write 0XF8006194 0x000FFFFF 0x0001FC82
|
||||||
|
mask_write 0XF8006204 0xFFFFFFFF 0x00000000
|
||||||
|
mask_write 0XF8006208 0x000F03FF 0x000803FF
|
||||||
|
mask_write 0XF800620C 0x000F03FF 0x000803FF
|
||||||
|
mask_write 0XF8006210 0x000F03FF 0x000803FF
|
||||||
|
mask_write 0XF8006214 0x000F03FF 0x000803FF
|
||||||
|
mask_write 0XF8006218 0x000F03FF 0x000003FF
|
||||||
|
mask_write 0XF800621C 0x000F03FF 0x000003FF
|
||||||
|
mask_write 0XF8006220 0x000F03FF 0x000003FF
|
||||||
|
mask_write 0XF8006224 0x000F03FF 0x000003FF
|
||||||
|
mask_write 0XF80062A8 0x00000FF7 0x00000000
|
||||||
|
mask_write 0XF80062AC 0xFFFFFFFF 0x00000000
|
||||||
|
mask_write 0XF80062B0 0x003FFFFF 0x00005125
|
||||||
|
mask_write 0XF80062B4 0x0003FFFF 0x000012A8
|
||||||
|
mask_poll 0XF8000B74 0x00002000
|
||||||
|
mask_write 0XF8006000 0x0001FFFF 0x00000081
|
||||||
|
mask_poll 0XF8006054 0x00000007
|
||||||
|
}
|
||||||
|
proc ps7_mio_init_data_2_0 {} {
|
||||||
|
mwr -force 0XF8000008 0x0000DF0D
|
||||||
|
mask_write 0XF8000B40 0x00000FFF 0x00000600
|
||||||
|
mask_write 0XF8000B44 0x00000FFF 0x00000600
|
||||||
|
mask_write 0XF8000B48 0x00000FFF 0x00000672
|
||||||
|
mask_write 0XF8000B4C 0x00000FFF 0x00000672
|
||||||
|
mask_write 0XF8000B50 0x00000FFF 0x00000674
|
||||||
|
mask_write 0XF8000B54 0x00000FFF 0x00000674
|
||||||
|
mask_write 0XF8000B58 0x00000FFF 0x00000600
|
||||||
|
mask_write 0XF8000B5C 0xFFFFFFFF 0x0018C61C
|
||||||
|
mask_write 0XF8000B60 0xFFFFFFFF 0x00F9861C
|
||||||
|
mask_write 0XF8000B64 0xFFFFFFFF 0x00F9861C
|
||||||
|
mask_write 0XF8000B68 0xFFFFFFFF 0x00F9861C
|
||||||
|
mask_write 0XF8000B6C 0x00007FFF 0x00000209
|
||||||
|
mask_write 0XF8000B70 0x00000021 0x00000021
|
||||||
|
mask_write 0XF8000B70 0x00000021 0x00000020
|
||||||
|
mask_write 0XF8000B70 0x07FFFFFF 0x00000823
|
||||||
|
mask_write 0XF8000700 0x00003FFF 0x00000600
|
||||||
|
mask_write 0XF8000704 0x00003FFF 0x00000702
|
||||||
|
mask_write 0XF8000708 0x00003FFF 0x00000702
|
||||||
|
mask_write 0XF800070C 0x00003FFF 0x00000702
|
||||||
|
mask_write 0XF8000710 0x00003FFF 0x00000702
|
||||||
|
mask_write 0XF8000714 0x00003FFF 0x00000702
|
||||||
|
mask_write 0XF8000718 0x00003FFF 0x00000702
|
||||||
|
mask_write 0XF800071C 0x00003FFF 0x00000600
|
||||||
|
mask_write 0XF8000720 0x00003FFF 0x00000700
|
||||||
|
mask_write 0XF8000724 0x00003FFF 0x00000600
|
||||||
|
mask_write 0XF8000728 0x00003FFF 0x00000600
|
||||||
|
mask_write 0XF800072C 0x00003FFF 0x00000600
|
||||||
|
mask_write 0XF8000730 0x00003FFF 0x00000600
|
||||||
|
mask_write 0XF8000734 0x00003FFF 0x00000600
|
||||||
|
mask_write 0XF8000738 0x00003FFF 0x00000600
|
||||||
|
mask_write 0XF800073C 0x00003FFF 0x00000600
|
||||||
|
mask_write 0XF8000740 0x00003FFF 0x00000302
|
||||||
|
mask_write 0XF8000744 0x00003FFF 0x00000302
|
||||||
|
mask_write 0XF8000748 0x00003FFF 0x00000302
|
||||||
|
mask_write 0XF800074C 0x00003FFF 0x00000302
|
||||||
|
mask_write 0XF8000750 0x00003FFF 0x00000302
|
||||||
|
mask_write 0XF8000754 0x00003FFF 0x00000302
|
||||||
|
mask_write 0XF8000758 0x00003FFF 0x00000303
|
||||||
|
mask_write 0XF800075C 0x00003FFF 0x00000303
|
||||||
|
mask_write 0XF8000760 0x00003FFF 0x00000303
|
||||||
|
mask_write 0XF8000764 0x00003FFF 0x00000303
|
||||||
|
mask_write 0XF8000768 0x00003FFF 0x00000303
|
||||||
|
mask_write 0XF800076C 0x00003FFF 0x00000303
|
||||||
|
mask_write 0XF8000770 0x00003FFF 0x00000304
|
||||||
|
mask_write 0XF8000774 0x00003FFF 0x00000305
|
||||||
|
mask_write 0XF8000778 0x00003FFF 0x00000304
|
||||||
|
mask_write 0XF800077C 0x00003FFF 0x00000305
|
||||||
|
mask_write 0XF8000780 0x00003FFF 0x00000304
|
||||||
|
mask_write 0XF8000784 0x00003FFF 0x00000304
|
||||||
|
mask_write 0XF8000788 0x00003FFF 0x00000304
|
||||||
|
mask_write 0XF800078C 0x00003FFF 0x00000304
|
||||||
|
mask_write 0XF8000790 0x00003FFF 0x00000305
|
||||||
|
mask_write 0XF8000794 0x00003FFF 0x00000304
|
||||||
|
mask_write 0XF8000798 0x00003FFF 0x00000304
|
||||||
|
mask_write 0XF800079C 0x00003FFF 0x00000304
|
||||||
|
mask_write 0XF80007A0 0x00003FFF 0x00000380
|
||||||
|
mask_write 0XF80007A4 0x00003FFF 0x00000380
|
||||||
|
mask_write 0XF80007A8 0x00003FFF 0x00000380
|
||||||
|
mask_write 0XF80007AC 0x00003FFF 0x00000380
|
||||||
|
mask_write 0XF80007B0 0x00003FFF 0x00000380
|
||||||
|
mask_write 0XF80007B4 0x00003FFF 0x00000380
|
||||||
|
mask_write 0XF80007B8 0x00003F01 0x00000201
|
||||||
|
mask_write 0XF80007BC 0x00003F01 0x00000201
|
||||||
|
mask_write 0XF80007C0 0x00003FFF 0x000002E0
|
||||||
|
mask_write 0XF80007C4 0x00003FFF 0x000002E1
|
||||||
|
mask_write 0XF80007C8 0x00003FFF 0x00000200
|
||||||
|
mask_write 0XF80007CC 0x00003FFF 0x00000200
|
||||||
|
mask_write 0XF80007D0 0x00003FFF 0x00000280
|
||||||
|
mask_write 0XF80007D4 0x00003FFF 0x00000280
|
||||||
|
mask_write 0XF8000830 0x003F003F 0x002F002E
|
||||||
|
mwr -force 0XF8000004 0x0000767B
|
||||||
|
}
|
||||||
|
proc ps7_peripherals_init_data_2_0 {} {
|
||||||
|
mwr -force 0XF8000008 0x0000DF0D
|
||||||
|
mask_write 0XF8000B48 0x00000180 0x00000180
|
||||||
|
mask_write 0XF8000B4C 0x00000180 0x00000180
|
||||||
|
mask_write 0XF8000B50 0x00000180 0x00000180
|
||||||
|
mask_write 0XF8000B54 0x00000180 0x00000180
|
||||||
|
mwr -force 0XF8000004 0x0000767B
|
||||||
|
mask_write 0XE0001034 0x000000FF 0x00000006
|
||||||
|
mask_write 0XE0001018 0x0000FFFF 0x0000003E
|
||||||
|
mask_write 0XE0001000 0x000001FF 0x00000017
|
||||||
|
mask_write 0XE0001004 0x00000FFF 0x00000020
|
||||||
|
mask_write 0XE000D000 0x00080000 0x00080000
|
||||||
|
mask_write 0XF8007000 0x20000000 0x00000000
|
||||||
|
}
|
||||||
|
proc ps7_post_config_2_0 {} {
|
||||||
|
mwr -force 0XF8000008 0x0000DF0D
|
||||||
|
mask_write 0XF8000900 0x0000000F 0x0000000F
|
||||||
|
mask_write 0XF8000240 0xFFFFFFFF 0x00000000
|
||||||
|
mwr -force 0XF8000004 0x0000767B
|
||||||
|
}
|
||||||
|
proc ps7_debug_2_0 {} {
|
||||||
|
mwr -force 0XF8898FB0 0xC5ACCE55
|
||||||
|
mwr -force 0XF8899FB0 0xC5ACCE55
|
||||||
|
mwr -force 0XF8809FB0 0xC5ACCE55
|
||||||
|
}
|
||||||
|
proc ps7_pll_init_data_1_0 {} {
|
||||||
|
mwr -force 0XF8000008 0x0000DF0D
|
||||||
|
mask_write 0XF8000110 0x003FFFF0 0x000FA220
|
||||||
|
mask_write 0XF8000100 0x0007F000 0x00028000
|
||||||
|
mask_write 0XF8000100 0x00000010 0x00000010
|
||||||
|
mask_write 0XF8000100 0x00000001 0x00000001
|
||||||
|
mask_write 0XF8000100 0x00000001 0x00000000
|
||||||
|
mask_poll 0XF800010C 0x00000001
|
||||||
|
mask_write 0XF8000100 0x00000010 0x00000000
|
||||||
|
mask_write 0XF8000120 0x1F003F30 0x1F000200
|
||||||
|
mask_write 0XF8000114 0x003FFFF0 0x0012C220
|
||||||
|
mask_write 0XF8000104 0x0007F000 0x00020000
|
||||||
|
mask_write 0XF8000104 0x00000010 0x00000010
|
||||||
|
mask_write 0XF8000104 0x00000001 0x00000001
|
||||||
|
mask_write 0XF8000104 0x00000001 0x00000000
|
||||||
|
mask_poll 0XF800010C 0x00000002
|
||||||
|
mask_write 0XF8000104 0x00000010 0x00000000
|
||||||
|
mask_write 0XF8000124 0xFFF00003 0x0C200003
|
||||||
|
mask_write 0XF8000118 0x003FFFF0 0x001452C0
|
||||||
|
mask_write 0XF8000108 0x0007F000 0x0001E000
|
||||||
|
mask_write 0XF8000108 0x00000010 0x00000010
|
||||||
|
mask_write 0XF8000108 0x00000001 0x00000001
|
||||||
|
mask_write 0XF8000108 0x00000001 0x00000000
|
||||||
|
mask_poll 0XF800010C 0x00000004
|
||||||
|
mask_write 0XF8000108 0x00000010 0x00000000
|
||||||
|
mwr -force 0XF8000004 0x0000767B
|
||||||
|
}
|
||||||
|
proc ps7_clock_init_data_1_0 {} {
|
||||||
|
mwr -force 0XF8000008 0x0000DF0D
|
||||||
|
mask_write 0XF8000128 0x03F03F01 0x00700F01
|
||||||
|
mask_write 0XF8000138 0x00000011 0x00000001
|
||||||
|
mask_write 0XF8000140 0x03F03F71 0x00100801
|
||||||
|
mask_write 0XF800014C 0x00003F31 0x00000501
|
||||||
|
mask_write 0XF8000150 0x00003F33 0x00001401
|
||||||
|
mask_write 0XF8000154 0x00003F33 0x00001402
|
||||||
|
mask_write 0XF8000168 0x00003F31 0x00000501
|
||||||
|
mask_write 0XF8000170 0x03F03F30 0x00200400
|
||||||
|
mask_write 0XF80001C4 0x00000001 0x00000001
|
||||||
|
mask_write 0XF800012C 0x01FFCCCD 0x01EC044D
|
||||||
|
mwr -force 0XF8000004 0x0000767B
|
||||||
|
}
|
||||||
|
proc ps7_ddr_init_data_1_0 {} {
|
||||||
|
mask_write 0XF8006000 0x0001FFFF 0x00000080
|
||||||
|
mask_write 0XF8006004 0x1FFFFFFF 0x00081081
|
||||||
|
mask_write 0XF8006008 0x03FFFFFF 0x03C0780F
|
||||||
|
mask_write 0XF800600C 0x03FFFFFF 0x02001001
|
||||||
|
mask_write 0XF8006010 0x03FFFFFF 0x00014001
|
||||||
|
mask_write 0XF8006014 0x001FFFFF 0x0004159B
|
||||||
|
mask_write 0XF8006018 0xF7FFFFFF 0x452460D2
|
||||||
|
mask_write 0XF800601C 0xFFFFFFFF 0x720238E5
|
||||||
|
mask_write 0XF8006020 0xFFFFFFFC 0x272872D0
|
||||||
|
mask_write 0XF8006024 0x0FFFFFFF 0x0000003C
|
||||||
|
mask_write 0XF8006028 0x00003FFF 0x00002007
|
||||||
|
mask_write 0XF800602C 0xFFFFFFFF 0x00000008
|
||||||
|
mask_write 0XF8006030 0xFFFFFFFF 0x00040930
|
||||||
|
mask_write 0XF8006034 0x13FF3FFF 0x000116D4
|
||||||
|
mask_write 0XF8006038 0x00001FC3 0x00000000
|
||||||
|
mask_write 0XF800603C 0x000FFFFF 0x00000777
|
||||||
|
mask_write 0XF8006040 0xFFFFFFFF 0xFFF00000
|
||||||
|
mask_write 0XF8006044 0x0FFFFFFF 0x0FF66666
|
||||||
|
mask_write 0XF8006048 0x3FFFFFFF 0x0003C248
|
||||||
|
mask_write 0XF8006050 0xFF0F8FFF 0x77010800
|
||||||
|
mask_write 0XF8006058 0x0001FFFF 0x00000101
|
||||||
|
mask_write 0XF800605C 0x0000FFFF 0x00005003
|
||||||
|
mask_write 0XF8006060 0x000017FF 0x0000003E
|
||||||
|
mask_write 0XF8006064 0x00021FE0 0x00020000
|
||||||
|
mask_write 0XF8006068 0x03FFFFFF 0x00284141
|
||||||
|
mask_write 0XF800606C 0x0000FFFF 0x00001610
|
||||||
|
mask_write 0XF80060A0 0x00FFFFFF 0x00008000
|
||||||
|
mask_write 0XF80060A4 0xFFFFFFFF 0x10200802
|
||||||
|
mask_write 0XF80060A8 0x0FFFFFFF 0x0690CB73
|
||||||
|
mask_write 0XF80060AC 0x000001FF 0x000001FE
|
||||||
|
mask_write 0XF80060B0 0x1FFFFFFF 0x1CFFFFFF
|
||||||
|
mask_write 0XF80060B4 0x000007FF 0x00000200
|
||||||
|
mask_write 0XF80060B8 0x01FFFFFF 0x00200066
|
||||||
|
mask_write 0XF80060C4 0x00000003 0x00000000
|
||||||
|
mask_write 0XF80060C8 0x000000FF 0x00000000
|
||||||
|
mask_write 0XF80060DC 0x00000001 0x00000000
|
||||||
|
mask_write 0XF80060F0 0x0000FFFF 0x00000000
|
||||||
|
mask_write 0XF80060F4 0x0000000F 0x00000008
|
||||||
|
mask_write 0XF8006114 0x000000FF 0x00000000
|
||||||
|
mask_write 0XF8006118 0x7FFFFFFF 0x40000001
|
||||||
|
mask_write 0XF800611C 0x7FFFFFFF 0x40000001
|
||||||
|
mask_write 0XF8006120 0x7FFFFFFF 0x40000001
|
||||||
|
mask_write 0XF8006124 0x7FFFFFFF 0x40000001
|
||||||
|
mask_write 0XF800612C 0x000FFFFF 0x00033C03
|
||||||
|
mask_write 0XF8006130 0x000FFFFF 0x00034003
|
||||||
|
mask_write 0XF8006134 0x000FFFFF 0x0002F400
|
||||||
|
mask_write 0XF8006138 0x000FFFFF 0x00030400
|
||||||
|
mask_write 0XF8006140 0x000FFFFF 0x00000035
|
||||||
|
mask_write 0XF8006144 0x000FFFFF 0x00000035
|
||||||
|
mask_write 0XF8006148 0x000FFFFF 0x00000035
|
||||||
|
mask_write 0XF800614C 0x000FFFFF 0x00000035
|
||||||
|
mask_write 0XF8006154 0x000FFFFF 0x00000083
|
||||||
|
mask_write 0XF8006158 0x000FFFFF 0x00000083
|
||||||
|
mask_write 0XF800615C 0x000FFFFF 0x00000080
|
||||||
|
mask_write 0XF8006160 0x000FFFFF 0x00000080
|
||||||
|
mask_write 0XF8006168 0x001FFFFF 0x00000124
|
||||||
|
mask_write 0XF800616C 0x001FFFFF 0x00000125
|
||||||
|
mask_write 0XF8006170 0x001FFFFF 0x00000112
|
||||||
|
mask_write 0XF8006174 0x001FFFFF 0x00000116
|
||||||
|
mask_write 0XF800617C 0x000FFFFF 0x000000C3
|
||||||
|
mask_write 0XF8006180 0x000FFFFF 0x000000C3
|
||||||
|
mask_write 0XF8006184 0x000FFFFF 0x000000C0
|
||||||
|
mask_write 0XF8006188 0x000FFFFF 0x000000C0
|
||||||
|
mask_write 0XF8006190 0xFFFFFFFF 0x10040080
|
||||||
|
mask_write 0XF8006194 0x000FFFFF 0x0001FC82
|
||||||
|
mask_write 0XF8006204 0xFFFFFFFF 0x00000000
|
||||||
|
mask_write 0XF8006208 0x000F03FF 0x000803FF
|
||||||
|
mask_write 0XF800620C 0x000F03FF 0x000803FF
|
||||||
|
mask_write 0XF8006210 0x000F03FF 0x000803FF
|
||||||
|
mask_write 0XF8006214 0x000F03FF 0x000803FF
|
||||||
|
mask_write 0XF8006218 0x000F03FF 0x000003FF
|
||||||
|
mask_write 0XF800621C 0x000F03FF 0x000003FF
|
||||||
|
mask_write 0XF8006220 0x000F03FF 0x000003FF
|
||||||
|
mask_write 0XF8006224 0x000F03FF 0x000003FF
|
||||||
|
mask_write 0XF80062A8 0x00000FF7 0x00000000
|
||||||
|
mask_write 0XF80062AC 0xFFFFFFFF 0x00000000
|
||||||
|
mask_write 0XF80062B0 0x003FFFFF 0x00005125
|
||||||
|
mask_write 0XF80062B4 0x0003FFFF 0x000012A8
|
||||||
|
mask_poll 0XF8000B74 0x00002000
|
||||||
|
mask_write 0XF8006000 0x0001FFFF 0x00000081
|
||||||
|
mask_poll 0XF8006054 0x00000007
|
||||||
|
}
|
||||||
|
proc ps7_mio_init_data_1_0 {} {
|
||||||
|
mwr -force 0XF8000008 0x0000DF0D
|
||||||
|
mask_write 0XF8000B40 0x00000FFF 0x00000600
|
||||||
|
mask_write 0XF8000B44 0x00000FFF 0x00000600
|
||||||
|
mask_write 0XF8000B48 0x00000FFF 0x00000672
|
||||||
|
mask_write 0XF8000B4C 0x00000FFF 0x00000672
|
||||||
|
mask_write 0XF8000B50 0x00000FFF 0x00000674
|
||||||
|
mask_write 0XF8000B54 0x00000FFF 0x00000674
|
||||||
|
mask_write 0XF8000B58 0x00000FFF 0x00000600
|
||||||
|
mask_write 0XF8000B5C 0xFFFFFFFF 0x0018C61C
|
||||||
|
mask_write 0XF8000B60 0xFFFFFFFF 0x00F9861C
|
||||||
|
mask_write 0XF8000B64 0xFFFFFFFF 0x00F9861C
|
||||||
|
mask_write 0XF8000B68 0xFFFFFFFF 0x00F9861C
|
||||||
|
mask_write 0XF8000B6C 0x000073FF 0x00000209
|
||||||
|
mask_write 0XF8000B70 0x00000021 0x00000021
|
||||||
|
mask_write 0XF8000B70 0x00000021 0x00000020
|
||||||
|
mask_write 0XF8000B70 0x07FFFFFF 0x00000823
|
||||||
|
mask_write 0XF8000700 0x00003FFF 0x00000600
|
||||||
|
mask_write 0XF8000704 0x00003FFF 0x00000702
|
||||||
|
mask_write 0XF8000708 0x00003FFF 0x00000702
|
||||||
|
mask_write 0XF800070C 0x00003FFF 0x00000702
|
||||||
|
mask_write 0XF8000710 0x00003FFF 0x00000702
|
||||||
|
mask_write 0XF8000714 0x00003FFF 0x00000702
|
||||||
|
mask_write 0XF8000718 0x00003FFF 0x00000702
|
||||||
|
mask_write 0XF800071C 0x00003FFF 0x00000600
|
||||||
|
mask_write 0XF8000720 0x00003FFF 0x00000700
|
||||||
|
mask_write 0XF8000724 0x00003FFF 0x00000600
|
||||||
|
mask_write 0XF8000728 0x00003FFF 0x00000600
|
||||||
|
mask_write 0XF800072C 0x00003FFF 0x00000600
|
||||||
|
mask_write 0XF8000730 0x00003FFF 0x00000600
|
||||||
|
mask_write 0XF8000734 0x00003FFF 0x00000600
|
||||||
|
mask_write 0XF8000738 0x00003FFF 0x00000600
|
||||||
|
mask_write 0XF800073C 0x00003FFF 0x00000600
|
||||||
|
mask_write 0XF8000740 0x00003FFF 0x00000302
|
||||||
|
mask_write 0XF8000744 0x00003FFF 0x00000302
|
||||||
|
mask_write 0XF8000748 0x00003FFF 0x00000302
|
||||||
|
mask_write 0XF800074C 0x00003FFF 0x00000302
|
||||||
|
mask_write 0XF8000750 0x00003FFF 0x00000302
|
||||||
|
mask_write 0XF8000754 0x00003FFF 0x00000302
|
||||||
|
mask_write 0XF8000758 0x00003FFF 0x00000303
|
||||||
|
mask_write 0XF800075C 0x00003FFF 0x00000303
|
||||||
|
mask_write 0XF8000760 0x00003FFF 0x00000303
|
||||||
|
mask_write 0XF8000764 0x00003FFF 0x00000303
|
||||||
|
mask_write 0XF8000768 0x00003FFF 0x00000303
|
||||||
|
mask_write 0XF800076C 0x00003FFF 0x00000303
|
||||||
|
mask_write 0XF8000770 0x00003FFF 0x00000304
|
||||||
|
mask_write 0XF8000774 0x00003FFF 0x00000305
|
||||||
|
mask_write 0XF8000778 0x00003FFF 0x00000304
|
||||||
|
mask_write 0XF800077C 0x00003FFF 0x00000305
|
||||||
|
mask_write 0XF8000780 0x00003FFF 0x00000304
|
||||||
|
mask_write 0XF8000784 0x00003FFF 0x00000304
|
||||||
|
mask_write 0XF8000788 0x00003FFF 0x00000304
|
||||||
|
mask_write 0XF800078C 0x00003FFF 0x00000304
|
||||||
|
mask_write 0XF8000790 0x00003FFF 0x00000305
|
||||||
|
mask_write 0XF8000794 0x00003FFF 0x00000304
|
||||||
|
mask_write 0XF8000798 0x00003FFF 0x00000304
|
||||||
|
mask_write 0XF800079C 0x00003FFF 0x00000304
|
||||||
|
mask_write 0XF80007A0 0x00003FFF 0x00000380
|
||||||
|
mask_write 0XF80007A4 0x00003FFF 0x00000380
|
||||||
|
mask_write 0XF80007A8 0x00003FFF 0x00000380
|
||||||
|
mask_write 0XF80007AC 0x00003FFF 0x00000380
|
||||||
|
mask_write 0XF80007B0 0x00003FFF 0x00000380
|
||||||
|
mask_write 0XF80007B4 0x00003FFF 0x00000380
|
||||||
|
mask_write 0XF80007B8 0x00003F01 0x00000201
|
||||||
|
mask_write 0XF80007BC 0x00003F01 0x00000201
|
||||||
|
mask_write 0XF80007C0 0x00003FFF 0x000002E0
|
||||||
|
mask_write 0XF80007C4 0x00003FFF 0x000002E1
|
||||||
|
mask_write 0XF80007C8 0x00003FFF 0x00000200
|
||||||
|
mask_write 0XF80007CC 0x00003FFF 0x00000200
|
||||||
|
mask_write 0XF80007D0 0x00003FFF 0x00000280
|
||||||
|
mask_write 0XF80007D4 0x00003FFF 0x00000280
|
||||||
|
mask_write 0XF8000830 0x003F003F 0x002F002E
|
||||||
|
mwr -force 0XF8000004 0x0000767B
|
||||||
|
}
|
||||||
|
proc ps7_peripherals_init_data_1_0 {} {
|
||||||
|
mwr -force 0XF8000008 0x0000DF0D
|
||||||
|
mask_write 0XF8000B48 0x00000180 0x00000180
|
||||||
|
mask_write 0XF8000B4C 0x00000180 0x00000180
|
||||||
|
mask_write 0XF8000B50 0x00000180 0x00000180
|
||||||
|
mask_write 0XF8000B54 0x00000180 0x00000180
|
||||||
|
mwr -force 0XF8000004 0x0000767B
|
||||||
|
mask_write 0XE0001034 0x000000FF 0x00000006
|
||||||
|
mask_write 0XE0001018 0x0000FFFF 0x0000003E
|
||||||
|
mask_write 0XE0001000 0x000001FF 0x00000017
|
||||||
|
mask_write 0XE0001004 0x00000FFF 0x00000020
|
||||||
|
mask_write 0XE000D000 0x00080000 0x00080000
|
||||||
|
mask_write 0XF8007000 0x20000000 0x00000000
|
||||||
|
}
|
||||||
|
proc ps7_post_config_1_0 {} {
|
||||||
|
mwr -force 0XF8000008 0x0000DF0D
|
||||||
|
mask_write 0XF8000900 0x0000000F 0x0000000F
|
||||||
|
mask_write 0XF8000240 0xFFFFFFFF 0x00000000
|
||||||
|
mwr -force 0XF8000004 0x0000767B
|
||||||
|
}
|
||||||
|
proc ps7_debug_1_0 {} {
|
||||||
|
mwr -force 0XF8898FB0 0xC5ACCE55
|
||||||
|
mwr -force 0XF8899FB0 0xC5ACCE55
|
||||||
|
mwr -force 0XF8809FB0 0xC5ACCE55
|
||||||
|
}
|
||||||
|
set PCW_SILICON_VER_1_0 "0x0"
|
||||||
|
set PCW_SILICON_VER_2_0 "0x1"
|
||||||
|
set PCW_SILICON_VER_3_0 "0x2"
|
||||||
|
set APU_FREQ 666666667
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
proc mask_poll { addr mask } {
|
||||||
|
set count 1
|
||||||
|
set curval "0x[string range [mrd $addr] end-8 end]"
|
||||||
|
set maskedval [expr {$curval & $mask}]
|
||||||
|
while { $maskedval == 0 } {
|
||||||
|
set curval "0x[string range [mrd $addr] end-8 end]"
|
||||||
|
set maskedval [expr {$curval & $mask}]
|
||||||
|
set count [ expr { $count + 1 } ]
|
||||||
|
if { $count == 100000000 } {
|
||||||
|
puts "Timeout Reached. Mask poll failed at ADDRESS: $addr MASK: $mask"
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
proc mask_delay { addr val } {
|
||||||
|
set delay [ get_number_of_cycles_for_delay $val ]
|
||||||
|
perf_reset_and_start_timer
|
||||||
|
set curval "0x[string range [mrd $addr] end-8 end]"
|
||||||
|
set maskedval [expr {$curval < $delay}]
|
||||||
|
while { $maskedval == 1 } {
|
||||||
|
set curval "0x[string range [mrd $addr] end-8 end]"
|
||||||
|
set maskedval [expr {$curval < $delay}]
|
||||||
|
}
|
||||||
|
perf_reset_clock
|
||||||
|
}
|
||||||
|
|
||||||
|
proc ps_version { } {
|
||||||
|
set si_ver "0x[string range [mrd 0xF8007080] end-8 end]"
|
||||||
|
set mask_sil_ver "0x[expr {$si_ver >> 28}]"
|
||||||
|
return $mask_sil_ver;
|
||||||
|
}
|
||||||
|
|
||||||
|
proc ps7_post_config {} {
|
||||||
|
|
||||||
|
ps7_post_config_1_0
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
proc ps7_debug {} {
|
||||||
|
ps7_debug_1_0
|
||||||
|
|
||||||
|
}
|
||||||
|
proc ps7_init {} {
|
||||||
|
|
||||||
|
ps7_mio_init_data_1_0
|
||||||
|
ps7_pll_init_data_1_0
|
||||||
|
ps7_clock_init_data_1_0
|
||||||
|
ps7_ddr_init_data_1_0
|
||||||
|
ps7_peripherals_init_data_1_0
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# For delay calculation using global timer
|
||||||
|
|
||||||
|
# start timer
|
||||||
|
proc perf_start_clock { } {
|
||||||
|
|
||||||
|
#writing SCU_GLOBAL_TIMER_CONTROL register
|
||||||
|
|
||||||
|
mask_write 0xF8F00208 0x00000109 0x00000009
|
||||||
|
}
|
||||||
|
|
||||||
|
# stop timer and reset timer count regs
|
||||||
|
proc perf_reset_clock { } {
|
||||||
|
perf_disable_clock
|
||||||
|
mask_write 0xF8F00200 0xFFFFFFFF 0x00000000
|
||||||
|
mask_write 0xF8F00204 0xFFFFFFFF 0x00000000
|
||||||
|
}
|
||||||
|
|
||||||
|
# Compute mask for given delay in miliseconds
|
||||||
|
proc get_number_of_cycles_for_delay { delay } {
|
||||||
|
|
||||||
|
# GTC is always clocked at 1/2 of the CPU frequency (CPU_3x2x)
|
||||||
|
variable APU_FREQ
|
||||||
|
return [ expr ($delay * $APU_FREQ /(2 * 1000))]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# stop timer
|
||||||
|
proc perf_disable_clock {} {
|
||||||
|
mask_write 0xF8F00208 0xFFFFFFFF 0x00000000
|
||||||
|
}
|
||||||
|
|
||||||
|
proc perf_reset_and_start_timer {} {
|
||||||
|
perf_reset_clock
|
||||||
|
perf_start_clock
|
||||||
|
}
|
||||||
|
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue