Compare commits

..

8 Commits
master ... eth

113 changed files with 5682 additions and 18182 deletions

View File

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

114
Cargo.lock generated
View File

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

View File

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

View File

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

View File

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

1
build.sh Executable file
View File

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

View File

@ -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";
};
}

View File

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

View File

@ -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/ :
{ {

View File

@ -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!");

View File

@ -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
);
}
}
}

View File

@ -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),
];

View File

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

View File

@ -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);
} }
} }

View File

@ -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);
} }
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,3 @@
//! PrimeCell DMA Controller (PL330)
mod regs;

View File

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

View File

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

View File

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

View File

@ -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()
} }

View File

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

View File

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

View File

@ -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();
} }

View File

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

View File

@ -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()
})
}
}
}

View File

@ -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!("");
}
}

View File

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

View File

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

View File

@ -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())
}
}

View File

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

View File

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

View File

@ -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(())
}
}

View File

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

View File

@ -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();
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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();
}
}

View File

@ -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();

View File

@ -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 = []

View File

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

View File

@ -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(())
}
}

View File

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

View File

@ -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(());
}
}

View File

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

View File

@ -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()));
}
}

View File

@ -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();
}
}

View File

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

View File

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

View File

@ -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 youre wanting to copy the contents of one file to another and youre
/// 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);
}
}

View File

@ -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::*;

View File

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

View File

@ -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");
}

View File

@ -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);
} }

View File

@ -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");
}
}

View File

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

View File

@ -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();
}
}

View File

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

View File

@ -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) };
} }
} }

View File

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

View File

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

View File

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

View File

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

View File

@ -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))
}
};
}

View File

@ -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;
}); });
} }

View File

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

View File

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

View File

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

View File

@ -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));
}); });
} }
} }

View File

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

View File

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

View File

@ -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
);
} }

View File

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

View File

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

View File

@ -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" ];
};
}

View File

@ -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
'';
}

View File

@ -1,10 +0,0 @@
let
pkgs = import <nixpkgs> {};
overlay = pkgs.fetchFromGitHub {
owner = "mozilla";
repo = "nixpkgs-mozilla";
rev = "efda5b357451dbb0431f983cca679ae3cd9b9829";
sha256 = "11wqrg86g3qva67vnk81ynvqyfj0zxk83cbrf0p9hsvxiwxs8469";
};
in
import overlay

View File

@ -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;
})

View File

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

View File

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

View File

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

28
openocd/gdb-zynq-commands Normal file
View File

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

771
openocd/ps7_init.tcl Normal file
View File

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