forked from M-Labs/artiq-zynq
Compare commits
15 Commits
Author | SHA1 | Date |
---|---|---|
mwojcik | a44a21436c | |
Sebastien Bourdeauducq | e946bcc3ed | |
Sebastien Bourdeauducq | 4f49c58d3b | |
Egor Savkin | 2a71b2fc62 | |
David Nadlinger | 2ad1970004 | |
Sebastien Bourdeauducq | d6bcc516cd | |
Egor Savkin | 99ebc2fcdb | |
Egor Savkin | 709aa8195b | |
Sebastien Bourdeauducq | 733f270819 | |
Sebastien Bourdeauducq | d30fb96674 | |
mwojcik | facc5808ef | |
mwojcik | 6f74cff4c5 | |
Sebastien Bourdeauducq | 3ea2690f15 | |
Sebastien Bourdeauducq | e02b8e25fe | |
Sebastien Bourdeauducq | 561efb0466 |
|
@ -4,8 +4,8 @@ ARTIQ on Zynq
|
||||||
How to use
|
How to use
|
||||||
----------
|
----------
|
||||||
|
|
||||||
1. Install the ARTIQ version that corresponds to the artiq-zynq version are targeting.
|
1. Install ARTIQ-7 or newer.
|
||||||
2. Select the latest successful build on [Hydra](https://nixbld.m-labs.hk/) for the targeted artiq-zynq version, or use AFWS to obtain firmware binaries.
|
2. Select the latest successful build on Hydra: https://nixbld.m-labs.hk/jobset/artiq/zynq
|
||||||
3. Search for the job named ``<board>-<variant>-sd`` (for example: ``zc706-nist_clock-sd`` or ``zc706-nist_qc2-sd``).
|
3. Search for the job named ``<board>-<variant>-sd`` (for example: ``zc706-nist_clock-sd`` or ``zc706-nist_qc2-sd``).
|
||||||
4. Download the ``boot.bin`` "binary distribution" and place it at the root of a FAT-formatted SD card.
|
4. Download the ``boot.bin`` "binary distribution" and place it at the root of a FAT-formatted SD card.
|
||||||
5. Optionally, create a ``config.txt`` configuration file at the root of the SD card containing ``key=value`` pairs on each line. Use the ``ip``, ``ip6`` and ``mac`` keys to respectively set the IPv4, IPv6 and MAC address of the board. Configuring an IPv6 address is entirely optional. If these keys are not found, the firmware will use default values that may or may not be compatible with your network.
|
5. Optionally, create a ``config.txt`` configuration file at the root of the SD card containing ``key=value`` pairs on each line. Use the ``ip``, ``ip6`` and ``mac`` keys to respectively set the IPv4, IPv6 and MAC address of the board. Configuring an IPv6 address is entirely optional. If these keys are not found, the firmware will use default values that may or may not be compatible with your network.
|
||||||
|
|
53
flake.lock
53
flake.lock
|
@ -11,15 +11,16 @@
|
||||||
"src-pythonparser": "src-pythonparser"
|
"src-pythonparser": "src-pythonparser"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1680398257,
|
"lastModified": 1676885665,
|
||||||
"narHash": "sha256-ANODm+Xjx/OYHkmQpybDuIPXiu22IkoQ0wdI0ReQsNk=",
|
"narHash": "sha256-DCi2fyz/vOM82YGBTgkmruw2tOm+EepTWeF7+oNs1+s=",
|
||||||
"ref": "refs/heads/master",
|
"ref": "release-7",
|
||||||
"rev": "7ba06bfe61cad4ad41f478188917cac6571a6875",
|
"rev": "8a2ea578b81dd4d8576c8e2b939474f418e03ad7",
|
||||||
"revCount": 8323,
|
"revCount": 8161,
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/m-labs/artiq.git"
|
"url": "https://github.com/m-labs/artiq.git"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
"ref": "release-7",
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/m-labs/artiq.git"
|
"url": "https://github.com/m-labs/artiq.git"
|
||||||
}
|
}
|
||||||
|
@ -68,11 +69,11 @@
|
||||||
"mozilla-overlay": {
|
"mozilla-overlay": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1672878308,
|
"lastModified": 1664789696,
|
||||||
"narHash": "sha256-0+fl6PHokhtSV+w58z2QD2rTf8QhcOGsT9o4LwHHZHE=",
|
"narHash": "sha256-UGWJHQShiwLCr4/DysMVFrYdYYHcOqAOVsWNUu+l6YU=",
|
||||||
"owner": "mozilla",
|
"owner": "mozilla",
|
||||||
"repo": "nixpkgs-mozilla",
|
"repo": "nixpkgs-mozilla",
|
||||||
"rev": "d38863db88e100866b3e494a651ee4962b762fcc",
|
"rev": "80627b282705101e7b38e19ca6e8df105031b072",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -84,11 +85,11 @@
|
||||||
"mozilla-overlay_2": {
|
"mozilla-overlay_2": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1677493379,
|
"lastModified": 1675354105,
|
||||||
"narHash": "sha256-A1gO8zlWLv3+tZ3cGVB1WYvvoN9pbFyv0xIJHcTsckw=",
|
"narHash": "sha256-ZAJGIZ7TjOCU7302lSUabNDz+rxM4If0l8/ZbE/7R5U=",
|
||||||
"owner": "mozilla",
|
"owner": "mozilla",
|
||||||
"repo": "nixpkgs-mozilla",
|
"repo": "nixpkgs-mozilla",
|
||||||
"rev": "78e723925daf5c9e8d0a1837ec27059e61649cb6",
|
"rev": "85eb0ba7d8e5d6d4b79e5b0180aadbdd25d76404",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -115,16 +116,16 @@
|
||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1673345971,
|
"lastModified": 1666056570,
|
||||||
"narHash": "sha256-4DfFcKLRfVUTyuGrGNNmw37IeIZSoku9tgTVmu/iD98=",
|
"narHash": "sha256-e7EkIY68Tp7NKyp9JSHh6CgPPdsKYYWxiL4wZQN8Cwg=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "54644f409ab471e87014bb305eac8c50190bcf48",
|
"rev": "47edaa313fc3767ce3026037a5b62352f22f3602",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"ref": "nixos-22.11",
|
"ref": "nixos-22.05",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
|
@ -144,11 +145,11 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1673433867,
|
"lastModified": 1664319253,
|
||||||
"narHash": "sha256-a7Oq35YoDzPtISbqAsaT+2/v15HZ7G1q0ukXmKWdb7Q=",
|
"narHash": "sha256-hycJAgy+NFF9f5I6++7yo8KdhMSyKCPKJazRPxeedI4=",
|
||||||
"owner": "m-labs",
|
"owner": "m-labs",
|
||||||
"repo": "sipyco",
|
"repo": "sipyco",
|
||||||
"rev": "38f8f4185d7db6b68bd7f71546da9077b1e2561c",
|
"rev": "d58ded7280e0f020be2446d4fee70f4393e6045f",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -160,11 +161,11 @@
|
||||||
"src-migen": {
|
"src-migen": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1673433200,
|
"lastModified": 1662111470,
|
||||||
"narHash": "sha256-ribBG06gsucz5oBS+O6aL8s2oJjx+qfl+vXmspts8gg=",
|
"narHash": "sha256-IPyhoFZLhY8d3jHB8jyvGdbey7V+X5eCzBZYSrJ18ec=",
|
||||||
"owner": "m-labs",
|
"owner": "m-labs",
|
||||||
"repo": "migen",
|
"repo": "migen",
|
||||||
"rev": "f3e9145c9825514a1b4225378936569da4df8e12",
|
"rev": "639e66f4f453438e83d86dc13491b9403bbd8ec6",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -176,11 +177,11 @@
|
||||||
"src-misoc": {
|
"src-misoc": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1671158014,
|
"lastModified": 1665395741,
|
||||||
"narHash": "sha256-50w0K2E2ympYrG1Tte/HVbsp4FS2U+yohqZByXTOo4I=",
|
"narHash": "sha256-7ULMGBPPn5NxZX6rdxU5GheoSNBiJklHQEVf04jU9tI=",
|
||||||
"ref": "refs/heads/master",
|
"ref": "master",
|
||||||
"rev": "26f039f9f6931a20a04ccd0f0a5402f67f553916",
|
"rev": "4fb0730db4c5de7e86f82fa3bd204e6c4608af85",
|
||||||
"revCount": 2436,
|
"revCount": 2427,
|
||||||
"submodules": true,
|
"submodules": true,
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/m-labs/misoc.git"
|
"url": "https://github.com/m-labs/misoc.git"
|
||||||
|
|
73
flake.nix
73
flake.nix
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
description = "ARTIQ port to the Zynq-7000 platform";
|
description = "ARTIQ port to the Zynq-7000 platform";
|
||||||
|
|
||||||
inputs.artiq.url = git+https://github.com/m-labs/artiq.git;
|
inputs.artiq.url = git+https://github.com/m-labs/artiq.git?ref=release-7;
|
||||||
inputs.mozilla-overlay = { url = github:mozilla/nixpkgs-mozilla; flake = false; };
|
inputs.mozilla-overlay = { url = github:mozilla/nixpkgs-mozilla; flake = false; };
|
||||||
inputs.zynq-rs.url = git+https://git.m-labs.hk/m-labs/zynq-rs;
|
inputs.zynq-rs.url = git+https://git.m-labs.hk/m-labs/zynq-rs;
|
||||||
inputs.zynq-rs.inputs.nixpkgs.follows = "artiq/nixpkgs";
|
inputs.zynq-rs.inputs.nixpkgs.follows = "artiq/nixpkgs";
|
||||||
|
@ -37,13 +37,13 @@
|
||||||
|
|
||||||
ramda = pkgs.python3Packages.buildPythonPackage {
|
ramda = pkgs.python3Packages.buildPythonPackage {
|
||||||
pname = "ramda";
|
pname = "ramda";
|
||||||
version = "unstable-2020-04-11";
|
version = "unstable-2019-02-01";
|
||||||
|
|
||||||
src = pkgs.fetchFromGitHub {
|
src = pkgs.fetchFromGitHub {
|
||||||
owner = "peteut";
|
owner = "peteut";
|
||||||
repo = "ramda.py";
|
repo = "ramda.py";
|
||||||
rev = "d315a9717ebd639366bf3fe26bad9e3d08ec3c49";
|
rev = "bd58f8e69d0e9a713d9c1f286a1ac5e5603956b1";
|
||||||
sha256 = "sha256-bmSt/IHDnULsZjsC6edELnNH7LoJSVF4L4XhwBAXRkY=";
|
sha256 = "0qzd5yp9lbaham8p1wiymdjapzbqsli7lvngv24c3z4ybd9jlq9g";
|
||||||
};
|
};
|
||||||
|
|
||||||
nativeBuildInputs = with pkgs.python3Packages; [ pbr ];
|
nativeBuildInputs = with pkgs.python3Packages; [ pbr ];
|
||||||
|
@ -54,34 +54,46 @@
|
||||||
doCheck = false;
|
doCheck = false;
|
||||||
|
|
||||||
preBuild = ''
|
preBuild = ''
|
||||||
export PBR_VERSION=0.5.5
|
export PBR_VERSION=0.0.1
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
migen-axi = pkgs.python3Packages.buildPythonPackage {
|
migen-axi = pkgs.python3Packages.buildPythonPackage {
|
||||||
pname = "migen-axi";
|
pname = "migen-axi";
|
||||||
version = "unstable-2023-01-06";
|
version = "unstable-2021-09-15";
|
||||||
|
|
||||||
src = pkgs.fetchFromGitHub {
|
src = pkgs.fetchFromGitHub {
|
||||||
owner = "peteut";
|
owner = "peteut";
|
||||||
repo = "migen-axi";
|
repo = "migen-axi";
|
||||||
rev = "27eaa84a70a3abfe1930c86c36c4de2cd652da35";
|
rev = "9763505ee96acd7572280a2d1233721342dc7c3f";
|
||||||
sha256 = "sha256-3Y9W5ns+1wbVd14iePzgSBzE+LxnGMUDtUw3BccFt80=";
|
sha256 = "15c7g05n183rka66fl1glzp6h7xjlpy1p6k8biry24dangsmxmvg";
|
||||||
};
|
};
|
||||||
|
|
||||||
format = "pyproject";
|
nativeBuildInputs = with pkgs.python3Packages; [ pbr ];
|
||||||
|
|
||||||
propagatedBuildInputs = with pkgs.python3Packages; [ setuptools click numpy toolz jinja2 ramda artiqpkgs.migen artiqpkgs.misoc ];
|
propagatedBuildInputs = with pkgs.python3Packages; [ setuptools click numpy toolz jinja2 ramda artiqpkgs.migen artiqpkgs.misoc ];
|
||||||
|
|
||||||
|
postPatch = ''
|
||||||
|
substituteInPlace requirements.txt \
|
||||||
|
--replace "jinja2==2.11.3" "jinja2"
|
||||||
|
substituteInPlace requirements.txt \
|
||||||
|
--replace "future==0.18.2" "future"
|
||||||
|
substituteInPlace requirements.txt \
|
||||||
|
--replace "ramda==0.5.5" "ramda"
|
||||||
|
substituteInPlace requirements.txt \
|
||||||
|
--replace "colorama==0.4.3" "colorama"
|
||||||
|
substituteInPlace requirements.txt \
|
||||||
|
--replace "toolz==0.10.0" "toolz"
|
||||||
|
substituteInPlace requirements.txt \
|
||||||
|
--replace "pyserial==3.4" "pyserial"
|
||||||
|
substituteInPlace requirements.txt \
|
||||||
|
--replace "markupsafe==1.1.1" "markupsafe"
|
||||||
|
'';
|
||||||
|
|
||||||
checkInputs = with pkgs.python3Packages; [ pytest pytest-timeout pytest-flake8 ];
|
checkInputs = with pkgs.python3Packages; [ pytest pytest-timeout pytest-flake8 ];
|
||||||
checkPhase = "pytest";
|
checkPhase = "pytest";
|
||||||
|
|
||||||
# migen/misoc version checks are broken with pyproject for some reason
|
preBuild = ''
|
||||||
postPatch = ''
|
export PBR_VERSION=0.0.1
|
||||||
substituteInPlace pyproject.toml \
|
|
||||||
--replace '"migen@git+https://github.com/m-labs/migen",' ""
|
|
||||||
substituteInPlace pyproject.toml \
|
|
||||||
--replace '"misoc@git+https://github.com/m-labs/misoc.git",' ""
|
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
binutils = { platform, target, zlib }: pkgs.stdenv.mkDerivation rec {
|
binutils = { platform, target, zlib }: pkgs.stdenv.mkDerivation rec {
|
||||||
|
@ -122,7 +134,7 @@
|
||||||
cargoLock = {
|
cargoLock = {
|
||||||
lockFile = src/Cargo.lock;
|
lockFile = src/Cargo.lock;
|
||||||
outputHashes = {
|
outputHashes = {
|
||||||
"libasync-0.0.0" = "sha256-WvNMUekL4Elc55RdqX8XP43QPnBrK8Rbd0bsoI61E5U=";
|
"libasync-0.0.0" = "sha256-xuwesRrQiccopPTCkwGqQxld74X74q7EVsKIrE0zirc=";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -253,23 +265,6 @@
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
fmt-check = pkgs.stdenv.mkDerivation {
|
|
||||||
name = "fmt-check";
|
|
||||||
|
|
||||||
nativeBuildInputs = [
|
|
||||||
rustPlatform.rust.cargo
|
|
||||||
];
|
|
||||||
|
|
||||||
phases = [ "buildPhase" ];
|
|
||||||
|
|
||||||
buildPhase =
|
|
||||||
''
|
|
||||||
cd ${self}/src
|
|
||||||
cargo fmt -- --check
|
|
||||||
touch $out
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
# for hitl-tests
|
# for hitl-tests
|
||||||
zc706-nist_qc2 = (build { target = "zc706"; variant = "nist_qc2"; });
|
zc706-nist_qc2 = (build { target = "zc706"; variant = "nist_qc2"; });
|
||||||
zc706-hitl-tests = pkgs.stdenv.mkDerivation {
|
zc706-hitl-tests = pkgs.stdenv.mkDerivation {
|
||||||
|
@ -334,11 +329,7 @@
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
in rec {
|
in rec {
|
||||||
packages.x86_64-linux =
|
packages.x86_64-linux = (build { target = "zc706"; variant = "nist_clock"; }) //
|
||||||
{
|
|
||||||
inherit fastnumbers artiq-netboot ramda migen-axi binutils-arm;
|
|
||||||
} //
|
|
||||||
(build { target = "zc706"; variant = "nist_clock"; }) //
|
|
||||||
(build { target = "zc706"; variant = "nist_clock_master"; }) //
|
(build { target = "zc706"; variant = "nist_clock_master"; }) //
|
||||||
(build { target = "zc706"; variant = "nist_clock_satellite"; }) //
|
(build { target = "zc706"; variant = "nist_clock_satellite"; }) //
|
||||||
(build { target = "zc706"; variant = "nist_clock_satellite_100mhz"; }) //
|
(build { target = "zc706"; variant = "nist_clock_satellite_100mhz"; }) //
|
||||||
|
@ -358,7 +349,7 @@
|
||||||
(build { target = "kasli_soc"; variant = "master"; json = ./kasli-soc-master.json; }) //
|
(build { target = "kasli_soc"; variant = "master"; json = ./kasli-soc-master.json; }) //
|
||||||
(build { target = "kasli_soc"; variant = "satellite"; json = ./kasli-soc-satellite.json; });
|
(build { target = "kasli_soc"; variant = "satellite"; json = ./kasli-soc-satellite.json; });
|
||||||
|
|
||||||
hydraJobs = packages.x86_64-linux // { inherit zc706-hitl-tests; inherit gateware-sim; inherit fmt-check; };
|
hydraJobs = packages.x86_64-linux // { inherit zc706-hitl-tests; inherit gateware-sim; };
|
||||||
|
|
||||||
devShell.x86_64-linux = pkgs.mkShell {
|
devShell.x86_64-linux = pkgs.mkShell {
|
||||||
name = "artiq-zynq-dev-shell";
|
name = "artiq-zynq-dev-shell";
|
||||||
|
@ -387,4 +378,4 @@
|
||||||
makeArtiqZynqPackage = build;
|
makeArtiqZynqPackage = build;
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
|
@ -1,7 +1,5 @@
|
||||||
# This file is automatically @generated by Cargo.
|
# This file is automatically @generated by Cargo.
|
||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 3
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "async-recursion"
|
name = "async-recursion"
|
||||||
version = "0.3.2"
|
version = "0.3.2"
|
||||||
|
@ -49,9 +47,9 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.0.77"
|
version = "1.0.73"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e9f73505338f7d905b19d18738976aae232eb46b8efc15554ffc56deb5d9ebe4"
|
checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cfg-if"
|
name = "cfg-if"
|
||||||
|
@ -138,9 +136,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures"
|
name = "futures"
|
||||||
version = "0.3.25"
|
version = "0.3.21"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "38390104763dc37a5145a53c29c63c1290b5d316d6086ec32c293f6736051bb0"
|
checksum = "f73fe65f54d1e12b726f517d3e2135ca3125a437b6d998caf1962961f7172d9e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures-channel",
|
"futures-channel",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
|
@ -152,9 +150,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-channel"
|
name = "futures-channel"
|
||||||
version = "0.3.25"
|
version = "0.3.21"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "52ba265a92256105f45b719605a571ffe2d1f0fea3807304b522c1d778f79eed"
|
checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"futures-sink",
|
"futures-sink",
|
||||||
|
@ -162,21 +160,21 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-core"
|
name = "futures-core"
|
||||||
version = "0.3.25"
|
version = "0.3.21"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "04909a7a7e4633ae6c4a9ab280aeb86da1236243a77b694a49eacd659a4bd3ac"
|
checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-io"
|
name = "futures-io"
|
||||||
version = "0.3.25"
|
version = "0.3.21"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "00f5fb52a06bdcadeb54e8d3671f8888a39697dcb0b81b23b55174030427f4eb"
|
checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-macro"
|
name = "futures-macro"
|
||||||
version = "0.3.25"
|
version = "0.3.21"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bdfb8ce053d86b91919aad980c220b1fb8401a9394410e1c289ed7e66b61835d"
|
checksum = "33c1e13800337f4d4d7a316bf45a567dbcb6ffe087f16424852d97e97a91f512"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
@ -185,21 +183,21 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-sink"
|
name = "futures-sink"
|
||||||
version = "0.3.25"
|
version = "0.3.21"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "39c15cf1a4aa79df40f1bb462fb39676d0ad9e366c2a33b590d7c66f4f81fcf9"
|
checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-task"
|
name = "futures-task"
|
||||||
version = "0.3.25"
|
version = "0.3.21"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2ffb393ac5d9a6eaa9d3fdf37ae2776656b706e200c8e16b1bdb227f5198e6ea"
|
checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-util"
|
name = "futures-util"
|
||||||
version = "0.3.25"
|
version = "0.3.21"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "197676987abd2f9cadff84926f410af1c183608d36641465df73ae8211dc65d6"
|
checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"futures-macro",
|
"futures-macro",
|
||||||
|
@ -221,7 +219,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libasync"
|
name = "libasync"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
source = "git+https://git.m-labs.hk/M-Labs/zynq-rs.git#67dbb5932fa8ff5f143983476f741f945871d286"
|
source = "git+https://git.m-labs.hk/M-Labs/zynq-rs.git#605c8f73a60cf41a6e2d535c5850933d3154e935"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"embedded-hal",
|
"embedded-hal",
|
||||||
"libcortex_a9",
|
"libcortex_a9",
|
||||||
|
@ -253,7 +251,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libboard_zynq"
|
name = "libboard_zynq"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
source = "git+https://git.m-labs.hk/M-Labs/zynq-rs.git#67dbb5932fa8ff5f143983476f741f945871d286"
|
source = "git+https://git.m-labs.hk/M-Labs/zynq-rs.git#605c8f73a60cf41a6e2d535c5850933d3154e935"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bit_field",
|
"bit_field",
|
||||||
"embedded-hal",
|
"embedded-hal",
|
||||||
|
@ -278,7 +276,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libconfig"
|
name = "libconfig"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://git.m-labs.hk/M-Labs/zynq-rs.git#67dbb5932fa8ff5f143983476f741f945871d286"
|
source = "git+https://git.m-labs.hk/M-Labs/zynq-rs.git#605c8f73a60cf41a6e2d535c5850933d3154e935"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"core_io",
|
"core_io",
|
||||||
"fatfs",
|
"fatfs",
|
||||||
|
@ -289,7 +287,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libcortex_a9"
|
name = "libcortex_a9"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
source = "git+https://git.m-labs.hk/M-Labs/zynq-rs.git#67dbb5932fa8ff5f143983476f741f945871d286"
|
source = "git+https://git.m-labs.hk/M-Labs/zynq-rs.git#605c8f73a60cf41a6e2d535c5850933d3154e935"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bit_field",
|
"bit_field",
|
||||||
"libregister",
|
"libregister",
|
||||||
|
@ -298,14 +296,14 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libm"
|
name = "libm"
|
||||||
version = "0.2.6"
|
version = "0.2.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "348108ab3fba42ec82ff6e9564fc4ca0247bdccdc68dd8af9764bbc79c3c8ffb"
|
checksum = "33a33a362ce288760ec6a508b94caaec573ae7d3bbbd91b87aa0bad4456839db"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libregister"
|
name = "libregister"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
source = "git+https://git.m-labs.hk/M-Labs/zynq-rs.git#67dbb5932fa8ff5f143983476f741f945871d286"
|
source = "git+https://git.m-labs.hk/M-Labs/zynq-rs.git#605c8f73a60cf41a6e2d535c5850933d3154e935"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bit_field",
|
"bit_field",
|
||||||
"vcell",
|
"vcell",
|
||||||
|
@ -315,7 +313,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libsupport_zynq"
|
name = "libsupport_zynq"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
source = "git+https://git.m-labs.hk/M-Labs/zynq-rs.git#67dbb5932fa8ff5f143983476f741f945871d286"
|
source = "git+https://git.m-labs.hk/M-Labs/zynq-rs.git#605c8f73a60cf41a6e2d535c5850933d3154e935"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cc",
|
"cc",
|
||||||
"compiler_builtins",
|
"compiler_builtins",
|
||||||
|
@ -334,9 +332,9 @@ checksum = "822add9edb1860698b79522510da17bef885171f75aa395cff099d770c609c24"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "log"
|
name = "log"
|
||||||
version = "0.4.17"
|
version = "0.4.14"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
|
checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 1.0.0",
|
"cfg-if 1.0.0",
|
||||||
]
|
]
|
||||||
|
@ -381,18 +379,18 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-traits"
|
name = "num-traits"
|
||||||
version = "0.2.15"
|
version = "0.2.14"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
|
checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"autocfg",
|
"autocfg",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pin-project-lite"
|
name = "pin-project-lite"
|
||||||
version = "0.2.9"
|
version = "0.2.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116"
|
checksum = "e280fbe77cc62c91527259e9442153f4688736748d24660126286329742b4c6c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pin-utils"
|
name = "pin-utils"
|
||||||
|
@ -402,18 +400,18 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.43"
|
version = "1.0.36"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab"
|
checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"unicode-ident",
|
"unicode-xid",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quote"
|
name = "quote"
|
||||||
version = "1.0.21"
|
version = "1.0.15"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179"
|
checksum = "864d3e96a899863136fc6e99f3d7cae289dafe43bf2c5ac19b70df7210c0a145"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
|
@ -503,20 +501,20 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "1.0.101"
|
version = "1.0.86"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e90cde112c4b9690b8cbe810cba9ddd8bc1d7472e2cae317b69e9438c1cba7d2"
|
checksum = "8a65b3f4ffa0092e9887669db0eae07941f023991ab58ea44da8fe8e2d511c6b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"unicode-ident",
|
"unicode-xid",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-ident"
|
name = "unicode-xid"
|
||||||
version = "1.0.5"
|
version = "0.2.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3"
|
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unwind"
|
name = "unwind"
|
||||||
|
|
|
@ -14,8 +14,9 @@ from misoc.integration import cpu_interface
|
||||||
|
|
||||||
from artiq.coredevice import jsondesc
|
from artiq.coredevice import jsondesc
|
||||||
from artiq.gateware import rtio, eem_7series
|
from artiq.gateware import rtio, eem_7series
|
||||||
from artiq.gateware.rtio.xilinx_clocking import fix_serdes_timing_path
|
|
||||||
from artiq.gateware.rtio.phy import ttl_simple
|
from artiq.gateware.rtio.phy import ttl_simple
|
||||||
|
from artiq.gateware.rtio.xilinx_clocking import fix_serdes_timing_path
|
||||||
|
from artiq.gateware.rtio.xilinx_clocking import RTIOClockMultiplier
|
||||||
from artiq.gateware.drtio.transceiver import gtx_7series
|
from artiq.gateware.drtio.transceiver import gtx_7series
|
||||||
from artiq.gateware.drtio.siphaser import SiPhaser7Series
|
from artiq.gateware.drtio.siphaser import SiPhaser7Series
|
||||||
from artiq.gateware.drtio.rx_synchronizer import XilinxRXSynchronizer
|
from artiq.gateware.drtio.rx_synchronizer import XilinxRXSynchronizer
|
||||||
|
@ -25,9 +26,57 @@ import dma
|
||||||
import analyzer
|
import analyzer
|
||||||
import acpki
|
import acpki
|
||||||
import drtio_aux_controller
|
import drtio_aux_controller
|
||||||
import zynq_clocking
|
|
||||||
|
|
||||||
|
class RTIOCRG(Module, AutoCSR):
|
||||||
|
def __init__(self, platform):
|
||||||
|
self.pll_reset = CSRStorage(reset=1)
|
||||||
|
self.pll_locked = CSRStatus()
|
||||||
|
self.clock_domains.cd_rtio = ClockDomain()
|
||||||
|
self.clock_domains.cd_rtiox4 = ClockDomain(reset_less=True)
|
||||||
|
|
||||||
|
clk_synth = platform.request("cdr_clk_clean_fabric")
|
||||||
|
clk_synth_se = Signal()
|
||||||
|
platform.add_period_constraint(clk_synth.p, 8.0)
|
||||||
|
self.specials += [
|
||||||
|
Instance("IBUFGDS",
|
||||||
|
p_DIFF_TERM="TRUE", p_IBUF_LOW_PWR="FALSE",
|
||||||
|
i_I=clk_synth.p, i_IB=clk_synth.n, o_O=clk_synth_se),
|
||||||
|
]
|
||||||
|
|
||||||
|
pll_locked = Signal()
|
||||||
|
rtio_clk = Signal()
|
||||||
|
rtiox4_clk = Signal()
|
||||||
|
fb_clk = Signal()
|
||||||
|
self.specials += [
|
||||||
|
Instance("PLLE2_ADV",
|
||||||
|
p_STARTUP_WAIT="FALSE", o_LOCKED=pll_locked,
|
||||||
|
p_BANDWIDTH="HIGH",
|
||||||
|
p_REF_JITTER1=0.001,
|
||||||
|
p_CLKIN1_PERIOD=8.0, p_CLKIN2_PERIOD=8.0,
|
||||||
|
i_CLKIN2=clk_synth_se,
|
||||||
|
# Warning: CLKINSEL=0 means CLKIN2 is selected
|
||||||
|
i_CLKINSEL=0,
|
||||||
|
|
||||||
|
# VCO @ 1.5GHz when using 125MHz input
|
||||||
|
p_CLKFBOUT_MULT=12, p_DIVCLK_DIVIDE=1,
|
||||||
|
i_CLKFBIN=fb_clk,
|
||||||
|
i_RST=self.pll_reset.storage,
|
||||||
|
|
||||||
|
o_CLKFBOUT=fb_clk,
|
||||||
|
|
||||||
|
p_CLKOUT0_DIVIDE=3, p_CLKOUT0_PHASE=0.0,
|
||||||
|
o_CLKOUT0=rtiox4_clk,
|
||||||
|
|
||||||
|
p_CLKOUT1_DIVIDE=12, p_CLKOUT1_PHASE=0.0,
|
||||||
|
o_CLKOUT1=rtio_clk),
|
||||||
|
Instance("BUFG", i_I=rtio_clk, o_O=self.cd_rtio.clk),
|
||||||
|
Instance("BUFG", i_I=rtiox4_clk, o_O=self.cd_rtiox4.clk),
|
||||||
|
|
||||||
|
AsyncResetSynchronizer(self.cd_rtio, ~pll_locked),
|
||||||
|
MultiReg(pll_locked, self.pll_locked.status)
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
eem_iostandard_dict = {
|
eem_iostandard_dict = {
|
||||||
0: "LVDS_25",
|
0: "LVDS_25",
|
||||||
1: "LVDS_25",
|
1: "LVDS_25",
|
||||||
|
@ -61,23 +110,6 @@ class SMAClkinForward(Module):
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class GTP125BootstrapClock(Module):
|
|
||||||
def __init__(self, platform):
|
|
||||||
self.clock_domains.cd_bootstrap = ClockDomain(reset_less=True)
|
|
||||||
self.cd_bootstrap.clk.attr.add("keep")
|
|
||||||
|
|
||||||
bootstrap_125 = platform.request("clk125_gtp")
|
|
||||||
bootstrap_se = Signal()
|
|
||||||
platform.add_period_constraint(bootstrap_125.p, 8.0)
|
|
||||||
self.specials += [
|
|
||||||
Instance("IBUFDS_GTE2",
|
|
||||||
p_CLKSWING_CFG="0b11",
|
|
||||||
i_CEB=0,
|
|
||||||
i_I=bootstrap_125.p, i_IB=bootstrap_125.n, o_O=bootstrap_se),
|
|
||||||
Instance("BUFG", i_I=bootstrap_se, o_O=self.cd_bootstrap.clk)
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
class GenericStandalone(SoCCore):
|
class GenericStandalone(SoCCore):
|
||||||
def __init__(self, description, acpki=False):
|
def __init__(self, description, acpki=False):
|
||||||
self.acpki = acpki
|
self.acpki = acpki
|
||||||
|
@ -90,30 +122,24 @@ class GenericStandalone(SoCCore):
|
||||||
ident = description["variant"]
|
ident = description["variant"]
|
||||||
if self.acpki:
|
if self.acpki:
|
||||||
ident = "acpki_" + ident
|
ident = "acpki_" + ident
|
||||||
SoCCore.__init__(self, platform=platform, csr_data_width=32, ident=ident, ps_cd_sys=False)
|
SoCCore.__init__(self, platform=platform, csr_data_width=32, ident=ident)
|
||||||
|
|
||||||
|
platform.add_platform_command("create_clock -name clk_fpga_0 -period 8 [get_pins \"PS7/FCLKCLK[0]\"]")
|
||||||
|
platform.add_platform_command("set_input_jitter clk_fpga_0 0.24")
|
||||||
|
|
||||||
self.submodules += SMAClkinForward(self.platform)
|
self.submodules += SMAClkinForward(self.platform)
|
||||||
|
|
||||||
self.rustc_cfg["has_si5324"] = None
|
self.rustc_cfg["has_si5324"] = None
|
||||||
self.rustc_cfg["si5324_soft_reset"] = None
|
self.rustc_cfg["si5324_soft_reset"] = None
|
||||||
|
|
||||||
clk_synth = platform.request("cdr_clk_clean_fabric")
|
|
||||||
clk_synth_se = Signal()
|
|
||||||
platform.add_period_constraint(clk_synth.p, 8.0)
|
|
||||||
|
|
||||||
self.specials += Instance("IBUFGDS",
|
|
||||||
p_DIFF_TERM="TRUE", p_IBUF_LOW_PWR="FALSE",
|
|
||||||
i_I=clk_synth.p, i_IB=clk_synth.n, o_O=clk_synth_se)
|
|
||||||
fix_serdes_timing_path(platform)
|
|
||||||
self.submodules.bootstrap = GTP125BootstrapClock(self.platform)
|
|
||||||
|
|
||||||
|
|
||||||
self.submodules.sys_crg = zynq_clocking.SYSCRG(self.platform, self.ps7, clk_synth_se)
|
|
||||||
platform.add_false_path_constraints(
|
|
||||||
self.bootstrap.cd_bootstrap.clk, self.sys_crg.cd_sys.clk)
|
|
||||||
self.csr_devices.append("sys_crg")
|
|
||||||
self.crg = self.ps7 # HACK for eem_7series to find the clock
|
self.crg = self.ps7 # HACK for eem_7series to find the clock
|
||||||
self.crg.cd_sys = self.sys_crg.cd_sys
|
self.submodules.rtio_crg = RTIOCRG(self.platform)
|
||||||
|
self.csr_devices.append("rtio_crg")
|
||||||
|
self.platform.add_period_constraint(self.rtio_crg.cd_rtio.clk, 8.)
|
||||||
|
self.platform.add_false_path_constraints(
|
||||||
|
self.ps7.cd_sys.clk,
|
||||||
|
self.rtio_crg.cd_rtio.clk)
|
||||||
|
fix_serdes_timing_path(platform)
|
||||||
|
|
||||||
self.rtio_channels = []
|
self.rtio_channels = []
|
||||||
has_grabber = any(peripheral["type"] == "grabber" for peripheral in description["peripherals"])
|
has_grabber = any(peripheral["type"] == "grabber" for peripheral in description["peripherals"])
|
||||||
|
@ -129,7 +155,7 @@ class GenericStandalone(SoCCore):
|
||||||
self.config["RTIO_LOG_CHANNEL"] = len(self.rtio_channels)
|
self.config["RTIO_LOG_CHANNEL"] = len(self.rtio_channels)
|
||||||
self.rtio_channels.append(rtio.LogChannel())
|
self.rtio_channels.append(rtio.LogChannel())
|
||||||
|
|
||||||
self.submodules.rtio_tsc = rtio.TSC(glbl_fine_ts_width=3)
|
self.submodules.rtio_tsc = rtio.TSC("async", glbl_fine_ts_width=3)
|
||||||
self.submodules.rtio_core = rtio.Core(self.rtio_tsc, self.rtio_channels)
|
self.submodules.rtio_core = rtio.Core(self.rtio_tsc, self.rtio_channels)
|
||||||
self.csr_devices.append("rtio_core")
|
self.csr_devices.append("rtio_core")
|
||||||
|
|
||||||
|
@ -165,12 +191,13 @@ class GenericStandalone(SoCCore):
|
||||||
self.add_csr_group("grabber", self.grabber_csr_group)
|
self.add_csr_group("grabber", self.grabber_csr_group)
|
||||||
for grabber in self.grabber_csr_group:
|
for grabber in self.grabber_csr_group:
|
||||||
self.platform.add_false_path_constraints(
|
self.platform.add_false_path_constraints(
|
||||||
self.sys_crg.cd_sys.clk, getattr(self, grabber).deserializer.cd_cl.clk)
|
self.rtio_crg.cd_rtio.clk, getattr(self, grabber).deserializer.cd_cl.clk)
|
||||||
|
|
||||||
|
|
||||||
class GenericMaster(SoCCore):
|
class GenericMaster(SoCCore):
|
||||||
def __init__(self, description, acpki=False):
|
def __init__(self, description, acpki=False):
|
||||||
clk_freq = description["rtio_frequency"]
|
sys_clk_freq = 125e6
|
||||||
|
rtio_clk_freq = description["rtio_frequency"]
|
||||||
|
|
||||||
self.acpki = acpki
|
self.acpki = acpki
|
||||||
self.rustc_cfg = dict()
|
self.rustc_cfg = dict()
|
||||||
|
@ -182,7 +209,10 @@ class GenericMaster(SoCCore):
|
||||||
ident = description["variant"]
|
ident = description["variant"]
|
||||||
if self.acpki:
|
if self.acpki:
|
||||||
ident = "acpki_" + ident
|
ident = "acpki_" + ident
|
||||||
SoCCore.__init__(self, platform=platform, csr_data_width=32, ident=ident, ps_cd_sys=False)
|
SoCCore.__init__(self, platform=platform, csr_data_width=32, ident=ident)
|
||||||
|
|
||||||
|
platform.add_platform_command("create_clock -name clk_fpga_0 -period 8 [get_pins \"PS7/FCLKCLK[0]\"]")
|
||||||
|
platform.add_platform_command("set_input_jitter clk_fpga_0 0.24")
|
||||||
|
|
||||||
self.submodules += SMAClkinForward(self.platform)
|
self.submodules += SMAClkinForward(self.platform)
|
||||||
|
|
||||||
|
@ -191,24 +221,12 @@ class GenericMaster(SoCCore):
|
||||||
self.submodules.drtio_transceiver = gtx_7series.GTX(
|
self.submodules.drtio_transceiver = gtx_7series.GTX(
|
||||||
clock_pads=platform.request("clk_gtp"),
|
clock_pads=platform.request("clk_gtp"),
|
||||||
pads=data_pads,
|
pads=data_pads,
|
||||||
clk_freq=clk_freq)
|
sys_clk_freq=sys_clk_freq)
|
||||||
self.csr_devices.append("drtio_transceiver")
|
self.csr_devices.append("drtio_transceiver")
|
||||||
|
|
||||||
txout_buf = Signal()
|
|
||||||
gtx0 = self.drtio_transceiver.gtxs[0]
|
|
||||||
self.specials += Instance("BUFG", i_I=gtx0.txoutclk, o_O=txout_buf)
|
|
||||||
|
|
||||||
self.submodules.bootstrap = GTP125BootstrapClock(self.platform)
|
|
||||||
self.submodules.sys_crg = zynq_clocking.SYSCRG(
|
|
||||||
self.platform,
|
|
||||||
self.ps7,
|
|
||||||
txout_buf,
|
|
||||||
clk_sw=gtx0.tx_init.done)
|
|
||||||
self.csr_devices.append("sys_crg")
|
|
||||||
self.crg = self.ps7 # HACK for eem_7series to find the clock
|
self.crg = self.ps7 # HACK for eem_7series to find the clock
|
||||||
self.crg.cd_sys = self.sys_crg.cd_sys
|
self.submodules.rtio_crg = RTIOClockMultiplier(rtio_clk_freq)
|
||||||
platform.add_false_path_constraints(
|
self.csr_devices.append("rtio_crg")
|
||||||
self.bootstrap.cd_bootstrap.clk, self.sys_crg.cd_sys.clk)
|
|
||||||
fix_serdes_timing_path(platform)
|
fix_serdes_timing_path(platform)
|
||||||
|
|
||||||
self.rustc_cfg["has_si5324"] = None
|
self.rustc_cfg["has_si5324"] = None
|
||||||
|
@ -228,7 +246,7 @@ class GenericMaster(SoCCore):
|
||||||
self.config["RTIO_LOG_CHANNEL"] = len(self.rtio_channels)
|
self.config["RTIO_LOG_CHANNEL"] = len(self.rtio_channels)
|
||||||
self.rtio_channels.append(rtio.LogChannel())
|
self.rtio_channels.append(rtio.LogChannel())
|
||||||
|
|
||||||
self.submodules.rtio_tsc = rtio.TSC(glbl_fine_ts_width=3)
|
self.submodules.rtio_tsc = rtio.TSC("async", glbl_fine_ts_width=3)
|
||||||
|
|
||||||
drtio_csr_group = []
|
drtio_csr_group = []
|
||||||
drtioaux_csr_group = []
|
drtioaux_csr_group = []
|
||||||
|
@ -304,7 +322,8 @@ class GenericMaster(SoCCore):
|
||||||
|
|
||||||
class GenericSatellite(SoCCore):
|
class GenericSatellite(SoCCore):
|
||||||
def __init__(self, description, acpki=False):
|
def __init__(self, description, acpki=False):
|
||||||
clk_freq = description["rtio_frequency"]
|
sys_clk_freq = 125e6
|
||||||
|
rtio_clk_freq = description["rtio_frequency"]
|
||||||
|
|
||||||
self.acpki = acpki
|
self.acpki = acpki
|
||||||
self.rustc_cfg = dict()
|
self.rustc_cfg = dict()
|
||||||
|
@ -316,34 +335,25 @@ class GenericSatellite(SoCCore):
|
||||||
ident = description["variant"]
|
ident = description["variant"]
|
||||||
if self.acpki:
|
if self.acpki:
|
||||||
ident = "acpki_" + ident
|
ident = "acpki_" + ident
|
||||||
SoCCore.__init__(self, platform=platform, csr_data_width=32, ident=ident, ps_cd_sys=False)
|
SoCCore.__init__(self, platform=platform, csr_data_width=32, ident=ident)
|
||||||
|
|
||||||
|
platform.add_platform_command("create_clock -name clk_fpga_0 -period 8 [get_pins \"PS7/FCLKCLK[0]\"]")
|
||||||
|
platform.add_platform_command("set_input_jitter clk_fpga_0 0.24")
|
||||||
|
|
||||||
|
self.crg = self.ps7 # HACK for eem_7series to find the clock
|
||||||
|
self.submodules.rtio_crg = RTIOClockMultiplier(rtio_clk_freq)
|
||||||
|
self.csr_devices.append("rtio_crg")
|
||||||
|
self.rustc_cfg["has_rtio_crg"] = None
|
||||||
|
fix_serdes_timing_path(platform)
|
||||||
|
|
||||||
data_pads = [platform.request("sfp", i) for i in range(4)]
|
data_pads = [platform.request("sfp", i) for i in range(4)]
|
||||||
|
|
||||||
self.submodules.drtio_transceiver = gtx_7series.GTX(
|
self.submodules.drtio_transceiver = gtx_7series.GTX(
|
||||||
clock_pads=platform.request("clk_gtp"),
|
clock_pads=platform.request("clk_gtp"),
|
||||||
pads=data_pads,
|
pads=data_pads,
|
||||||
clk_freq=clk_freq)
|
sys_clk_freq=sys_clk_freq)
|
||||||
self.csr_devices.append("drtio_transceiver")
|
self.csr_devices.append("drtio_transceiver")
|
||||||
|
|
||||||
txout_buf = Signal()
|
|
||||||
gtx0 = self.drtio_transceiver.gtxs[0]
|
|
||||||
self.specials += Instance("BUFG", i_I=gtx0.txoutclk, o_O=txout_buf)
|
|
||||||
|
|
||||||
self.submodules.bootstrap = GTP125BootstrapClock(self.platform)
|
|
||||||
self.submodules.sys_crg = zynq_clocking.SYSCRG(
|
|
||||||
self.platform,
|
|
||||||
self.ps7,
|
|
||||||
txout_buf,
|
|
||||||
clk_sw=gtx0.tx_init.done)
|
|
||||||
platform.add_false_path_constraints(
|
|
||||||
self.bootstrap.cd_bootstrap.clk, self.sys_crg.cd_sys.clk)
|
|
||||||
self.csr_devices.append("sys_crg")
|
|
||||||
self.crg = self.ps7 # HACK for eem_7series to find the clock
|
|
||||||
self.crg.cd_sys = self.sys_crg.cd_sys
|
|
||||||
|
|
||||||
fix_serdes_timing_path(platform)
|
|
||||||
|
|
||||||
self.rtio_channels = []
|
self.rtio_channels = []
|
||||||
has_grabber = any(peripheral["type"] == "grabber" for peripheral in description["peripherals"])
|
has_grabber = any(peripheral["type"] == "grabber" for peripheral in description["peripherals"])
|
||||||
if has_grabber:
|
if has_grabber:
|
||||||
|
@ -358,7 +368,7 @@ class GenericSatellite(SoCCore):
|
||||||
self.config["RTIO_LOG_CHANNEL"] = len(self.rtio_channels)
|
self.config["RTIO_LOG_CHANNEL"] = len(self.rtio_channels)
|
||||||
self.rtio_channels.append(rtio.LogChannel())
|
self.rtio_channels.append(rtio.LogChannel())
|
||||||
|
|
||||||
self.submodules.rtio_tsc = rtio.TSC(glbl_fine_ts_width=3)
|
self.submodules.rtio_tsc = rtio.TSC("sync", glbl_fine_ts_width=3)
|
||||||
|
|
||||||
drtioaux_csr_group = []
|
drtioaux_csr_group = []
|
||||||
drtioaux_memory_group = []
|
drtioaux_memory_group = []
|
||||||
|
@ -427,9 +437,9 @@ class GenericSatellite(SoCCore):
|
||||||
self.comb += self.drtiosat.async_errors.eq(self.local_io.async_errors)
|
self.comb += self.drtiosat.async_errors.eq(self.local_io.async_errors)
|
||||||
|
|
||||||
self.submodules.cri_con = rtio.CRIInterconnectShared(
|
self.submodules.cri_con = rtio.CRIInterconnectShared(
|
||||||
[self.drtiosat.cri, self.rtio_dma.cri],
|
[self.drtiosat.cri],
|
||||||
[self.local_io.cri] + self.drtio_cri,
|
[self.local_io.cri] + self.drtio_cri,
|
||||||
enable_routing=True)
|
mode="sync", enable_routing=True)
|
||||||
self.csr_devices.append("cri_con")
|
self.csr_devices.append("cri_con")
|
||||||
|
|
||||||
self.submodules.routing_table = rtio.RoutingTableAccess(self.cri_con)
|
self.submodules.routing_table = rtio.RoutingTableAccess(self.cri_con)
|
||||||
|
@ -438,22 +448,31 @@ class GenericSatellite(SoCCore):
|
||||||
self.submodules.rtio_moninj = rtio.MonInj(self.rtio_channels)
|
self.submodules.rtio_moninj = rtio.MonInj(self.rtio_channels)
|
||||||
self.csr_devices.append("rtio_moninj")
|
self.csr_devices.append("rtio_moninj")
|
||||||
|
|
||||||
rtio_clk_period = 1e9/clk_freq
|
rtio_clk_period = 1e9/rtio_clk_freq
|
||||||
self.rustc_cfg["rtio_frequency"] = str(clk_freq/1e6)
|
self.rustc_cfg["rtio_frequency"] = str(rtio_clk_freq/1e6)
|
||||||
|
|
||||||
self.submodules.siphaser = SiPhaser7Series(
|
self.submodules.siphaser = SiPhaser7Series(
|
||||||
si5324_clkin=platform.request("cdr_clk"),
|
si5324_clkin=platform.request("cdr_clk"),
|
||||||
rx_synchronizer=self.rx_synchronizer,
|
rx_synchronizer=self.rx_synchronizer,
|
||||||
ultrascale=False,
|
ultrascale=False,
|
||||||
rtio_clk_freq=self.drtio_transceiver.rtio_clk_freq)
|
rtio_clk_freq=self.drtio_transceiver.rtio_clk_freq)
|
||||||
|
platform.add_false_path_constraints(
|
||||||
|
self.crg.cd_sys.clk, self.siphaser.mmcm_freerun_output)
|
||||||
self.csr_devices.append("siphaser")
|
self.csr_devices.append("siphaser")
|
||||||
self.rustc_cfg["has_si5324"] = None
|
self.rustc_cfg["has_si5324"] = None
|
||||||
self.rustc_cfg["has_siphaser"] = None
|
self.rustc_cfg["has_siphaser"] = None
|
||||||
self.rustc_cfg["si5324_soft_reset"] = None
|
self.rustc_cfg["si5324_soft_reset"] = None
|
||||||
|
|
||||||
gtx0 = self.drtio_transceiver.gtxs[0]
|
gtx0 = self.drtio_transceiver.gtxs[0]
|
||||||
|
platform.add_period_constraint(gtx0.txoutclk, rtio_clk_period)
|
||||||
|
platform.add_period_constraint(gtx0.rxoutclk, rtio_clk_period)
|
||||||
platform.add_false_path_constraints(
|
platform.add_false_path_constraints(
|
||||||
|
self.crg.cd_sys.clk,
|
||||||
gtx0.txoutclk, gtx0.rxoutclk)
|
gtx0.txoutclk, gtx0.rxoutclk)
|
||||||
|
for gtx in self.drtio_transceiver.gtxs[1:]:
|
||||||
|
platform.add_period_constraint(gtx.rxoutclk, rtio_clk_period)
|
||||||
|
platform.add_false_path_constraints(
|
||||||
|
self.crg.cd_sys.clk, gtx.rxoutclk)
|
||||||
|
|
||||||
if has_grabber:
|
if has_grabber:
|
||||||
self.rustc_cfg["has_grabber"] = None
|
self.rustc_cfg["has_grabber"] = None
|
||||||
|
|
|
@ -168,7 +168,7 @@ class FullStackTB(Module):
|
||||||
bus = axi.Interface(ws*8)
|
bus = axi.Interface(ws*8)
|
||||||
self.memory = AXIMemorySim(bus, sequence)
|
self.memory = AXIMemorySim(bus, sequence)
|
||||||
self.submodules.dut = dma.DMA(bus)
|
self.submodules.dut = dma.DMA(bus)
|
||||||
self.submodules.tsc = rtio.TSC()
|
self.submodules.tsc = rtio.TSC("async")
|
||||||
self.submodules.rtio = rtio.Core(self.tsc, rtio_channels)
|
self.submodules.rtio = rtio.Core(self.tsc, rtio_channels)
|
||||||
self.comb += self.dut.cri.connect(self.rtio.cri)
|
self.comb += self.dut.cri.connect(self.rtio.cri)
|
||||||
|
|
||||||
|
@ -229,7 +229,7 @@ class TestDMA(unittest.TestCase):
|
||||||
do_dma(tb.dut, 0), monitor(),
|
do_dma(tb.dut, 0), monitor(),
|
||||||
(None for _ in range(70)),
|
(None for _ in range(70)),
|
||||||
tb.memory.ar(), tb.memory.r()
|
tb.memory.ar(), tb.memory.r()
|
||||||
]}, {"sys": 8, "rsys": 8, "rio": 8, "rio_phy": 8})
|
]}, {"sys": 8, "rsys": 8, "rtio": 8, "rio": 8, "rio_phy": 8})
|
||||||
|
|
||||||
correct_changes = [(timestamp + 11, channel)
|
correct_changes = [(timestamp + 11, channel)
|
||||||
for channel, timestamp, _, _ in test_writes_full_stack]
|
for channel, timestamp, _, _ in test_writes_full_stack]
|
||||||
|
|
|
@ -15,7 +15,7 @@ from misoc.cores import gpio
|
||||||
|
|
||||||
from artiq.gateware import rtio, nist_clock, nist_qc2
|
from artiq.gateware import rtio, nist_clock, nist_qc2
|
||||||
from artiq.gateware.rtio.phy import ttl_simple, ttl_serdes_7series, dds, spi2, edge_counter
|
from artiq.gateware.rtio.phy import ttl_simple, ttl_serdes_7series, dds, spi2, edge_counter
|
||||||
from artiq.gateware.rtio.xilinx_clocking import fix_serdes_timing_path
|
from artiq.gateware.rtio.xilinx_clocking import RTIOClockMultiplier, fix_serdes_timing_path
|
||||||
from artiq.gateware.drtio.transceiver import gtx_7series
|
from artiq.gateware.drtio.transceiver import gtx_7series
|
||||||
from artiq.gateware.drtio.siphaser import SiPhaser7Series
|
from artiq.gateware.drtio.siphaser import SiPhaser7Series
|
||||||
from artiq.gateware.drtio.rx_synchronizer import XilinxRXSynchronizer
|
from artiq.gateware.drtio.rx_synchronizer import XilinxRXSynchronizer
|
||||||
|
@ -25,7 +25,50 @@ import dma
|
||||||
import analyzer
|
import analyzer
|
||||||
import acpki
|
import acpki
|
||||||
import drtio_aux_controller
|
import drtio_aux_controller
|
||||||
import zynq_clocking
|
|
||||||
|
|
||||||
|
class RTIOCRG(Module, AutoCSR):
|
||||||
|
def __init__(self, platform, rtio_internal_clk):
|
||||||
|
self.clock_sel = CSRStorage()
|
||||||
|
self.pll_reset = CSRStorage(reset=1)
|
||||||
|
self.pll_locked = CSRStatus()
|
||||||
|
self.clock_domains.cd_rtio = ClockDomain()
|
||||||
|
self.clock_domains.cd_rtiox4 = ClockDomain(reset_less=True)
|
||||||
|
|
||||||
|
rtio_external_clk = Signal()
|
||||||
|
user_sma_clock = platform.request("user_sma_clock")
|
||||||
|
platform.add_period_constraint(user_sma_clock.p, 8.0)
|
||||||
|
self.specials += Instance("IBUFDS",
|
||||||
|
i_I=user_sma_clock.p, i_IB=user_sma_clock.n,
|
||||||
|
o_O=rtio_external_clk)
|
||||||
|
|
||||||
|
pll_locked = Signal()
|
||||||
|
rtio_clk = Signal()
|
||||||
|
rtiox4_clk = Signal()
|
||||||
|
self.specials += [
|
||||||
|
Instance("PLLE2_ADV",
|
||||||
|
p_STARTUP_WAIT="FALSE", o_LOCKED=pll_locked,
|
||||||
|
|
||||||
|
p_REF_JITTER1=0.01,
|
||||||
|
p_CLKIN1_PERIOD=8.0, p_CLKIN2_PERIOD=8.0,
|
||||||
|
i_CLKIN1=rtio_internal_clk, i_CLKIN2=rtio_external_clk,
|
||||||
|
# Warning: CLKINSEL=0 means CLKIN2 is selected
|
||||||
|
i_CLKINSEL=~self.clock_sel.storage,
|
||||||
|
|
||||||
|
# VCO @ 1GHz when using 125MHz input
|
||||||
|
p_CLKFBOUT_MULT=8, p_DIVCLK_DIVIDE=1,
|
||||||
|
i_CLKFBIN=self.cd_rtio.clk,
|
||||||
|
i_RST=self.pll_reset.storage,
|
||||||
|
|
||||||
|
o_CLKFBOUT=rtio_clk,
|
||||||
|
|
||||||
|
p_CLKOUT0_DIVIDE=2, p_CLKOUT0_PHASE=0.0,
|
||||||
|
o_CLKOUT0=rtiox4_clk),
|
||||||
|
Instance("BUFG", i_I=rtio_clk, o_O=self.cd_rtio.clk),
|
||||||
|
Instance("BUFG", i_I=rtiox4_clk, o_O=self.cd_rtiox4.clk),
|
||||||
|
AsyncResetSynchronizer(self.cd_rtio, ~pll_locked),
|
||||||
|
MultiReg(pll_locked, self.pll_locked.status)
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
class SMAClkinForward(Module):
|
class SMAClkinForward(Module):
|
||||||
|
@ -41,37 +84,6 @@ class SMAClkinForward(Module):
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class CLK200BootstrapClock(Module):
|
|
||||||
def __init__(self, platform, freq=125e6):
|
|
||||||
self.clock_domains.cd_bootstrap = ClockDomain(reset_less=True)
|
|
||||||
self.cd_bootstrap.clk.attr.add("keep")
|
|
||||||
|
|
||||||
clk200 = platform.request("clk200")
|
|
||||||
clk200_se = Signal()
|
|
||||||
|
|
||||||
pll_fb = Signal()
|
|
||||||
pll_clkout = Signal()
|
|
||||||
assert freq in [125e6, 100e6]
|
|
||||||
divide = int(1e9/freq)
|
|
||||||
self.specials += [
|
|
||||||
Instance("IBUFDS",
|
|
||||||
i_I=clk200.p, i_IB=clk200.n, o_O=clk200_se),
|
|
||||||
Instance("PLLE2_BASE",
|
|
||||||
p_CLKIN1_PERIOD=5.0,
|
|
||||||
i_CLKIN1=clk200_se,
|
|
||||||
i_CLKFBIN=pll_fb,
|
|
||||||
o_CLKFBOUT=pll_fb,
|
|
||||||
|
|
||||||
# VCO @ 1GHz
|
|
||||||
p_CLKFBOUT_MULT=5, p_DIVCLK_DIVIDE=1,
|
|
||||||
|
|
||||||
# 125MHz/100MHz for bootstrap
|
|
||||||
p_CLKOUT1_DIVIDE=divide, p_CLKOUT1_PHASE=0.0, o_CLKOUT1=pll_clkout,
|
|
||||||
),
|
|
||||||
Instance("BUFG", i_I=pll_clkout, o_O=self.cd_bootstrap.clk)
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
# The NIST backplanes require setting VADJ to 3.3V by reprogramming the power supply.
|
# The NIST backplanes require setting VADJ to 3.3V by reprogramming the power supply.
|
||||||
# This also changes the I/O standard for some on-board LEDs.
|
# This also changes the I/O standard for some on-board LEDs.
|
||||||
leds_fmc33 = [
|
leds_fmc33 = [
|
||||||
|
@ -123,6 +135,9 @@ def prepare_zc706_platform(platform):
|
||||||
platform.toolchain.bitstream_commands.extend([
|
platform.toolchain.bitstream_commands.extend([
|
||||||
"set_property BITSTREAM.GENERAL.COMPRESS True [current_design]",
|
"set_property BITSTREAM.GENERAL.COMPRESS True [current_design]",
|
||||||
])
|
])
|
||||||
|
platform.add_platform_command("create_clock -name clk_fpga_0 -period 8 [get_pins \"PS7/FCLKCLK[0]\"]")
|
||||||
|
platform.add_platform_command("set_input_jitter clk_fpga_0 0.24")
|
||||||
|
|
||||||
|
|
||||||
class ZC706(SoCCore):
|
class ZC706(SoCCore):
|
||||||
def __init__(self, acpki=False):
|
def __init__(self, acpki=False):
|
||||||
|
@ -135,37 +150,18 @@ class ZC706(SoCCore):
|
||||||
ident = self.__class__.__name__
|
ident = self.__class__.__name__
|
||||||
if self.acpki:
|
if self.acpki:
|
||||||
ident = "acpki_" + ident
|
ident = "acpki_" + ident
|
||||||
SoCCore.__init__(self, platform=platform, csr_data_width=32, ident=ident, ps_cd_sys=False)
|
SoCCore.__init__(self, platform=platform, csr_data_width=32, ident=ident)
|
||||||
|
|
||||||
platform.add_extension(si5324_fmc33)
|
self.submodules.rtio_crg = RTIOCRG(self.platform, self.ps7.cd_sys.clk)
|
||||||
self.comb += platform.request("si5324_33").rst_n.eq(1)
|
self.csr_devices.append("rtio_crg")
|
||||||
|
self.rustc_cfg["has_rtio_crg_clock_sel"] = None
|
||||||
cdr_clk = Signal()
|
self.platform.add_period_constraint(self.rtio_crg.cd_rtio.clk, 8.)
|
||||||
cdr_clk_buf = Signal()
|
self.platform.add_false_path_constraints(
|
||||||
si5324_out = platform.request("si5324_clkout")
|
self.ps7.cd_sys.clk,
|
||||||
platform.add_period_constraint(si5324_out.p, 8.0)
|
self.rtio_crg.cd_rtio.clk)
|
||||||
self.specials += [
|
|
||||||
Instance("IBUFDS_GTE2",
|
|
||||||
i_CEB=0,
|
|
||||||
i_I=si5324_out.p, i_IB=si5324_out.n,
|
|
||||||
o_O=cdr_clk,
|
|
||||||
p_CLKCM_CFG="0b1",
|
|
||||||
p_CLKRCV_TRST="0b1",
|
|
||||||
p_CLKSWING_CFG="0b11"),
|
|
||||||
Instance("BUFG", i_I=cdr_clk, o_O=cdr_clk_buf)
|
|
||||||
]
|
|
||||||
self.rustc_cfg["has_si5324"] = None
|
|
||||||
self.rustc_cfg["si5324_as_synthesizer"] = None
|
|
||||||
self.rustc_cfg["si5324_soft_reset"] = None
|
|
||||||
|
|
||||||
self.submodules.bootstrap = CLK200BootstrapClock(platform)
|
|
||||||
self.submodules.sys_crg = zynq_clocking.SYSCRG(self.platform, self.ps7, cdr_clk_buf)
|
|
||||||
platform.add_false_path_constraints(
|
|
||||||
self.bootstrap.cd_bootstrap.clk, self.sys_crg.cd_sys.clk)
|
|
||||||
self.csr_devices.append("sys_crg")
|
|
||||||
|
|
||||||
def add_rtio(self, rtio_channels):
|
def add_rtio(self, rtio_channels):
|
||||||
self.submodules.rtio_tsc = rtio.TSC(glbl_fine_ts_width=3)
|
self.submodules.rtio_tsc = rtio.TSC("async", glbl_fine_ts_width=3)
|
||||||
self.submodules.rtio_core = rtio.Core(self.rtio_tsc, rtio_channels)
|
self.submodules.rtio_core = rtio.Core(self.rtio_tsc, rtio_channels)
|
||||||
self.csr_devices.append("rtio_core")
|
self.csr_devices.append("rtio_core")
|
||||||
|
|
||||||
|
@ -202,17 +198,20 @@ class _MasterBase(SoCCore):
|
||||||
self.acpki = acpki
|
self.acpki = acpki
|
||||||
self.rustc_cfg = dict()
|
self.rustc_cfg = dict()
|
||||||
|
|
||||||
clk_freq = 100e6 if drtio100mhz else 125e6
|
|
||||||
|
|
||||||
platform = zc706.Platform()
|
platform = zc706.Platform()
|
||||||
prepare_zc706_platform(platform)
|
prepare_zc706_platform(platform)
|
||||||
ident = self.__class__.__name__
|
ident = self.__class__.__name__
|
||||||
if self.acpki:
|
if self.acpki:
|
||||||
ident = "acpki_" + ident
|
ident = "acpki_" + ident
|
||||||
SoCCore.__init__(self, platform=platform, csr_data_width=32, ident=ident, ps_cd_sys=False)
|
SoCCore.__init__(self, platform=platform, csr_data_width=32, ident=ident)
|
||||||
|
|
||||||
platform.add_extension(si5324_fmc33)
|
platform.add_extension(si5324_fmc33)
|
||||||
|
|
||||||
|
self.sys_clk_freq = 125e6
|
||||||
|
rtio_clk_freq = 100e6 if drtio100mhz else self.sys_clk_freq
|
||||||
|
|
||||||
|
platform = self.platform
|
||||||
|
|
||||||
self.comb += platform.request("sfp_tx_disable_n").eq(1)
|
self.comb += platform.request("sfp_tx_disable_n").eq(1)
|
||||||
data_pads = [
|
data_pads = [
|
||||||
platform.request("sfp"),
|
platform.request("sfp"),
|
||||||
|
@ -225,23 +224,11 @@ class _MasterBase(SoCCore):
|
||||||
self.submodules.drtio_transceiver = gtx_7series.GTX(
|
self.submodules.drtio_transceiver = gtx_7series.GTX(
|
||||||
clock_pads=platform.request("si5324_clkout"),
|
clock_pads=platform.request("si5324_clkout"),
|
||||||
pads=data_pads,
|
pads=data_pads,
|
||||||
clk_freq=clk_freq)
|
sys_clk_freq=self.sys_clk_freq,
|
||||||
|
rtio_clk_freq=rtio_clk_freq)
|
||||||
self.csr_devices.append("drtio_transceiver")
|
self.csr_devices.append("drtio_transceiver")
|
||||||
|
|
||||||
self.submodules.rtio_tsc = rtio.TSC(glbl_fine_ts_width=3)
|
self.submodules.rtio_tsc = rtio.TSC("async", glbl_fine_ts_width=3)
|
||||||
txout_buf = Signal()
|
|
||||||
gtx0 = self.drtio_transceiver.gtxs[0]
|
|
||||||
self.specials += Instance("BUFG", i_I=gtx0.txoutclk, o_O=txout_buf)
|
|
||||||
self.submodules.bootstrap = CLK200BootstrapClock(platform, clk_freq)
|
|
||||||
self.submodules.sys_crg = zynq_clocking.SYSCRG(
|
|
||||||
self.platform,
|
|
||||||
self.ps7,
|
|
||||||
txout_buf,
|
|
||||||
clk_sw=gtx0.tx_init.done,
|
|
||||||
freq=clk_freq)
|
|
||||||
platform.add_false_path_constraints(
|
|
||||||
self.bootstrap.cd_bootstrap.clk, self.sys_crg.cd_sys.clk)
|
|
||||||
self.csr_devices.append("sys_crg")
|
|
||||||
|
|
||||||
drtio_csr_group = []
|
drtio_csr_group = []
|
||||||
drtioaux_csr_group = []
|
drtioaux_csr_group = []
|
||||||
|
@ -284,20 +271,28 @@ class _MasterBase(SoCCore):
|
||||||
self.rustc_cfg["has_si5324"] = None
|
self.rustc_cfg["has_si5324"] = None
|
||||||
self.rustc_cfg["si5324_as_synthesizer"] = None
|
self.rustc_cfg["si5324_as_synthesizer"] = None
|
||||||
|
|
||||||
|
rtio_clk_period = 1e9/self.drtio_transceiver.rtio_clk_freq
|
||||||
# Constrain TX & RX timing for the first transceiver channel
|
# Constrain TX & RX timing for the first transceiver channel
|
||||||
# (First channel acts as master for phase alignment for all channels' TX)
|
# (First channel acts as master for phase alignment for all channels' TX)
|
||||||
|
gtx0 = self.drtio_transceiver.gtxs[0]
|
||||||
|
platform.add_period_constraint(gtx0.txoutclk, rtio_clk_period)
|
||||||
|
platform.add_period_constraint(gtx0.rxoutclk, rtio_clk_period)
|
||||||
platform.add_false_path_constraints(
|
platform.add_false_path_constraints(
|
||||||
|
self.ps7.cd_sys.clk,
|
||||||
gtx0.txoutclk, gtx0.rxoutclk)
|
gtx0.txoutclk, gtx0.rxoutclk)
|
||||||
# Constrain RX timing for the each transceiver channel
|
# Constrain RX timing for the each transceiver channel
|
||||||
# (Each channel performs single-lane phase alignment for RX)
|
# (Each channel performs single-lane phase alignment for RX)
|
||||||
for gtx in self.drtio_transceiver.gtxs[1:]:
|
for gtx in self.drtio_transceiver.gtxs[1:]:
|
||||||
|
platform.add_period_constraint(gtx.rxoutclk, rtio_clk_period)
|
||||||
platform.add_false_path_constraints(
|
platform.add_false_path_constraints(
|
||||||
gtx0.txoutclk, gtx.rxoutclk)
|
self.ps7.cd_sys.clk, gtx0.txoutclk, gtx.rxoutclk)
|
||||||
|
|
||||||
fix_serdes_timing_path(platform)
|
self.submodules.rtio_crg = RTIOClockMultiplier(self.sys_clk_freq)
|
||||||
|
self.csr_devices.append("rtio_crg")
|
||||||
|
fix_serdes_timing_path(self.platform)
|
||||||
|
|
||||||
def add_rtio(self, rtio_channels):
|
def add_rtio(self, rtio_channels):
|
||||||
self.submodules.rtio_tsc = rtio.TSC(glbl_fine_ts_width=3)
|
self.submodules.rtio_tsc = rtio.TSC("async", glbl_fine_ts_width=3)
|
||||||
self.submodules.rtio_core = rtio.Core(self.rtio_tsc, rtio_channels)
|
self.submodules.rtio_core = rtio.Core(self.rtio_tsc, rtio_channels)
|
||||||
self.csr_devices.append("rtio_core")
|
self.csr_devices.append("rtio_core")
|
||||||
|
|
||||||
|
@ -319,7 +314,7 @@ class _MasterBase(SoCCore):
|
||||||
self.submodules.cri_con = rtio.CRIInterconnectShared(
|
self.submodules.cri_con = rtio.CRIInterconnectShared(
|
||||||
[self.rtio.cri, self.rtio_dma.cri],
|
[self.rtio.cri, self.rtio_dma.cri],
|
||||||
[self.rtio_core.cri] + self.drtio_cri,
|
[self.rtio_core.cri] + self.drtio_cri,
|
||||||
enable_routing=True)
|
mode="sync", enable_routing=True)
|
||||||
self.csr_devices.append("cri_con")
|
self.csr_devices.append("cri_con")
|
||||||
|
|
||||||
self.submodules.rtio_moninj = rtio.MonInj(rtio_channels)
|
self.submodules.rtio_moninj = rtio.MonInj(rtio_channels)
|
||||||
|
@ -338,17 +333,19 @@ class _SatelliteBase(SoCCore):
|
||||||
self.acpki = acpki
|
self.acpki = acpki
|
||||||
self.rustc_cfg = dict()
|
self.rustc_cfg = dict()
|
||||||
|
|
||||||
clk_freq = 100e6 if drtio100mhz else 125e6
|
|
||||||
|
|
||||||
platform = zc706.Platform()
|
platform = zc706.Platform()
|
||||||
prepare_zc706_platform(platform)
|
prepare_zc706_platform(platform)
|
||||||
ident = self.__class__.__name__
|
ident = self.__class__.__name__
|
||||||
if self.acpki:
|
if self.acpki:
|
||||||
ident = "acpki_" + ident
|
ident = "acpki_" + ident
|
||||||
SoCCore.__init__(self, platform=platform, csr_data_width=32, ident=ident, ps_cd_sys=False)
|
SoCCore.__init__(self, platform=platform, csr_data_width=32, ident=ident)
|
||||||
|
|
||||||
platform.add_extension(si5324_fmc33)
|
platform.add_extension(si5324_fmc33)
|
||||||
|
|
||||||
|
self.sys_clk_freq = 125e6
|
||||||
|
rtio_clk_freq = 100e6 if drtio100mhz else self.sys_clk_freq
|
||||||
|
platform = self.platform
|
||||||
|
|
||||||
# SFP
|
# SFP
|
||||||
self.comb += platform.request("sfp_tx_disable_n").eq(0)
|
self.comb += platform.request("sfp_tx_disable_n").eq(0)
|
||||||
data_pads = [
|
data_pads = [
|
||||||
|
@ -356,33 +353,16 @@ class _SatelliteBase(SoCCore):
|
||||||
platform.request("user_sma_mgt")
|
platform.request("user_sma_mgt")
|
||||||
]
|
]
|
||||||
|
|
||||||
self.submodules.rtio_tsc = rtio.TSC(glbl_fine_ts_width=3)
|
self.submodules.rtio_tsc = rtio.TSC("sync", glbl_fine_ts_width=3)
|
||||||
|
|
||||||
# 1000BASE_BX10 Ethernet compatible, 125MHz RTIO clock
|
# 1000BASE_BX10 Ethernet compatible, 125MHz RTIO clock
|
||||||
self.submodules.drtio_transceiver = gtx_7series.GTX(
|
self.submodules.drtio_transceiver = gtx_7series.GTX(
|
||||||
clock_pads=platform.request("si5324_clkout"),
|
clock_pads=platform.request("si5324_clkout"),
|
||||||
pads=data_pads,
|
pads=data_pads,
|
||||||
clk_freq=clk_freq)
|
sys_clk_freq=self.sys_clk_freq,
|
||||||
|
rtio_clk_freq=rtio_clk_freq)
|
||||||
self.csr_devices.append("drtio_transceiver")
|
self.csr_devices.append("drtio_transceiver")
|
||||||
|
|
||||||
txout_buf = Signal()
|
|
||||||
txout_buf.attr.add("keep")
|
|
||||||
gtx0 = self.drtio_transceiver.gtxs[0]
|
|
||||||
self.specials += Instance(
|
|
||||||
"BUFG",
|
|
||||||
i_I=gtx0.txoutclk,
|
|
||||||
o_O=txout_buf)
|
|
||||||
self.submodules.bootstrap = CLK200BootstrapClock(platform, clk_freq)
|
|
||||||
self.submodules.sys_crg = zynq_clocking.SYSCRG(
|
|
||||||
self.platform,
|
|
||||||
self.ps7,
|
|
||||||
txout_buf,
|
|
||||||
clk_sw=gtx0.tx_init.done,
|
|
||||||
freq=clk_freq)
|
|
||||||
platform.add_false_path_constraints(
|
|
||||||
self.bootstrap.cd_bootstrap.clk, self.sys_crg.cd_sys.clk)
|
|
||||||
self.csr_devices.append("sys_crg")
|
|
||||||
|
|
||||||
drtioaux_csr_group = []
|
drtioaux_csr_group = []
|
||||||
drtioaux_memory_group = []
|
drtioaux_memory_group = []
|
||||||
drtiorep_csr_group = []
|
drtiorep_csr_group = []
|
||||||
|
@ -440,7 +420,7 @@ class _SatelliteBase(SoCCore):
|
||||||
ultrascale=False,
|
ultrascale=False,
|
||||||
rtio_clk_freq=self.drtio_transceiver.rtio_clk_freq)
|
rtio_clk_freq=self.drtio_transceiver.rtio_clk_freq)
|
||||||
platform.add_false_path_constraints(
|
platform.add_false_path_constraints(
|
||||||
self.sys_crg.cd_sys.clk, self.siphaser.mmcm_freerun_output)
|
self.ps7.cd_sys.clk, self.siphaser.mmcm_freerun_output)
|
||||||
self.csr_devices.append("siphaser")
|
self.csr_devices.append("siphaser")
|
||||||
self.submodules.si5324_rst_n = gpio.GPIOOut(platform.request("si5324_33").rst_n)
|
self.submodules.si5324_rst_n = gpio.GPIOOut(platform.request("si5324_33").rst_n)
|
||||||
self.csr_devices.append("si5324_rst_n")
|
self.csr_devices.append("si5324_rst_n")
|
||||||
|
@ -450,15 +430,23 @@ class _SatelliteBase(SoCCore):
|
||||||
rtio_clk_period = 1e9/self.drtio_transceiver.rtio_clk_freq
|
rtio_clk_period = 1e9/self.drtio_transceiver.rtio_clk_freq
|
||||||
# Constrain TX & RX timing for the first transceiver channel
|
# Constrain TX & RX timing for the first transceiver channel
|
||||||
# (First channel acts as master for phase alignment for all channels' TX)
|
# (First channel acts as master for phase alignment for all channels' TX)
|
||||||
|
gtx0 = self.drtio_transceiver.gtxs[0]
|
||||||
|
platform.add_period_constraint(gtx0.txoutclk, rtio_clk_period)
|
||||||
|
platform.add_period_constraint(gtx0.rxoutclk, rtio_clk_period)
|
||||||
platform.add_false_path_constraints(
|
platform.add_false_path_constraints(
|
||||||
|
self.ps7.cd_sys.clk,
|
||||||
gtx0.txoutclk, gtx0.rxoutclk)
|
gtx0.txoutclk, gtx0.rxoutclk)
|
||||||
# Constrain RX timing for the each transceiver channel
|
# Constrain RX timing for the each transceiver channel
|
||||||
# (Each channel performs single-lane phase alignment for RX)
|
# (Each channel performs single-lane phase alignment for RX)
|
||||||
for gtx in self.drtio_transceiver.gtxs[1:]:
|
for gtx in self.drtio_transceiver.gtxs[1:]:
|
||||||
|
platform.add_period_constraint(gtx.rxoutclk, rtio_clk_period)
|
||||||
platform.add_false_path_constraints(
|
platform.add_false_path_constraints(
|
||||||
self.sys_crg.cd_sys.clk, gtx.rxoutclk)
|
self.ps7.cd_sys.clk, gtx.rxoutclk)
|
||||||
|
|
||||||
fix_serdes_timing_path(platform)
|
self.submodules.rtio_crg = RTIOClockMultiplier(self.sys_clk_freq)
|
||||||
|
self.csr_devices.append("rtio_crg")
|
||||||
|
self.rustc_cfg["has_rtio_crg"] = None
|
||||||
|
fix_serdes_timing_path(self.platform)
|
||||||
|
|
||||||
def add_rtio(self, rtio_channels):
|
def add_rtio(self, rtio_channels):
|
||||||
self.submodules.rtio_moninj = rtio.MonInj(rtio_channels)
|
self.submodules.rtio_moninj = rtio.MonInj(rtio_channels)
|
||||||
|
@ -476,14 +464,11 @@ class _SatelliteBase(SoCCore):
|
||||||
self.submodules.rtio = rtio.KernelInitiator(self.rtio_tsc, now64=True)
|
self.submodules.rtio = rtio.KernelInitiator(self.rtio_tsc, now64=True)
|
||||||
self.csr_devices.append("rtio")
|
self.csr_devices.append("rtio")
|
||||||
|
|
||||||
self.submodules.rtio_dma = dma.DMA(self.ps7.s_axi_hp0)
|
|
||||||
self.csr_devices.append("rtio_dma")
|
|
||||||
|
|
||||||
self.submodules.local_io = SyncRTIO(self.rtio_tsc, rtio_channels)
|
self.submodules.local_io = SyncRTIO(self.rtio_tsc, rtio_channels)
|
||||||
self.submodules.cri_con = rtio.CRIInterconnectShared(
|
self.submodules.cri_con = rtio.CRIInterconnectShared(
|
||||||
[self.drtiosat.cri, self.rtio_dma.cri],
|
[self.drtiosat.cri],
|
||||||
[self.local_io.cri] + self.drtio_cri,
|
[self.local_io.cri] + self.drtio_cri,
|
||||||
enable_routing=True)
|
mode="sync", enable_routing=True)
|
||||||
self.csr_devices.append("cri_con")
|
self.csr_devices.append("cri_con")
|
||||||
|
|
||||||
self.submodules.routing_table = rtio.RoutingTableAccess(self.cri_con)
|
self.submodules.routing_table = rtio.RoutingTableAccess(self.cri_con)
|
||||||
|
@ -640,7 +625,6 @@ class _NIST_QC2_RTIO:
|
||||||
class NIST_CLOCK(ZC706, _NIST_CLOCK_RTIO):
|
class NIST_CLOCK(ZC706, _NIST_CLOCK_RTIO):
|
||||||
def __init__(self, acpki, drtio100mhz):
|
def __init__(self, acpki, drtio100mhz):
|
||||||
ZC706.__init__(self, acpki)
|
ZC706.__init__(self, acpki)
|
||||||
self.submodules += SMAClkinForward(self.platform)
|
|
||||||
_NIST_CLOCK_RTIO.__init__(self)
|
_NIST_CLOCK_RTIO.__init__(self)
|
||||||
|
|
||||||
class NIST_CLOCK_Master(_MasterBase, _NIST_CLOCK_RTIO):
|
class NIST_CLOCK_Master(_MasterBase, _NIST_CLOCK_RTIO):
|
||||||
|
@ -656,7 +640,6 @@ class NIST_CLOCK_Satellite(_SatelliteBase, _NIST_CLOCK_RTIO):
|
||||||
class NIST_QC2(ZC706, _NIST_QC2_RTIO):
|
class NIST_QC2(ZC706, _NIST_QC2_RTIO):
|
||||||
def __init__(self, acpki, drtio100mhz):
|
def __init__(self, acpki, drtio100mhz):
|
||||||
ZC706.__init__(self, acpki)
|
ZC706.__init__(self, acpki)
|
||||||
self.submodules += SMAClkinForward(self.platform)
|
|
||||||
_NIST_QC2_RTIO.__init__(self)
|
_NIST_QC2_RTIO.__init__(self)
|
||||||
|
|
||||||
class NIST_QC2_Master(_MasterBase, _NIST_QC2_RTIO):
|
class NIST_QC2_Master(_MasterBase, _NIST_QC2_RTIO):
|
||||||
|
|
|
@ -1,122 +0,0 @@
|
||||||
from migen import *
|
|
||||||
from migen.genlib.cdc import MultiReg
|
|
||||||
from migen.genlib.resetsync import AsyncResetSynchronizer
|
|
||||||
from misoc.interconnect.csr import *
|
|
||||||
|
|
||||||
|
|
||||||
class ClockSwitchFSM(Module):
|
|
||||||
def __init__(self):
|
|
||||||
self.i_clk_sw = Signal()
|
|
||||||
|
|
||||||
self.o_clk_sw = Signal()
|
|
||||||
self.o_reset = Signal()
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
i_switch = Signal()
|
|
||||||
o_switch = Signal()
|
|
||||||
reset = Signal()
|
|
||||||
|
|
||||||
# at 125MHz bootstrap cd, will get around 0.5ms
|
|
||||||
delay_counter = Signal(16, reset=0xFFFF)
|
|
||||||
|
|
||||||
# register to prevent glitches
|
|
||||||
self.sync.bootstrap += [
|
|
||||||
self.o_clk_sw.eq(o_switch),
|
|
||||||
self.o_reset.eq(reset),
|
|
||||||
]
|
|
||||||
|
|
||||||
self.o_clk_sw.attr.add("no_retiming")
|
|
||||||
self.o_reset.attr.add("no_retiming")
|
|
||||||
self.i_clk_sw.attr.add("no_retiming")
|
|
||||||
i_switch.attr.add("no_retiming")
|
|
||||||
|
|
||||||
self.specials += MultiReg(self.i_clk_sw, i_switch, "bootstrap")
|
|
||||||
|
|
||||||
fsm = ClockDomainsRenamer("bootstrap")(FSM(reset_state="START"))
|
|
||||||
|
|
||||||
self.submodules += fsm
|
|
||||||
|
|
||||||
fsm.act("START",
|
|
||||||
If(i_switch & ~o_switch,
|
|
||||||
NextState("RESET_START"))
|
|
||||||
)
|
|
||||||
|
|
||||||
fsm.act("RESET_START",
|
|
||||||
reset.eq(1),
|
|
||||||
If(delay_counter == 0,
|
|
||||||
NextValue(delay_counter, 0xFFFF),
|
|
||||||
NextState("CLOCK_SWITCH")
|
|
||||||
).Else(
|
|
||||||
NextValue(delay_counter, delay_counter-1),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
fsm.act("CLOCK_SWITCH",
|
|
||||||
reset.eq(1),
|
|
||||||
NextValue(o_switch, 1),
|
|
||||||
NextValue(delay_counter, delay_counter-1),
|
|
||||||
If(delay_counter == 0,
|
|
||||||
NextState("END"))
|
|
||||||
)
|
|
||||||
fsm.act("END",
|
|
||||||
NextValue(o_switch, 1),
|
|
||||||
reset.eq(0))
|
|
||||||
|
|
||||||
|
|
||||||
class SYSCRG(Module, AutoCSR):
|
|
||||||
def __init__(self, platform, ps7, main_clk, clk_sw=None, freq=125e6):
|
|
||||||
# assumes bootstrap clock is same freq as main and sys output
|
|
||||||
self.clock_domains.cd_sys = ClockDomain()
|
|
||||||
self.clock_domains.cd_sys4x = ClockDomain(reset_less=True)
|
|
||||||
|
|
||||||
self.current_clock = CSRStatus()
|
|
||||||
|
|
||||||
self.cd_sys.clk.attr.add("keep")
|
|
||||||
|
|
||||||
bootstrap_clk = ClockSignal("bootstrap")
|
|
||||||
|
|
||||||
period = 1e9/freq
|
|
||||||
|
|
||||||
pll_locked = Signal()
|
|
||||||
pll_sys = Signal()
|
|
||||||
pll_sys4x = Signal()
|
|
||||||
fb_clk = Signal()
|
|
||||||
|
|
||||||
self.submodules.clk_sw_fsm = ClockSwitchFSM()
|
|
||||||
|
|
||||||
if clk_sw is None:
|
|
||||||
self.clock_switch = CSRStorage()
|
|
||||||
self.comb += self.clk_sw_fsm.i_clk_sw.eq(self.clock_switch.storage)
|
|
||||||
else:
|
|
||||||
self.comb += self.clk_sw_fsm.i_clk_sw.eq(clk_sw)
|
|
||||||
|
|
||||||
self.specials += [
|
|
||||||
Instance("PLLE2_ADV",
|
|
||||||
p_STARTUP_WAIT="FALSE", o_LOCKED=pll_locked,
|
|
||||||
p_BANDWIDTH="HIGH",
|
|
||||||
p_REF_JITTER1=0.001,
|
|
||||||
p_CLKIN1_PERIOD=period, i_CLKIN1=main_clk,
|
|
||||||
p_CLKIN2_PERIOD=period, i_CLKIN2=bootstrap_clk,
|
|
||||||
i_CLKINSEL=self.clk_sw_fsm.o_clk_sw,
|
|
||||||
|
|
||||||
# VCO @ 1.5GHz when using 125MHz input
|
|
||||||
# 1.2GHz for 100MHz (zc706)
|
|
||||||
p_CLKFBOUT_MULT=12, p_DIVCLK_DIVIDE=1,
|
|
||||||
i_CLKFBIN=fb_clk,
|
|
||||||
i_RST=self.clk_sw_fsm.o_reset,
|
|
||||||
|
|
||||||
o_CLKFBOUT=fb_clk,
|
|
||||||
|
|
||||||
p_CLKOUT0_DIVIDE=3, p_CLKOUT0_PHASE=0.0,
|
|
||||||
o_CLKOUT0=pll_sys4x,
|
|
||||||
|
|
||||||
p_CLKOUT1_DIVIDE=12, p_CLKOUT1_PHASE=0.0,
|
|
||||||
o_CLKOUT1=pll_sys),
|
|
||||||
Instance("BUFG", i_I=pll_sys, o_O=self.cd_sys.clk),
|
|
||||||
Instance("BUFG", i_I=pll_sys4x, o_O=self.cd_sys4x.clk),
|
|
||||||
|
|
||||||
AsyncResetSynchronizer(self.cd_sys, ~pll_locked),
|
|
||||||
]
|
|
||||||
|
|
||||||
self.comb += self.current_clock.status.eq(self.clk_sw_fsm.o_clk_sw)
|
|
|
@ -1,10 +1,9 @@
|
||||||
use core::fmt;
|
|
||||||
|
|
||||||
use libconfig::Config;
|
use libconfig::Config;
|
||||||
use log::{info, warn};
|
|
||||||
|
|
||||||
#[cfg(has_drtio_routing)]
|
#[cfg(has_drtio_routing)]
|
||||||
use crate::pl::csr;
|
use crate::pl::csr;
|
||||||
|
use core::fmt;
|
||||||
|
|
||||||
|
use log::{warn, info};
|
||||||
|
|
||||||
#[cfg(has_drtio_routing)]
|
#[cfg(has_drtio_routing)]
|
||||||
pub const DEST_COUNT: usize = 256;
|
pub const DEST_COUNT: usize = 256;
|
||||||
|
@ -19,7 +18,7 @@ impl RoutingTable {
|
||||||
// default routing table is for star topology with no repeaters
|
// default routing table is for star topology with no repeaters
|
||||||
pub fn default_master(default_n_links: usize) -> RoutingTable {
|
pub fn default_master(default_n_links: usize) -> RoutingTable {
|
||||||
let mut ret = RoutingTable([[INVALID_HOP; MAX_HOPS]; DEST_COUNT]);
|
let mut ret = RoutingTable([[INVALID_HOP; MAX_HOPS]; DEST_COUNT]);
|
||||||
let n_entries = default_n_links + 1; // include local RTIO
|
let n_entries = default_n_links + 1; // include local RTIO
|
||||||
for i in 0..n_entries {
|
for i in 0..n_entries {
|
||||||
ret.0[i][0] = i as u8;
|
ret.0[i][0] = i as u8;
|
||||||
}
|
}
|
||||||
|
@ -59,10 +58,10 @@ impl fmt::Display for RoutingTable {
|
||||||
pub fn config_routing_table(default_n_links: usize, cfg: &Config) -> RoutingTable {
|
pub fn config_routing_table(default_n_links: usize, cfg: &Config) -> RoutingTable {
|
||||||
let mut ret = RoutingTable::default_master(default_n_links);
|
let mut ret = RoutingTable::default_master(default_n_links);
|
||||||
if let Ok(data) = cfg.read("routing_table") {
|
if let Ok(data) = cfg.read("routing_table") {
|
||||||
if data.len() == DEST_COUNT * MAX_HOPS {
|
if data.len() == DEST_COUNT*MAX_HOPS {
|
||||||
for i in 0..DEST_COUNT {
|
for i in 0..DEST_COUNT {
|
||||||
for j in 0..MAX_HOPS {
|
for j in 0..MAX_HOPS {
|
||||||
ret.0[i][j] = data[i * MAX_HOPS + j];
|
ret.0[i][j] = data[i*MAX_HOPS+j];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
use core_io::{Error as IoError, ErrorKind as IoErrorKind};
|
|
||||||
use crc;
|
use crc;
|
||||||
use io::{proto::{ProtoRead, ProtoWrite},
|
|
||||||
Cursor};
|
use core_io::{ErrorKind as IoErrorKind, Error as IoError};
|
||||||
use libboard_zynq::{time::Milliseconds, timer::GlobalTimer};
|
use io::{proto::ProtoRead, proto::ProtoWrite, Cursor};
|
||||||
|
use libboard_zynq::{timer::GlobalTimer, time::Milliseconds};
|
||||||
use libcortex_a9::asm::dmb;
|
use libcortex_a9::asm::dmb;
|
||||||
|
use crate::mem::mem::DRTIOAUX_MEM;
|
||||||
|
use crate::pl::csr::DRTIOAUX;
|
||||||
|
use crate::drtioaux_proto::Error as ProtocolError;
|
||||||
|
|
||||||
pub use crate::drtioaux_proto::Packet;
|
pub use crate::drtioaux_proto::Packet;
|
||||||
use crate::{drtioaux_proto::Error as ProtocolError, mem::mem::DRTIOAUX_MEM, pl::csr::DRTIOAUX};
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
|
@ -19,7 +21,7 @@ pub enum Error {
|
||||||
|
|
||||||
RoutingError,
|
RoutingError,
|
||||||
|
|
||||||
Protocol(ProtocolError),
|
Protocol(ProtocolError)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ProtocolError> for Error {
|
impl From<ProtocolError> for Error {
|
||||||
|
@ -61,7 +63,7 @@ pub fn copy_work_buffer(src: *mut u32, dst: *mut u32, len: isize) {
|
||||||
// and AXI burst reads/writes are not implemented yet in gateware
|
// and AXI burst reads/writes are not implemented yet in gateware
|
||||||
// thus the need for a work buffer for transmitting and copying it over
|
// thus the need for a work buffer for transmitting and copying it over
|
||||||
unsafe {
|
unsafe {
|
||||||
for i in 0..(len / 4) {
|
for i in 0..(len/4) {
|
||||||
*dst.offset(i) = *src.offset(i);
|
*dst.offset(i) = *src.offset(i);
|
||||||
//data memory barrier to prevent bursts
|
//data memory barrier to prevent bursts
|
||||||
dmb();
|
dmb();
|
||||||
|
@ -70,7 +72,8 @@ pub fn copy_work_buffer(src: *mut u32, dst: *mut u32, len: isize) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn receive<F, T>(linkno: u8, f: F) -> Result<Option<T>, Error>
|
fn receive<F, T>(linkno: u8, f: F) -> Result<Option<T>, Error>
|
||||||
where F: FnOnce(&[u8]) -> Result<T, Error> {
|
where F: FnOnce(&[u8]) -> Result<T, Error>
|
||||||
|
{
|
||||||
let linkidx = linkno as usize;
|
let linkidx = linkno as usize;
|
||||||
unsafe {
|
unsafe {
|
||||||
if (DRTIOAUX[linkidx].aux_rx_present_read)() == 1 {
|
if (DRTIOAUX[linkidx].aux_rx_present_read)() == 1 {
|
||||||
|
@ -90,12 +93,12 @@ where F: FnOnce(&[u8]) -> Result<T, Error> {
|
||||||
|
|
||||||
pub fn recv(linkno: u8) -> Result<Option<Packet>, Error> {
|
pub fn recv(linkno: u8) -> Result<Option<Packet>, Error> {
|
||||||
if has_rx_error(linkno) {
|
if has_rx_error(linkno) {
|
||||||
return Err(Error::GatewareError);
|
return Err(Error::GatewareError)
|
||||||
}
|
}
|
||||||
|
|
||||||
receive(linkno, |buffer| {
|
receive(linkno, |buffer| {
|
||||||
if buffer.len() < 8 {
|
if buffer.len() < 8 {
|
||||||
return Err(IoError::new(IoErrorKind::UnexpectedEof, "Unexpected end").into());
|
return Err(IoError::new(IoErrorKind::UnexpectedEof, "Unexpected end").into())
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut reader = Cursor::new(buffer);
|
let mut reader = Cursor::new(buffer);
|
||||||
|
@ -104,7 +107,7 @@ pub fn recv(linkno: u8) -> Result<Option<Packet>, Error> {
|
||||||
let checksum = crc::crc32::checksum_ieee(&reader.get_ref()[0..checksum_at]);
|
let checksum = crc::crc32::checksum_ieee(&reader.get_ref()[0..checksum_at]);
|
||||||
reader.set_position(checksum_at);
|
reader.set_position(checksum_at);
|
||||||
if reader.read_u32()? != checksum {
|
if reader.read_u32()? != checksum {
|
||||||
return Err(Error::CorruptedPacket);
|
return Err(Error::CorruptedPacket)
|
||||||
}
|
}
|
||||||
reader.set_position(0);
|
reader.set_position(0);
|
||||||
|
|
||||||
|
@ -112,7 +115,9 @@ pub fn recv(linkno: u8) -> Result<Option<Packet>, Error> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn recv_timeout(linkno: u8, timeout_ms: Option<u64>, timer: GlobalTimer) -> Result<Packet, Error> {
|
pub fn recv_timeout(linkno: u8, timeout_ms: Option<u64>,
|
||||||
|
timer: GlobalTimer) -> Result<Packet, Error>
|
||||||
|
{
|
||||||
let timeout_ms = Milliseconds(timeout_ms.unwrap_or(10));
|
let timeout_ms = Milliseconds(timeout_ms.unwrap_or(10));
|
||||||
let limit = timer.get_time() + timeout_ms;
|
let limit = timer.get_time() + timeout_ms;
|
||||||
while timer.get_time() < limit {
|
while timer.get_time() < limit {
|
||||||
|
@ -125,14 +130,15 @@ pub fn recv_timeout(linkno: u8, timeout_ms: Option<u64>, timer: GlobalTimer) ->
|
||||||
}
|
}
|
||||||
|
|
||||||
fn transmit<F>(linkno: u8, f: F) -> Result<(), Error>
|
fn transmit<F>(linkno: u8, f: F) -> Result<(), Error>
|
||||||
where F: FnOnce(&mut [u8]) -> Result<usize, Error> {
|
where F: FnOnce(&mut [u8]) -> Result<usize, Error>
|
||||||
|
{
|
||||||
let linkno = linkno as usize;
|
let linkno = linkno as usize;
|
||||||
unsafe {
|
unsafe {
|
||||||
while (DRTIOAUX[linkno].aux_tx_read)() != 0 {}
|
while (DRTIOAUX[linkno].aux_tx_read)() != 0 {}
|
||||||
let ptr = DRTIOAUX_MEM[linkno].base as *mut u32;
|
let ptr = DRTIOAUX_MEM[linkno].base as *mut u32;
|
||||||
let len = DRTIOAUX_MEM[linkno].size / 2;
|
let len = DRTIOAUX_MEM[linkno].size / 2;
|
||||||
// work buffer, works with unaligned mem access
|
// work buffer, works with unaligned mem access
|
||||||
let mut buf: [u8; 1024] = [0; 1024];
|
let mut buf: [u8; 1024] = [0; 1024];
|
||||||
let len = f(&mut buf[0..len])?;
|
let len = f(&mut buf[0..len])?;
|
||||||
copy_work_buffer(buf.as_mut_ptr() as *mut u32, ptr, len as isize);
|
copy_work_buffer(buf.as_mut_ptr() as *mut u32, ptr, len as isize);
|
||||||
(DRTIOAUX[linkno].aux_tx_length_write)(len as u16);
|
(DRTIOAUX[linkno].aux_tx_length_write)(len as u16);
|
||||||
|
@ -146,7 +152,7 @@ pub fn send(linkno: u8, packet: &Packet) -> Result<(), Error> {
|
||||||
let mut writer = Cursor::new(buffer);
|
let mut writer = Cursor::new(buffer);
|
||||||
|
|
||||||
packet.write_to(&mut writer)?;
|
packet.write_to(&mut writer)?;
|
||||||
|
|
||||||
// Pad till offset 4, insert checksum there
|
// Pad till offset 4, insert checksum there
|
||||||
let padding = (12 - (writer.position() % 8)) % 8;
|
let padding = (12 - (writer.position() % 8)) % 8;
|
||||||
for _ in 0..padding {
|
for _ in 0..padding {
|
||||||
|
|
|
@ -1,16 +1,18 @@
|
||||||
use core_io::{Error as IoError, ErrorKind as IoErrorKind};
|
|
||||||
use crc;
|
use crc;
|
||||||
use io::{proto::{ProtoRead, ProtoWrite},
|
|
||||||
Cursor};
|
use core_io::{ErrorKind as IoErrorKind, Error as IoError};
|
||||||
use libasync::{block_async, task};
|
|
||||||
use libboard_zynq::{time::Milliseconds, timer::GlobalTimer};
|
|
||||||
use nb;
|
|
||||||
use void::Void;
|
use void::Void;
|
||||||
|
use nb;
|
||||||
|
|
||||||
|
use libboard_zynq::{timer::GlobalTimer, time::Milliseconds};
|
||||||
|
use libasync::{task, block_async};
|
||||||
|
|
||||||
|
use io::{proto::ProtoRead, proto::ProtoWrite, Cursor};
|
||||||
|
use crate::mem::mem::DRTIOAUX_MEM;
|
||||||
|
use crate::pl::csr::DRTIOAUX;
|
||||||
|
use crate::drtioaux::{Error, has_rx_error, copy_work_buffer};
|
||||||
|
|
||||||
pub use crate::drtioaux_proto::Packet;
|
pub use crate::drtioaux_proto::Packet;
|
||||||
use crate::{drtioaux::{copy_work_buffer, has_rx_error, Error},
|
|
||||||
mem::mem::DRTIOAUX_MEM,
|
|
||||||
pl::csr::DRTIOAUX};
|
|
||||||
|
|
||||||
pub async fn reset(linkno: u8) {
|
pub async fn reset(linkno: u8) {
|
||||||
let linkno = linkno as usize;
|
let linkno = linkno as usize;
|
||||||
|
@ -27,14 +29,16 @@ fn tx_ready(linkno: usize) -> nb::Result<(), Void> {
|
||||||
unsafe {
|
unsafe {
|
||||||
if (DRTIOAUX[linkno].aux_tx_read)() != 0 {
|
if (DRTIOAUX[linkno].aux_tx_read)() != 0 {
|
||||||
Err(nb::Error::WouldBlock)
|
Err(nb::Error::WouldBlock)
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn receive<F, T>(linkno: u8, f: F) -> Result<Option<T>, Error>
|
async fn receive<F, T>(linkno: u8, f: F) -> Result<Option<T>, Error>
|
||||||
where F: FnOnce(&[u8]) -> Result<T, Error> {
|
where F: FnOnce(&[u8]) -> Result<T, Error>
|
||||||
|
{
|
||||||
let linkidx = linkno as usize;
|
let linkidx = linkno as usize;
|
||||||
unsafe {
|
unsafe {
|
||||||
if (DRTIOAUX[linkidx].aux_rx_present_read)() == 1 {
|
if (DRTIOAUX[linkidx].aux_rx_present_read)() == 1 {
|
||||||
|
@ -54,12 +58,12 @@ where F: FnOnce(&[u8]) -> Result<T, Error> {
|
||||||
|
|
||||||
pub async fn recv(linkno: u8) -> Result<Option<Packet>, Error> {
|
pub async fn recv(linkno: u8) -> Result<Option<Packet>, Error> {
|
||||||
if has_rx_error(linkno) {
|
if has_rx_error(linkno) {
|
||||||
return Err(Error::GatewareError);
|
return Err(Error::GatewareError)
|
||||||
}
|
}
|
||||||
|
|
||||||
receive(linkno, |buffer| {
|
receive(linkno, |buffer| {
|
||||||
if buffer.len() < 8 {
|
if buffer.len() < 8 {
|
||||||
return Err(IoError::new(IoErrorKind::UnexpectedEof, "Unexpected end").into());
|
return Err(IoError::new(IoErrorKind::UnexpectedEof, "Unexpected end").into())
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut reader = Cursor::new(buffer);
|
let mut reader = Cursor::new(buffer);
|
||||||
|
@ -68,16 +72,17 @@ pub async fn recv(linkno: u8) -> Result<Option<Packet>, Error> {
|
||||||
let checksum = crc::crc32::checksum_ieee(&reader.get_ref()[0..checksum_at]);
|
let checksum = crc::crc32::checksum_ieee(&reader.get_ref()[0..checksum_at]);
|
||||||
reader.set_position(checksum_at);
|
reader.set_position(checksum_at);
|
||||||
if reader.read_u32()? != checksum {
|
if reader.read_u32()? != checksum {
|
||||||
return Err(Error::CorruptedPacket);
|
return Err(Error::CorruptedPacket)
|
||||||
}
|
}
|
||||||
reader.set_position(0);
|
reader.set_position(0);
|
||||||
|
|
||||||
Ok(Packet::read_from(&mut reader)?)
|
Ok(Packet::read_from(&mut reader)?)
|
||||||
})
|
}).await
|
||||||
.await
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn recv_timeout(linkno: u8, timeout_ms: Option<u64>, timer: GlobalTimer) -> Result<Packet, Error> {
|
pub async fn recv_timeout(linkno: u8, timeout_ms: Option<u64>,
|
||||||
|
timer: GlobalTimer) -> Result<Packet, Error>
|
||||||
|
{
|
||||||
let timeout_ms = Milliseconds(timeout_ms.unwrap_or(10));
|
let timeout_ms = Milliseconds(timeout_ms.unwrap_or(10));
|
||||||
let limit = timer.get_time() + timeout_ms;
|
let limit = timer.get_time() + timeout_ms;
|
||||||
let mut would_block = false;
|
let mut would_block = false;
|
||||||
|
@ -88,9 +93,7 @@ pub async fn recv_timeout(linkno: u8, timeout_ms: Option<u64>, timer: GlobalTime
|
||||||
task::r#yield().await;
|
task::r#yield().await;
|
||||||
}
|
}
|
||||||
match recv(linkno).await? {
|
match recv(linkno).await? {
|
||||||
None => {
|
None => { would_block = true; },
|
||||||
would_block = true;
|
|
||||||
}
|
|
||||||
Some(packet) => return Ok(packet),
|
Some(packet) => return Ok(packet),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -98,14 +101,15 @@ pub async fn recv_timeout(linkno: u8, timeout_ms: Option<u64>, timer: GlobalTime
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn transmit<F>(linkno: u8, f: F) -> Result<(), Error>
|
async fn transmit<F>(linkno: u8, f: F) -> Result<(), Error>
|
||||||
where F: FnOnce(&mut [u8]) -> Result<usize, Error> {
|
where F: FnOnce(&mut [u8]) -> Result<usize, Error>
|
||||||
|
{
|
||||||
let linkno = linkno as usize;
|
let linkno = linkno as usize;
|
||||||
unsafe {
|
unsafe {
|
||||||
let _ = block_async!(tx_ready(linkno)).await;
|
let _ = block_async!(tx_ready(linkno)).await;
|
||||||
let ptr = DRTIOAUX_MEM[linkno].base as *mut u32;
|
let ptr = DRTIOAUX_MEM[linkno].base as *mut u32;
|
||||||
let len = DRTIOAUX_MEM[linkno].size / 2;
|
let len = DRTIOAUX_MEM[linkno].size / 2;
|
||||||
// work buffer, works with unaligned mem access
|
// work buffer, works with unaligned mem access
|
||||||
let mut buf: [u8; 1024] = [0; 1024];
|
let mut buf: [u8; 1024] = [0; 1024];
|
||||||
let len = f(&mut buf[0..len])?;
|
let len = f(&mut buf[0..len])?;
|
||||||
copy_work_buffer(buf.as_mut_ptr() as *mut u32, ptr, len as isize);
|
copy_work_buffer(buf.as_mut_ptr() as *mut u32, ptr, len as isize);
|
||||||
(DRTIOAUX[linkno].aux_tx_length_write)(len as u16);
|
(DRTIOAUX[linkno].aux_tx_length_write)(len as u16);
|
||||||
|
@ -119,7 +123,7 @@ pub async fn send(linkno: u8, packet: &Packet) -> Result<(), Error> {
|
||||||
let mut writer = Cursor::new(buffer);
|
let mut writer = Cursor::new(buffer);
|
||||||
|
|
||||||
packet.write_to(&mut writer)?;
|
packet.write_to(&mut writer)?;
|
||||||
|
|
||||||
// Pad till offset 4, insert checksum there
|
// Pad till offset 4, insert checksum there
|
||||||
let padding = (12 - (writer.position() % 8)) % 8;
|
let padding = (12 - (writer.position() % 8)) % 8;
|
||||||
for _ in 0..padding {
|
for _ in 0..padding {
|
||||||
|
@ -130,6 +134,5 @@ pub async fn send(linkno: u8, packet: &Packet) -> Result<(), Error> {
|
||||||
writer.write_u32(checksum)?;
|
writer.write_u32(checksum)?;
|
||||||
|
|
||||||
Ok(writer.position())
|
Ok(writer.position())
|
||||||
})
|
}).await
|
||||||
.await
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,11 @@
|
||||||
use core_io::{Error as IoError, Read, Write};
|
use core_io::{Write, Read, Error as IoError};
|
||||||
use io::proto::{ProtoRead, ProtoWrite};
|
|
||||||
|
|
||||||
/* 512 (max size) - 4 (CRC) - 1 (packet ID) - 1 (destination) - 4 (trace ID) - 1 (last) - 2 (length) */
|
use io::proto::{ProtoWrite, ProtoRead};
|
||||||
pub const DMA_TRACE_MAX_SIZE: usize = 499;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
UnknownPacket(u8),
|
UnknownPacket(u8),
|
||||||
Io(IoError),
|
Io(IoError)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<IoError> for Error {
|
impl From<IoError> for Error {
|
||||||
|
@ -24,155 +22,45 @@ pub enum Packet {
|
||||||
ResetAck,
|
ResetAck,
|
||||||
TSCAck,
|
TSCAck,
|
||||||
|
|
||||||
DestinationStatusRequest {
|
DestinationStatusRequest { destination: u8 },
|
||||||
destination: u8,
|
|
||||||
},
|
|
||||||
DestinationDownReply,
|
DestinationDownReply,
|
||||||
DestinationOkReply,
|
DestinationOkReply,
|
||||||
DestinationSequenceErrorReply {
|
DestinationSequenceErrorReply { channel: u16 },
|
||||||
channel: u16,
|
DestinationCollisionReply { channel: u16 },
|
||||||
},
|
DestinationBusyReply { channel: u16 },
|
||||||
DestinationCollisionReply {
|
|
||||||
channel: u16,
|
|
||||||
},
|
|
||||||
DestinationBusyReply {
|
|
||||||
channel: u16,
|
|
||||||
},
|
|
||||||
|
|
||||||
RoutingSetPath {
|
RoutingSetPath { destination: u8, hops: [u8; 32] },
|
||||||
destination: u8,
|
RoutingSetRank { rank: u8 },
|
||||||
hops: [u8; 32],
|
|
||||||
},
|
|
||||||
RoutingSetRank {
|
|
||||||
rank: u8,
|
|
||||||
},
|
|
||||||
RoutingAck,
|
RoutingAck,
|
||||||
|
|
||||||
MonitorRequest {
|
MonitorRequest { destination: u8, channel: u16, probe: u8 },
|
||||||
destination: u8,
|
MonitorReply { value: u64 },
|
||||||
channel: u16,
|
InjectionRequest { destination: u8, channel: u16, overrd: u8, value: u8 },
|
||||||
probe: u8,
|
InjectionStatusRequest { destination: u8, channel: u16, overrd: u8 },
|
||||||
},
|
InjectionStatusReply { value: u8 },
|
||||||
MonitorReply {
|
|
||||||
value: u64,
|
|
||||||
},
|
|
||||||
InjectionRequest {
|
|
||||||
destination: u8,
|
|
||||||
channel: u16,
|
|
||||||
overrd: u8,
|
|
||||||
value: u8,
|
|
||||||
},
|
|
||||||
InjectionStatusRequest {
|
|
||||||
destination: u8,
|
|
||||||
channel: u16,
|
|
||||||
overrd: u8,
|
|
||||||
},
|
|
||||||
InjectionStatusReply {
|
|
||||||
value: u8,
|
|
||||||
},
|
|
||||||
|
|
||||||
I2cStartRequest {
|
I2cStartRequest { destination: u8, busno: u8 },
|
||||||
destination: u8,
|
I2cRestartRequest { destination: u8, busno: u8 },
|
||||||
busno: u8,
|
I2cStopRequest { destination: u8, busno: u8 },
|
||||||
},
|
I2cWriteRequest { destination: u8, busno: u8, data: u8 },
|
||||||
I2cRestartRequest {
|
I2cWriteReply { succeeded: bool, ack: bool },
|
||||||
destination: u8,
|
I2cReadRequest { destination: u8, busno: u8, ack: bool },
|
||||||
busno: u8,
|
I2cReadReply { succeeded: bool, data: u8 },
|
||||||
},
|
I2cBasicReply { succeeded: bool },
|
||||||
I2cStopRequest {
|
I2cSwitchSelectRequest { destination: u8, busno: u8, address: u8, mask: u8 },
|
||||||
destination: u8,
|
|
||||||
busno: u8,
|
|
||||||
},
|
|
||||||
I2cWriteRequest {
|
|
||||||
destination: u8,
|
|
||||||
busno: u8,
|
|
||||||
data: u8,
|
|
||||||
},
|
|
||||||
I2cWriteReply {
|
|
||||||
succeeded: bool,
|
|
||||||
ack: bool,
|
|
||||||
},
|
|
||||||
I2cReadRequest {
|
|
||||||
destination: u8,
|
|
||||||
busno: u8,
|
|
||||||
ack: bool,
|
|
||||||
},
|
|
||||||
I2cReadReply {
|
|
||||||
succeeded: bool,
|
|
||||||
data: u8,
|
|
||||||
},
|
|
||||||
I2cBasicReply {
|
|
||||||
succeeded: bool,
|
|
||||||
},
|
|
||||||
I2cSwitchSelectRequest {
|
|
||||||
destination: u8,
|
|
||||||
busno: u8,
|
|
||||||
address: u8,
|
|
||||||
mask: u8,
|
|
||||||
},
|
|
||||||
|
|
||||||
SpiSetConfigRequest {
|
SpiSetConfigRequest { destination: u8, busno: u8, flags: u8, length: u8, div: u8, cs: u8 },
|
||||||
destination: u8,
|
SpiWriteRequest { destination: u8, busno: u8, data: u32 },
|
||||||
busno: u8,
|
SpiReadRequest { destination: u8, busno: u8 },
|
||||||
flags: u8,
|
SpiReadReply { succeeded: bool, data: u32 },
|
||||||
length: u8,
|
SpiBasicReply { succeeded: bool },
|
||||||
div: u8,
|
|
||||||
cs: u8,
|
|
||||||
},
|
|
||||||
SpiWriteRequest {
|
|
||||||
destination: u8,
|
|
||||||
busno: u8,
|
|
||||||
data: u32,
|
|
||||||
},
|
|
||||||
SpiReadRequest {
|
|
||||||
destination: u8,
|
|
||||||
busno: u8,
|
|
||||||
},
|
|
||||||
SpiReadReply {
|
|
||||||
succeeded: bool,
|
|
||||||
data: u32,
|
|
||||||
},
|
|
||||||
SpiBasicReply {
|
|
||||||
succeeded: bool,
|
|
||||||
},
|
|
||||||
|
|
||||||
DmaAddTraceRequest {
|
|
||||||
destination: u8,
|
|
||||||
id: u32,
|
|
||||||
last: bool,
|
|
||||||
length: u16,
|
|
||||||
trace: [u8; DMA_TRACE_MAX_SIZE],
|
|
||||||
},
|
|
||||||
DmaAddTraceReply {
|
|
||||||
succeeded: bool,
|
|
||||||
},
|
|
||||||
DmaRemoveTraceRequest {
|
|
||||||
destination: u8,
|
|
||||||
id: u32,
|
|
||||||
},
|
|
||||||
DmaRemoveTraceReply {
|
|
||||||
succeeded: bool,
|
|
||||||
},
|
|
||||||
DmaPlaybackRequest {
|
|
||||||
destination: u8,
|
|
||||||
id: u32,
|
|
||||||
timestamp: u64,
|
|
||||||
},
|
|
||||||
DmaPlaybackReply {
|
|
||||||
succeeded: bool,
|
|
||||||
},
|
|
||||||
DmaPlaybackStatus {
|
|
||||||
destination: u8,
|
|
||||||
id: u32,
|
|
||||||
error: u8,
|
|
||||||
channel: u32,
|
|
||||||
timestamp: u64,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Packet {
|
impl Packet {
|
||||||
pub fn read_from<R>(reader: &mut R) -> Result<Self, Error>
|
pub fn read_from<R>(reader: &mut R) -> Result<Self, Error>
|
||||||
where R: Read + ?Sized {
|
where R: Read + ?Sized
|
||||||
|
{
|
||||||
Ok(match reader.read_u8()? {
|
Ok(match reader.read_u8()? {
|
||||||
0x00 => Packet::EchoRequest,
|
0x00 => Packet::EchoRequest,
|
||||||
0x01 => Packet::EchoReply,
|
0x01 => Packet::EchoReply,
|
||||||
|
@ -181,18 +69,18 @@ impl Packet {
|
||||||
0x04 => Packet::TSCAck,
|
0x04 => Packet::TSCAck,
|
||||||
|
|
||||||
0x20 => Packet::DestinationStatusRequest {
|
0x20 => Packet::DestinationStatusRequest {
|
||||||
destination: reader.read_u8()?,
|
destination: reader.read_u8()?
|
||||||
},
|
},
|
||||||
0x21 => Packet::DestinationDownReply,
|
0x21 => Packet::DestinationDownReply,
|
||||||
0x22 => Packet::DestinationOkReply,
|
0x22 => Packet::DestinationOkReply,
|
||||||
0x23 => Packet::DestinationSequenceErrorReply {
|
0x23 => Packet::DestinationSequenceErrorReply {
|
||||||
channel: reader.read_u16()?,
|
channel: reader.read_u16()?
|
||||||
},
|
},
|
||||||
0x24 => Packet::DestinationCollisionReply {
|
0x24 => Packet::DestinationCollisionReply {
|
||||||
channel: reader.read_u16()?,
|
channel: reader.read_u16()?
|
||||||
},
|
},
|
||||||
0x25 => Packet::DestinationBusyReply {
|
0x25 => Packet::DestinationBusyReply {
|
||||||
channel: reader.read_u16()?,
|
channel: reader.read_u16()?
|
||||||
},
|
},
|
||||||
|
|
||||||
0x30 => {
|
0x30 => {
|
||||||
|
@ -201,75 +89,75 @@ impl Packet {
|
||||||
reader.read_exact(&mut hops)?;
|
reader.read_exact(&mut hops)?;
|
||||||
Packet::RoutingSetPath {
|
Packet::RoutingSetPath {
|
||||||
destination: destination,
|
destination: destination,
|
||||||
hops: hops,
|
hops: hops
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
0x31 => Packet::RoutingSetRank {
|
0x31 => Packet::RoutingSetRank {
|
||||||
rank: reader.read_u8()?,
|
rank: reader.read_u8()?
|
||||||
},
|
},
|
||||||
0x32 => Packet::RoutingAck,
|
0x32 => Packet::RoutingAck,
|
||||||
|
|
||||||
0x40 => Packet::MonitorRequest {
|
0x40 => Packet::MonitorRequest {
|
||||||
destination: reader.read_u8()?,
|
destination: reader.read_u8()?,
|
||||||
channel: reader.read_u16()?,
|
channel: reader.read_u16()?,
|
||||||
probe: reader.read_u8()?,
|
probe: reader.read_u8()?
|
||||||
},
|
},
|
||||||
0x41 => Packet::MonitorReply {
|
0x41 => Packet::MonitorReply {
|
||||||
value: reader.read_u64()?,
|
value: reader.read_u64()?
|
||||||
},
|
},
|
||||||
0x50 => Packet::InjectionRequest {
|
0x50 => Packet::InjectionRequest {
|
||||||
destination: reader.read_u8()?,
|
destination: reader.read_u8()?,
|
||||||
channel: reader.read_u16()?,
|
channel: reader.read_u16()?,
|
||||||
overrd: reader.read_u8()?,
|
overrd: reader.read_u8()?,
|
||||||
value: reader.read_u8()?,
|
value: reader.read_u8()?
|
||||||
},
|
},
|
||||||
0x51 => Packet::InjectionStatusRequest {
|
0x51 => Packet::InjectionStatusRequest {
|
||||||
destination: reader.read_u8()?,
|
destination: reader.read_u8()?,
|
||||||
channel: reader.read_u16()?,
|
channel: reader.read_u16()?,
|
||||||
overrd: reader.read_u8()?,
|
overrd: reader.read_u8()?
|
||||||
},
|
},
|
||||||
0x52 => Packet::InjectionStatusReply {
|
0x52 => Packet::InjectionStatusReply {
|
||||||
value: reader.read_u8()?,
|
value: reader.read_u8()?
|
||||||
},
|
},
|
||||||
|
|
||||||
0x80 => Packet::I2cStartRequest {
|
0x80 => Packet::I2cStartRequest {
|
||||||
destination: reader.read_u8()?,
|
destination: reader.read_u8()?,
|
||||||
busno: reader.read_u8()?,
|
busno: reader.read_u8()?
|
||||||
},
|
},
|
||||||
0x81 => Packet::I2cRestartRequest {
|
0x81 => Packet::I2cRestartRequest {
|
||||||
destination: reader.read_u8()?,
|
destination: reader.read_u8()?,
|
||||||
busno: reader.read_u8()?,
|
busno: reader.read_u8()?
|
||||||
},
|
},
|
||||||
0x82 => Packet::I2cStopRequest {
|
0x82 => Packet::I2cStopRequest {
|
||||||
destination: reader.read_u8()?,
|
destination: reader.read_u8()?,
|
||||||
busno: reader.read_u8()?,
|
busno: reader.read_u8()?
|
||||||
},
|
},
|
||||||
0x83 => Packet::I2cWriteRequest {
|
0x83 => Packet::I2cWriteRequest {
|
||||||
destination: reader.read_u8()?,
|
destination: reader.read_u8()?,
|
||||||
busno: reader.read_u8()?,
|
busno: reader.read_u8()?,
|
||||||
data: reader.read_u8()?,
|
data: reader.read_u8()?
|
||||||
},
|
},
|
||||||
0x84 => Packet::I2cWriteReply {
|
0x84 => Packet::I2cWriteReply {
|
||||||
succeeded: reader.read_bool()?,
|
succeeded: reader.read_bool()?,
|
||||||
ack: reader.read_bool()?,
|
ack: reader.read_bool()?
|
||||||
},
|
},
|
||||||
0x85 => Packet::I2cReadRequest {
|
0x85 => Packet::I2cReadRequest {
|
||||||
destination: reader.read_u8()?,
|
destination: reader.read_u8()?,
|
||||||
busno: reader.read_u8()?,
|
busno: reader.read_u8()?,
|
||||||
ack: reader.read_bool()?,
|
ack: reader.read_bool()?
|
||||||
},
|
},
|
||||||
0x86 => Packet::I2cReadReply {
|
0x86 => Packet::I2cReadReply {
|
||||||
succeeded: reader.read_bool()?,
|
succeeded: reader.read_bool()?,
|
||||||
data: reader.read_u8()?,
|
data: reader.read_u8()?
|
||||||
},
|
},
|
||||||
0x87 => Packet::I2cBasicReply {
|
0x87 => Packet::I2cBasicReply {
|
||||||
succeeded: reader.read_bool()?,
|
succeeded: reader.read_bool()?
|
||||||
},
|
},
|
||||||
0x88 => Packet::I2cSwitchSelectRequest {
|
0x88 => Packet::I2cSwitchSelectRequest {
|
||||||
destination: reader.read_u8()?,
|
destination: reader.read_u8()?,
|
||||||
busno: reader.read_u8()?,
|
busno: reader.read_u8()?,
|
||||||
address: reader.read_u8()?,
|
address: reader.read_u8()?,
|
||||||
mask: reader.read_u8()?,
|
mask: reader.read_u8()?
|
||||||
},
|
},
|
||||||
|
|
||||||
0x90 => Packet::SpiSetConfigRequest {
|
0x90 => Packet::SpiSetConfigRequest {
|
||||||
|
@ -278,221 +166,157 @@ impl Packet {
|
||||||
flags: reader.read_u8()?,
|
flags: reader.read_u8()?,
|
||||||
length: reader.read_u8()?,
|
length: reader.read_u8()?,
|
||||||
div: reader.read_u8()?,
|
div: reader.read_u8()?,
|
||||||
cs: reader.read_u8()?,
|
cs: reader.read_u8()?
|
||||||
},
|
},
|
||||||
/* 0x91: was Packet::SpiSetXferRequest */
|
/* 0x91: was Packet::SpiSetXferRequest */
|
||||||
0x92 => Packet::SpiWriteRequest {
|
0x92 => Packet::SpiWriteRequest {
|
||||||
destination: reader.read_u8()?,
|
destination: reader.read_u8()?,
|
||||||
busno: reader.read_u8()?,
|
busno: reader.read_u8()?,
|
||||||
data: reader.read_u32()?,
|
data: reader.read_u32()?
|
||||||
},
|
},
|
||||||
0x93 => Packet::SpiReadRequest {
|
0x93 => Packet::SpiReadRequest {
|
||||||
destination: reader.read_u8()?,
|
destination: reader.read_u8()?,
|
||||||
busno: reader.read_u8()?,
|
busno: reader.read_u8()?
|
||||||
},
|
},
|
||||||
0x94 => Packet::SpiReadReply {
|
0x94 => Packet::SpiReadReply {
|
||||||
succeeded: reader.read_bool()?,
|
succeeded: reader.read_bool()?,
|
||||||
data: reader.read_u32()?,
|
data: reader.read_u32()?
|
||||||
},
|
},
|
||||||
0x95 => Packet::SpiBasicReply {
|
0x95 => Packet::SpiBasicReply {
|
||||||
succeeded: reader.read_bool()?,
|
succeeded: reader.read_bool()?
|
||||||
},
|
},
|
||||||
|
|
||||||
0xb0 => {
|
ty => return Err(Error::UnknownPacket(ty))
|
||||||
let destination = reader.read_u8()?;
|
|
||||||
let id = reader.read_u32()?;
|
|
||||||
let last = reader.read_bool()?;
|
|
||||||
let length = reader.read_u16()?;
|
|
||||||
let mut trace: [u8; DMA_TRACE_MAX_SIZE] = [0; DMA_TRACE_MAX_SIZE];
|
|
||||||
reader.read_exact(&mut trace[0..length as usize])?;
|
|
||||||
Packet::DmaAddTraceRequest {
|
|
||||||
destination: destination,
|
|
||||||
id: id,
|
|
||||||
last: last,
|
|
||||||
length: length as u16,
|
|
||||||
trace: trace,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
0xb1 => Packet::DmaAddTraceReply {
|
|
||||||
succeeded: reader.read_bool()?,
|
|
||||||
},
|
|
||||||
0xb2 => Packet::DmaRemoveTraceRequest {
|
|
||||||
destination: reader.read_u8()?,
|
|
||||||
id: reader.read_u32()?,
|
|
||||||
},
|
|
||||||
0xb3 => Packet::DmaRemoveTraceReply {
|
|
||||||
succeeded: reader.read_bool()?,
|
|
||||||
},
|
|
||||||
0xb4 => Packet::DmaPlaybackRequest {
|
|
||||||
destination: reader.read_u8()?,
|
|
||||||
id: reader.read_u32()?,
|
|
||||||
timestamp: reader.read_u64()?,
|
|
||||||
},
|
|
||||||
0xb5 => Packet::DmaPlaybackReply {
|
|
||||||
succeeded: reader.read_bool()?,
|
|
||||||
},
|
|
||||||
0xb6 => Packet::DmaPlaybackStatus {
|
|
||||||
destination: reader.read_u8()?,
|
|
||||||
id: reader.read_u32()?,
|
|
||||||
error: reader.read_u8()?,
|
|
||||||
channel: reader.read_u32()?,
|
|
||||||
timestamp: reader.read_u64()?,
|
|
||||||
},
|
|
||||||
|
|
||||||
ty => return Err(Error::UnknownPacket(ty)),
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write_to<W>(&self, writer: &mut W) -> Result<(), IoError>
|
pub fn write_to<W>(&self, writer: &mut W) -> Result<(), IoError>
|
||||||
where W: Write + ?Sized {
|
where W: Write + ?Sized
|
||||||
|
{
|
||||||
|
|
||||||
match *self {
|
match *self {
|
||||||
Packet::EchoRequest => writer.write_u8(0x00)?,
|
Packet::EchoRequest =>
|
||||||
Packet::EchoReply => writer.write_u8(0x01)?,
|
writer.write_u8(0x00)?,
|
||||||
Packet::ResetRequest => writer.write_u8(0x02)?,
|
Packet::EchoReply =>
|
||||||
Packet::ResetAck => writer.write_u8(0x03)?,
|
writer.write_u8(0x01)?,
|
||||||
Packet::TSCAck => writer.write_u8(0x04)?,
|
Packet::ResetRequest =>
|
||||||
|
writer.write_u8(0x02)?,
|
||||||
|
Packet::ResetAck =>
|
||||||
|
writer.write_u8(0x03)?,
|
||||||
|
Packet::TSCAck =>
|
||||||
|
writer.write_u8(0x04)?,
|
||||||
|
|
||||||
Packet::DestinationStatusRequest { destination } => {
|
Packet::DestinationStatusRequest { destination } => {
|
||||||
writer.write_u8(0x20)?;
|
writer.write_u8(0x20)?;
|
||||||
writer.write_u8(destination)?;
|
writer.write_u8(destination)?;
|
||||||
}
|
},
|
||||||
Packet::DestinationDownReply => writer.write_u8(0x21)?,
|
Packet::DestinationDownReply =>
|
||||||
Packet::DestinationOkReply => writer.write_u8(0x22)?,
|
writer.write_u8(0x21)?,
|
||||||
|
Packet::DestinationOkReply =>
|
||||||
|
writer.write_u8(0x22)?,
|
||||||
Packet::DestinationSequenceErrorReply { channel } => {
|
Packet::DestinationSequenceErrorReply { channel } => {
|
||||||
writer.write_u8(0x23)?;
|
writer.write_u8(0x23)?;
|
||||||
writer.write_u16(channel)?;
|
writer.write_u16(channel)?;
|
||||||
}
|
},
|
||||||
Packet::DestinationCollisionReply { channel } => {
|
Packet::DestinationCollisionReply { channel } => {
|
||||||
writer.write_u8(0x24)?;
|
writer.write_u8(0x24)?;
|
||||||
writer.write_u16(channel)?;
|
writer.write_u16(channel)?;
|
||||||
}
|
},
|
||||||
Packet::DestinationBusyReply { channel } => {
|
Packet::DestinationBusyReply { channel } => {
|
||||||
writer.write_u8(0x25)?;
|
writer.write_u8(0x25)?;
|
||||||
writer.write_u16(channel)?;
|
writer.write_u16(channel)?;
|
||||||
}
|
},
|
||||||
|
|
||||||
Packet::RoutingSetPath { destination, hops } => {
|
Packet::RoutingSetPath { destination, hops } => {
|
||||||
writer.write_u8(0x30)?;
|
writer.write_u8(0x30)?;
|
||||||
writer.write_u8(destination)?;
|
writer.write_u8(destination)?;
|
||||||
writer.write_all(&hops)?;
|
writer.write_all(&hops)?;
|
||||||
}
|
},
|
||||||
Packet::RoutingSetRank { rank } => {
|
Packet::RoutingSetRank { rank } => {
|
||||||
writer.write_u8(0x31)?;
|
writer.write_u8(0x31)?;
|
||||||
writer.write_u8(rank)?;
|
writer.write_u8(rank)?;
|
||||||
}
|
},
|
||||||
Packet::RoutingAck => writer.write_u8(0x32)?,
|
Packet::RoutingAck =>
|
||||||
|
writer.write_u8(0x32)?,
|
||||||
|
|
||||||
Packet::MonitorRequest {
|
Packet::MonitorRequest { destination, channel, probe } => {
|
||||||
destination,
|
|
||||||
channel,
|
|
||||||
probe,
|
|
||||||
} => {
|
|
||||||
writer.write_u8(0x40)?;
|
writer.write_u8(0x40)?;
|
||||||
writer.write_u8(destination)?;
|
writer.write_u8(destination)?;
|
||||||
writer.write_u16(channel)?;
|
writer.write_u16(channel)?;
|
||||||
writer.write_u8(probe)?;
|
writer.write_u8(probe)?;
|
||||||
}
|
},
|
||||||
Packet::MonitorReply { value } => {
|
Packet::MonitorReply { value } => {
|
||||||
writer.write_u8(0x41)?;
|
writer.write_u8(0x41)?;
|
||||||
writer.write_u64(value)?;
|
writer.write_u64(value)?;
|
||||||
}
|
},
|
||||||
Packet::InjectionRequest {
|
Packet::InjectionRequest { destination, channel, overrd, value } => {
|
||||||
destination,
|
|
||||||
channel,
|
|
||||||
overrd,
|
|
||||||
value,
|
|
||||||
} => {
|
|
||||||
writer.write_u8(0x50)?;
|
writer.write_u8(0x50)?;
|
||||||
writer.write_u8(destination)?;
|
writer.write_u8(destination)?;
|
||||||
writer.write_u16(channel)?;
|
writer.write_u16(channel)?;
|
||||||
writer.write_u8(overrd)?;
|
writer.write_u8(overrd)?;
|
||||||
writer.write_u8(value)?;
|
writer.write_u8(value)?;
|
||||||
}
|
},
|
||||||
Packet::InjectionStatusRequest {
|
Packet::InjectionStatusRequest { destination, channel, overrd } => {
|
||||||
destination,
|
|
||||||
channel,
|
|
||||||
overrd,
|
|
||||||
} => {
|
|
||||||
writer.write_u8(0x51)?;
|
writer.write_u8(0x51)?;
|
||||||
writer.write_u8(destination)?;
|
writer.write_u8(destination)?;
|
||||||
writer.write_u16(channel)?;
|
writer.write_u16(channel)?;
|
||||||
writer.write_u8(overrd)?;
|
writer.write_u8(overrd)?;
|
||||||
}
|
},
|
||||||
Packet::InjectionStatusReply { value } => {
|
Packet::InjectionStatusReply { value } => {
|
||||||
writer.write_u8(0x52)?;
|
writer.write_u8(0x52)?;
|
||||||
writer.write_u8(value)?;
|
writer.write_u8(value)?;
|
||||||
}
|
},
|
||||||
|
|
||||||
Packet::I2cStartRequest { destination, busno } => {
|
Packet::I2cStartRequest { destination, busno } => {
|
||||||
writer.write_u8(0x80)?;
|
writer.write_u8(0x80)?;
|
||||||
writer.write_u8(destination)?;
|
writer.write_u8(destination)?;
|
||||||
writer.write_u8(busno)?;
|
writer.write_u8(busno)?;
|
||||||
}
|
},
|
||||||
Packet::I2cRestartRequest { destination, busno } => {
|
Packet::I2cRestartRequest { destination, busno } => {
|
||||||
writer.write_u8(0x81)?;
|
writer.write_u8(0x81)?;
|
||||||
writer.write_u8(destination)?;
|
writer.write_u8(destination)?;
|
||||||
writer.write_u8(busno)?;
|
writer.write_u8(busno)?;
|
||||||
}
|
},
|
||||||
Packet::I2cStopRequest { destination, busno } => {
|
Packet::I2cStopRequest { destination, busno } => {
|
||||||
writer.write_u8(0x82)?;
|
writer.write_u8(0x82)?;
|
||||||
writer.write_u8(destination)?;
|
writer.write_u8(destination)?;
|
||||||
writer.write_u8(busno)?;
|
writer.write_u8(busno)?;
|
||||||
}
|
},
|
||||||
Packet::I2cWriteRequest {
|
Packet::I2cWriteRequest { destination, busno, data } => {
|
||||||
destination,
|
|
||||||
busno,
|
|
||||||
data,
|
|
||||||
} => {
|
|
||||||
writer.write_u8(0x83)?;
|
writer.write_u8(0x83)?;
|
||||||
writer.write_u8(destination)?;
|
writer.write_u8(destination)?;
|
||||||
writer.write_u8(busno)?;
|
writer.write_u8(busno)?;
|
||||||
writer.write_u8(data)?;
|
writer.write_u8(data)?;
|
||||||
}
|
},
|
||||||
Packet::I2cWriteReply { succeeded, ack } => {
|
Packet::I2cWriteReply { succeeded, ack } => {
|
||||||
writer.write_u8(0x84)?;
|
writer.write_u8(0x84)?;
|
||||||
writer.write_bool(succeeded)?;
|
writer.write_bool(succeeded)?;
|
||||||
writer.write_bool(ack)?;
|
writer.write_bool(ack)?;
|
||||||
}
|
},
|
||||||
Packet::I2cReadRequest {
|
Packet::I2cReadRequest { destination, busno, ack } => {
|
||||||
destination,
|
|
||||||
busno,
|
|
||||||
ack,
|
|
||||||
} => {
|
|
||||||
writer.write_u8(0x85)?;
|
writer.write_u8(0x85)?;
|
||||||
writer.write_u8(destination)?;
|
writer.write_u8(destination)?;
|
||||||
writer.write_u8(busno)?;
|
writer.write_u8(busno)?;
|
||||||
writer.write_bool(ack)?;
|
writer.write_bool(ack)?;
|
||||||
}
|
},
|
||||||
Packet::I2cReadReply { succeeded, data } => {
|
Packet::I2cReadReply { succeeded, data } => {
|
||||||
writer.write_u8(0x86)?;
|
writer.write_u8(0x86)?;
|
||||||
writer.write_bool(succeeded)?;
|
writer.write_bool(succeeded)?;
|
||||||
writer.write_u8(data)?;
|
writer.write_u8(data)?;
|
||||||
}
|
},
|
||||||
Packet::I2cBasicReply { succeeded } => {
|
Packet::I2cBasicReply { succeeded } => {
|
||||||
writer.write_u8(0x87)?;
|
writer.write_u8(0x87)?;
|
||||||
writer.write_bool(succeeded)?;
|
writer.write_bool(succeeded)?;
|
||||||
}
|
},
|
||||||
Packet::I2cSwitchSelectRequest {
|
Packet::I2cSwitchSelectRequest { destination, busno, address, mask } => {
|
||||||
destination,
|
|
||||||
busno,
|
|
||||||
address,
|
|
||||||
mask,
|
|
||||||
} => {
|
|
||||||
writer.write_u8(0x88)?;
|
writer.write_u8(0x88)?;
|
||||||
writer.write_u8(destination)?;
|
writer.write_u8(destination)?;
|
||||||
writer.write_u8(busno)?;
|
writer.write_u8(busno)?;
|
||||||
writer.write_u8(address)?;
|
writer.write_u8(address)?;
|
||||||
writer.write_u8(mask)?;
|
writer.write_u8(mask)?;
|
||||||
}
|
},
|
||||||
|
|
||||||
Packet::SpiSetConfigRequest {
|
Packet::SpiSetConfigRequest { destination, busno, flags, length, div, cs } => {
|
||||||
destination,
|
|
||||||
busno,
|
|
||||||
flags,
|
|
||||||
length,
|
|
||||||
div,
|
|
||||||
cs,
|
|
||||||
} => {
|
|
||||||
writer.write_u8(0x90)?;
|
writer.write_u8(0x90)?;
|
||||||
writer.write_u8(destination)?;
|
writer.write_u8(destination)?;
|
||||||
writer.write_u8(busno)?;
|
writer.write_u8(busno)?;
|
||||||
|
@ -500,90 +324,30 @@ impl Packet {
|
||||||
writer.write_u8(length)?;
|
writer.write_u8(length)?;
|
||||||
writer.write_u8(div)?;
|
writer.write_u8(div)?;
|
||||||
writer.write_u8(cs)?;
|
writer.write_u8(cs)?;
|
||||||
}
|
},
|
||||||
Packet::SpiWriteRequest {
|
Packet::SpiWriteRequest { destination, busno, data } => {
|
||||||
destination,
|
|
||||||
busno,
|
|
||||||
data,
|
|
||||||
} => {
|
|
||||||
writer.write_u8(0x92)?;
|
writer.write_u8(0x92)?;
|
||||||
writer.write_u8(destination)?;
|
writer.write_u8(destination)?;
|
||||||
writer.write_u8(busno)?;
|
writer.write_u8(busno)?;
|
||||||
writer.write_u32(data)?;
|
writer.write_u32(data)?;
|
||||||
}
|
},
|
||||||
Packet::SpiReadRequest { destination, busno } => {
|
Packet::SpiReadRequest { destination, busno } => {
|
||||||
writer.write_u8(0x93)?;
|
writer.write_u8(0x93)?;
|
||||||
writer.write_u8(destination)?;
|
writer.write_u8(destination)?;
|
||||||
writer.write_u8(busno)?;
|
writer.write_u8(busno)?;
|
||||||
}
|
},
|
||||||
Packet::SpiReadReply { succeeded, data } => {
|
Packet::SpiReadReply { succeeded, data } => {
|
||||||
writer.write_u8(0x94)?;
|
writer.write_u8(0x94)?;
|
||||||
writer.write_bool(succeeded)?;
|
writer.write_bool(succeeded)?;
|
||||||
writer.write_u32(data)?;
|
writer.write_u32(data)?;
|
||||||
}
|
},
|
||||||
Packet::SpiBasicReply { succeeded } => {
|
Packet::SpiBasicReply { succeeded } => {
|
||||||
writer.write_u8(0x95)?;
|
writer.write_u8(0x95)?;
|
||||||
writer.write_bool(succeeded)?;
|
writer.write_bool(succeeded)?;
|
||||||
}
|
},
|
||||||
|
|
||||||
Packet::DmaAddTraceRequest {
|
|
||||||
destination,
|
|
||||||
id,
|
|
||||||
last,
|
|
||||||
trace,
|
|
||||||
length,
|
|
||||||
} => {
|
|
||||||
writer.write_u8(0xb0)?;
|
|
||||||
writer.write_u8(destination)?;
|
|
||||||
writer.write_u32(id)?;
|
|
||||||
writer.write_bool(last)?;
|
|
||||||
// trace may be broken down to fit within drtio aux memory limit
|
|
||||||
// will be reconstructed by satellite
|
|
||||||
writer.write_u16(length)?;
|
|
||||||
writer.write_all(&trace[0..length as usize])?;
|
|
||||||
}
|
|
||||||
Packet::DmaAddTraceReply { succeeded } => {
|
|
||||||
writer.write_u8(0xb1)?;
|
|
||||||
writer.write_bool(succeeded)?;
|
|
||||||
}
|
|
||||||
Packet::DmaRemoveTraceRequest { destination, id } => {
|
|
||||||
writer.write_u8(0xb2)?;
|
|
||||||
writer.write_u8(destination)?;
|
|
||||||
writer.write_u32(id)?;
|
|
||||||
}
|
|
||||||
Packet::DmaRemoveTraceReply { succeeded } => {
|
|
||||||
writer.write_u8(0xb3)?;
|
|
||||||
writer.write_bool(succeeded)?;
|
|
||||||
}
|
|
||||||
Packet::DmaPlaybackRequest {
|
|
||||||
destination,
|
|
||||||
id,
|
|
||||||
timestamp,
|
|
||||||
} => {
|
|
||||||
writer.write_u8(0xb4)?;
|
|
||||||
writer.write_u8(destination)?;
|
|
||||||
writer.write_u32(id)?;
|
|
||||||
writer.write_u64(timestamp)?;
|
|
||||||
}
|
|
||||||
Packet::DmaPlaybackReply { succeeded } => {
|
|
||||||
writer.write_u8(0xb5)?;
|
|
||||||
writer.write_bool(succeeded)?;
|
|
||||||
}
|
|
||||||
Packet::DmaPlaybackStatus {
|
|
||||||
destination,
|
|
||||||
id,
|
|
||||||
error,
|
|
||||||
channel,
|
|
||||||
timestamp,
|
|
||||||
} => {
|
|
||||||
writer.write_u8(0xb6)?;
|
|
||||||
writer.write_u8(destination)?;
|
|
||||||
writer.write_u32(id)?;
|
|
||||||
writer.write_u8(error)?;
|
|
||||||
writer.write_u32(channel)?;
|
|
||||||
writer.write_u64(timestamp)?;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,8 +19,10 @@ pub struct IoExpander<'a> {
|
||||||
registers: Registers,
|
registers: Registers,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl<'a> IoExpander<'a> {
|
impl<'a> IoExpander<'a> {
|
||||||
pub fn new(i2c: &'a mut i2c::I2c, index: u8) -> Result<Self, &'static str> {
|
pub fn new(i2c: &'a mut i2c::I2c, index: u8) -> Result<Self, &'static str> {
|
||||||
|
|
||||||
// Both expanders on SHARED I2C bus
|
// Both expanders on SHARED I2C bus
|
||||||
let mut io_expander = match index {
|
let mut io_expander = match index {
|
||||||
0 => IoExpander {
|
0 => IoExpander {
|
||||||
|
@ -52,7 +54,10 @@ impl<'a> IoExpander<'a> {
|
||||||
_ => return Err("incorrect I/O expander index"),
|
_ => return Err("incorrect I/O expander index"),
|
||||||
};
|
};
|
||||||
if !io_expander.check_ack()? {
|
if !io_expander.check_ack()? {
|
||||||
info!("MCP23017 io expander {} not found. Checking for PCA9539.", index);
|
info!(
|
||||||
|
"MCP23017 io expander {} not found. Checking for PCA9539.",
|
||||||
|
index
|
||||||
|
);
|
||||||
io_expander.address += 0xa8; // translate to PCA9539 addresses (see schematic)
|
io_expander.address += 0xa8; // translate to PCA9539 addresses (see schematic)
|
||||||
io_expander.registers = Registers {
|
io_expander.registers = Registers {
|
||||||
iodira: 0x06,
|
iodira: 0x06,
|
||||||
|
|
|
@ -1,38 +1,38 @@
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![feature(never_type)]
|
#![feature(never_type)]
|
||||||
|
|
||||||
extern crate core_io;
|
extern crate log;
|
||||||
extern crate crc;
|
extern crate crc;
|
||||||
extern crate embedded_hal;
|
extern crate embedded_hal;
|
||||||
|
extern crate core_io;
|
||||||
extern crate io;
|
extern crate io;
|
||||||
extern crate libasync;
|
|
||||||
extern crate libboard_zynq;
|
extern crate libboard_zynq;
|
||||||
|
extern crate libregister;
|
||||||
extern crate libconfig;
|
extern crate libconfig;
|
||||||
extern crate libcortex_a9;
|
extern crate libcortex_a9;
|
||||||
extern crate libregister;
|
extern crate libasync;
|
||||||
extern crate log;
|
|
||||||
extern crate log_buffer;
|
extern crate log_buffer;
|
||||||
|
|
||||||
|
#[path = "../../../build/pl.rs"]
|
||||||
|
pub mod pl;
|
||||||
|
pub mod drtioaux_proto;
|
||||||
pub mod drtio_routing;
|
pub mod drtio_routing;
|
||||||
|
pub mod logger;
|
||||||
|
#[cfg(has_si5324)]
|
||||||
|
pub mod si5324;
|
||||||
#[cfg(has_drtio)]
|
#[cfg(has_drtio)]
|
||||||
pub mod drtioaux;
|
pub mod drtioaux;
|
||||||
#[cfg(has_drtio)]
|
#[cfg(has_drtio)]
|
||||||
pub mod drtioaux_async;
|
pub mod drtioaux_async;
|
||||||
pub mod drtioaux_proto;
|
|
||||||
#[cfg(feature = "target_kasli_soc")]
|
|
||||||
pub mod io_expander;
|
|
||||||
pub mod logger;
|
|
||||||
#[cfg(has_drtio)]
|
#[cfg(has_drtio)]
|
||||||
#[rustfmt::skip]
|
|
||||||
#[path = "../../../build/mem.rs"]
|
#[path = "../../../build/mem.rs"]
|
||||||
pub mod mem;
|
pub mod mem;
|
||||||
#[rustfmt::skip]
|
#[cfg(feature = "target_kasli_soc")]
|
||||||
#[path = "../../../build/pl.rs"]
|
pub mod io_expander;
|
||||||
pub mod pl;
|
|
||||||
#[cfg(has_si5324)]
|
|
||||||
pub mod si5324;
|
|
||||||
|
|
||||||
use core::{cmp, str};
|
use core::{cmp, str};
|
||||||
|
use libboard_zynq::slcr;
|
||||||
|
use libregister::RegisterW;
|
||||||
|
|
||||||
pub fn identifier_read(buf: &mut [u8]) -> &str {
|
pub fn identifier_read(buf: &mut [u8]) -> &str {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -46,3 +46,26 @@ pub fn identifier_read(buf: &mut [u8]) -> &str {
|
||||||
str::from_utf8_unchecked(&buf[..len as usize])
|
str::from_utf8_unchecked(&buf[..len as usize])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn init_gateware() {
|
||||||
|
// Set up PS->PL clocks
|
||||||
|
slcr::RegisterBlock::unlocked(|slcr| {
|
||||||
|
// As we are touching the mux, the clock may glitch, so reset the PL.
|
||||||
|
slcr.fpga_rst_ctrl.write(
|
||||||
|
slcr::FpgaRstCtrl::zeroed()
|
||||||
|
.fpga0_out_rst(true)
|
||||||
|
.fpga1_out_rst(true)
|
||||||
|
.fpga2_out_rst(true)
|
||||||
|
.fpga3_out_rst(true)
|
||||||
|
);
|
||||||
|
slcr.fpga0_clk_ctrl.write(
|
||||||
|
slcr::Fpga0ClkCtrl::zeroed()
|
||||||
|
.src_sel(slcr::PllSource::IoPll)
|
||||||
|
.divisor0(8)
|
||||||
|
.divisor1(1)
|
||||||
|
);
|
||||||
|
slcr.fpga_rst_ctrl.write(
|
||||||
|
slcr::FpgaRstCtrl::zeroed()
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
|
@ -1,13 +1,13 @@
|
||||||
use core::{cell::Cell, fmt::Write};
|
use core::cell::Cell;
|
||||||
|
use core::fmt::Write;
|
||||||
use libboard_zynq::{println, timer::GlobalTimer};
|
use log::{Log, LevelFilter};
|
||||||
use libcortex_a9::mutex::{Mutex, MutexGuard};
|
|
||||||
use log::{LevelFilter, Log};
|
|
||||||
use log_buffer::LogBuffer;
|
use log_buffer::LogBuffer;
|
||||||
|
use libcortex_a9::mutex::{Mutex, MutexGuard};
|
||||||
|
use libboard_zynq::{println, timer::GlobalTimer};
|
||||||
|
|
||||||
pub struct LogBufferRef<'a> {
|
pub struct LogBufferRef<'a> {
|
||||||
buffer: MutexGuard<'a, LogBuffer<&'static mut [u8]>>,
|
buffer: MutexGuard<'a, LogBuffer<&'static mut [u8]>>,
|
||||||
old_log_level: LevelFilter,
|
old_log_level: LevelFilter
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> LogBufferRef<'a> {
|
impl<'a> LogBufferRef<'a> {
|
||||||
|
@ -37,7 +37,7 @@ impl<'a> Drop for LogBufferRef<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct BufferLogger {
|
pub struct BufferLogger {
|
||||||
buffer: Mutex<LogBuffer<&'static mut [u8]>>,
|
buffer: Mutex<LogBuffer<&'static mut [u8]>>,
|
||||||
uart_filter: Cell<LevelFilter>,
|
uart_filter: Cell<LevelFilter>,
|
||||||
buffer_filter: Cell<LevelFilter>,
|
buffer_filter: Cell<LevelFilter>,
|
||||||
}
|
}
|
||||||
|
@ -56,7 +56,8 @@ impl BufferLogger {
|
||||||
pub fn register(self) {
|
pub fn register(self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
LOGGER = Some(self);
|
LOGGER = Some(self);
|
||||||
log::set_logger(LOGGER.as_ref().unwrap()).expect("global logger can only be initialized once");
|
log::set_logger(LOGGER.as_ref().unwrap())
|
||||||
|
.expect("global logger can only be initialized once");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,7 +66,9 @@ impl BufferLogger {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn buffer<'a>(&'a self) -> Option<LogBufferRef<'a>> {
|
pub fn buffer<'a>(&'a self) -> Option<LogBufferRef<'a>> {
|
||||||
self.buffer.try_lock().map(LogBufferRef::new)
|
self.buffer
|
||||||
|
.try_lock()
|
||||||
|
.map(LogBufferRef::new)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn uart_log_level(&self) -> LevelFilter {
|
pub fn uart_log_level(&self) -> LevelFilter {
|
||||||
|
@ -96,36 +99,25 @@ impl Log for BufferLogger {
|
||||||
|
|
||||||
fn log(&self, record: &log::Record) {
|
fn log(&self, record: &log::Record) {
|
||||||
if self.enabled(record.metadata()) {
|
if self.enabled(record.metadata()) {
|
||||||
let timestamp = unsafe { GlobalTimer::get() }.get_us().0;
|
let timestamp = unsafe {
|
||||||
let seconds = timestamp / 1_000_000;
|
GlobalTimer::get()
|
||||||
let micros = timestamp % 1_000_000;
|
}.get_us().0;
|
||||||
|
let seconds = timestamp / 1_000_000;
|
||||||
|
let micros = timestamp % 1_000_000;
|
||||||
|
|
||||||
if record.level() <= self.buffer_log_level() {
|
if record.level() <= self.buffer_log_level() {
|
||||||
let mut buffer = self.buffer.lock();
|
let mut buffer = self.buffer.lock();
|
||||||
writeln!(
|
writeln!(buffer, "[{:6}.{:06}s] {:>5}({}): {}", seconds, micros,
|
||||||
buffer,
|
record.level(), record.target(), record.args()).unwrap();
|
||||||
"[{:6}.{:06}s] {:>5}({}): {}",
|
|
||||||
seconds,
|
|
||||||
micros,
|
|
||||||
record.level(),
|
|
||||||
record.target(),
|
|
||||||
record.args()
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if record.level() <= self.uart_log_level() {
|
if record.level() <= self.uart_log_level() {
|
||||||
println!(
|
println!("[{:6}.{:06}s] {:>5}({}): {}", seconds, micros,
|
||||||
"[{:6}.{:06}s] {:>5}({}): {}",
|
record.level(), record.target(), record.args());
|
||||||
seconds,
|
|
||||||
micros,
|
|
||||||
record.level(),
|
|
||||||
record.target(),
|
|
||||||
record.args()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn flush(&self) {}
|
fn flush(&self) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
use core::result;
|
use core::result;
|
||||||
|
|
||||||
use embedded_hal::blocking::delay::DelayUs;
|
|
||||||
use libboard_zynq::{i2c::I2c, time::Milliseconds, timer::GlobalTimer};
|
|
||||||
use log::info;
|
use log::info;
|
||||||
|
use libboard_zynq::{i2c::I2c, timer::GlobalTimer, time::Milliseconds};
|
||||||
|
use embedded_hal::blocking::delay::DelayUs;
|
||||||
#[cfg(not(si5324_soft_reset))]
|
#[cfg(not(si5324_soft_reset))]
|
||||||
use crate::pl::csr;
|
use crate::pl::csr;
|
||||||
|
|
||||||
|
@ -13,13 +11,9 @@ const ADDRESS: u8 = 0x68;
|
||||||
|
|
||||||
#[cfg(not(si5324_soft_reset))]
|
#[cfg(not(si5324_soft_reset))]
|
||||||
fn hard_reset(timer: &mut GlobalTimer) {
|
fn hard_reset(timer: &mut GlobalTimer) {
|
||||||
unsafe {
|
unsafe { csr::si5324_rst_n::out_write(0); }
|
||||||
csr::si5324_rst_n::out_write(0);
|
|
||||||
}
|
|
||||||
timer.delay_us(1_000);
|
timer.delay_us(1_000);
|
||||||
unsafe {
|
unsafe { csr::si5324_rst_n::out_write(1); }
|
||||||
csr::si5324_rst_n::out_write(1);
|
|
||||||
}
|
|
||||||
timer.delay_us(10_000);
|
timer.delay_us(10_000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,7 +29,7 @@ pub struct FrequencySettings {
|
||||||
pub n31: u32,
|
pub n31: u32,
|
||||||
pub n32: u32,
|
pub n32: u32,
|
||||||
pub bwsel: u8,
|
pub bwsel: u8,
|
||||||
pub crystal_as_ckin2: bool,
|
pub crystal_ref: bool
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum Input {
|
pub enum Input {
|
||||||
|
@ -45,52 +39,52 @@ pub enum Input {
|
||||||
|
|
||||||
fn map_frequency_settings(settings: &FrequencySettings) -> Result<FrequencySettings> {
|
fn map_frequency_settings(settings: &FrequencySettings) -> Result<FrequencySettings> {
|
||||||
if settings.nc1_ls != 0 && (settings.nc1_ls % 2) == 1 {
|
if settings.nc1_ls != 0 && (settings.nc1_ls % 2) == 1 {
|
||||||
return Err("NC1_LS must be 0 or even");
|
return Err("NC1_LS must be 0 or even")
|
||||||
}
|
}
|
||||||
if settings.nc1_ls > (1 << 20) {
|
if settings.nc1_ls > (1 << 20) {
|
||||||
return Err("NC1_LS is too high");
|
return Err("NC1_LS is too high")
|
||||||
}
|
}
|
||||||
if (settings.n2_ls % 2) == 1 {
|
if (settings.n2_ls % 2) == 1 {
|
||||||
return Err("N2_LS must be even");
|
return Err("N2_LS must be even")
|
||||||
}
|
}
|
||||||
if settings.n2_ls > (1 << 20) {
|
if settings.n2_ls > (1 << 20) {
|
||||||
return Err("N2_LS is too high");
|
return Err("N2_LS is too high")
|
||||||
}
|
}
|
||||||
if settings.n31 > (1 << 19) {
|
if settings.n31 > (1 << 19) {
|
||||||
return Err("N31 is too high");
|
return Err("N31 is too high")
|
||||||
}
|
}
|
||||||
if settings.n32 > (1 << 19) {
|
if settings.n32 > (1 << 19) {
|
||||||
return Err("N32 is too high");
|
return Err("N32 is too high")
|
||||||
}
|
}
|
||||||
let r = FrequencySettings {
|
let r = FrequencySettings {
|
||||||
n1_hs: match settings.n1_hs {
|
n1_hs: match settings.n1_hs {
|
||||||
4 => 0b000,
|
4 => 0b000,
|
||||||
5 => 0b001,
|
5 => 0b001,
|
||||||
6 => 0b010,
|
6 => 0b010,
|
||||||
7 => 0b011,
|
7 => 0b011,
|
||||||
8 => 0b100,
|
8 => 0b100,
|
||||||
9 => 0b101,
|
9 => 0b101,
|
||||||
10 => 0b110,
|
10 => 0b110,
|
||||||
11 => 0b111,
|
11 => 0b111,
|
||||||
_ => return Err("N1_HS has an invalid value"),
|
_ => return Err("N1_HS has an invalid value")
|
||||||
},
|
},
|
||||||
nc1_ls: settings.nc1_ls - 1,
|
nc1_ls: settings.nc1_ls - 1,
|
||||||
n2_hs: match settings.n2_hs {
|
n2_hs: match settings.n2_hs {
|
||||||
4 => 0b000,
|
4 => 0b000,
|
||||||
5 => 0b001,
|
5 => 0b001,
|
||||||
6 => 0b010,
|
6 => 0b010,
|
||||||
7 => 0b011,
|
7 => 0b011,
|
||||||
8 => 0b100,
|
8 => 0b100,
|
||||||
9 => 0b101,
|
9 => 0b101,
|
||||||
10 => 0b110,
|
10 => 0b110,
|
||||||
11 => 0b111,
|
11 => 0b111,
|
||||||
_ => return Err("N2_HS has an invalid value"),
|
_ => return Err("N2_HS has an invalid value")
|
||||||
},
|
},
|
||||||
n2_ls: settings.n2_ls - 1,
|
n2_ls: settings.n2_ls - 1,
|
||||||
n31: settings.n31 - 1,
|
n31: settings.n31 - 1,
|
||||||
n32: settings.n32 - 1,
|
n32: settings.n32 - 1,
|
||||||
bwsel: settings.bwsel,
|
bwsel: settings.bwsel,
|
||||||
crystal_as_ckin2: settings.crystal_as_ckin2,
|
crystal_ref: settings.crystal_ref
|
||||||
};
|
};
|
||||||
Ok(r)
|
Ok(r)
|
||||||
}
|
}
|
||||||
|
@ -98,13 +92,13 @@ fn map_frequency_settings(settings: &FrequencySettings) -> Result<FrequencySetti
|
||||||
fn write(i2c: &mut I2c, reg: u8, val: u8) -> Result<()> {
|
fn write(i2c: &mut I2c, reg: u8, val: u8) -> Result<()> {
|
||||||
i2c.start().unwrap();
|
i2c.start().unwrap();
|
||||||
if !i2c.write(ADDRESS << 1).unwrap() {
|
if !i2c.write(ADDRESS << 1).unwrap() {
|
||||||
return Err("Si5324 failed to ack write address");
|
return Err("Si5324 failed to ack write address")
|
||||||
}
|
}
|
||||||
if !i2c.write(reg).unwrap() {
|
if !i2c.write(reg).unwrap() {
|
||||||
return Err("Si5324 failed to ack register");
|
return Err("Si5324 failed to ack register")
|
||||||
}
|
}
|
||||||
if !i2c.write(val).unwrap() {
|
if !i2c.write(val).unwrap() {
|
||||||
return Err("Si5324 failed to ack value");
|
return Err("Si5324 failed to ack value")
|
||||||
}
|
}
|
||||||
i2c.stop().unwrap();
|
i2c.stop().unwrap();
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -114,10 +108,10 @@ fn write(i2c: &mut I2c, reg: u8, val: u8) -> Result<()> {
|
||||||
fn write_no_ack_value(i2c: &mut I2c, reg: u8, val: u8) -> Result<()> {
|
fn write_no_ack_value(i2c: &mut I2c, reg: u8, val: u8) -> Result<()> {
|
||||||
i2c.start().unwrap();
|
i2c.start().unwrap();
|
||||||
if !i2c.write(ADDRESS << 1).unwrap() {
|
if !i2c.write(ADDRESS << 1).unwrap() {
|
||||||
return Err("Si5324 failed to ack write address");
|
return Err("Si5324 failed to ack write address")
|
||||||
}
|
}
|
||||||
if !i2c.write(reg).unwrap() {
|
if !i2c.write(reg).unwrap() {
|
||||||
return Err("Si5324 failed to ack register");
|
return Err("Si5324 failed to ack register")
|
||||||
}
|
}
|
||||||
i2c.write(val).unwrap();
|
i2c.write(val).unwrap();
|
||||||
i2c.stop().unwrap();
|
i2c.stop().unwrap();
|
||||||
|
@ -127,22 +121,22 @@ fn write_no_ack_value(i2c: &mut I2c, reg: u8, val: u8) -> Result<()> {
|
||||||
fn read(i2c: &mut I2c, reg: u8) -> Result<u8> {
|
fn read(i2c: &mut I2c, reg: u8) -> Result<u8> {
|
||||||
i2c.start().unwrap();
|
i2c.start().unwrap();
|
||||||
if !i2c.write(ADDRESS << 1).unwrap() {
|
if !i2c.write(ADDRESS << 1).unwrap() {
|
||||||
return Err("Si5324 failed to ack write address");
|
return Err("Si5324 failed to ack write address")
|
||||||
}
|
}
|
||||||
if !i2c.write(reg).unwrap() {
|
if !i2c.write(reg).unwrap() {
|
||||||
return Err("Si5324 failed to ack register");
|
return Err("Si5324 failed to ack register")
|
||||||
}
|
}
|
||||||
i2c.restart().unwrap();
|
i2c.restart().unwrap();
|
||||||
if !i2c.write((ADDRESS << 1) | 1).unwrap() {
|
if !i2c.write((ADDRESS << 1) | 1).unwrap() {
|
||||||
return Err("Si5324 failed to ack read address");
|
return Err("Si5324 failed to ack read address")
|
||||||
}
|
}
|
||||||
let val = i2c.read(false).unwrap();
|
let val = i2c.read(false).unwrap();
|
||||||
i2c.stop().unwrap();
|
i2c.stop().unwrap();
|
||||||
Ok(val)
|
Ok(val)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rmw<F>(i2c: &mut I2c, reg: u8, f: F) -> Result<()>
|
fn rmw<F>(i2c: &mut I2c, reg: u8, f: F) -> Result<()> where
|
||||||
where F: Fn(u8) -> u8 {
|
F: Fn(u8) -> u8 {
|
||||||
let value = read(i2c, reg)?;
|
let value = read(i2c, reg)?;
|
||||||
write(i2c, reg, f(value))?;
|
write(i2c, reg, f(value))?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -161,18 +155,18 @@ fn soft_reset(i2c: &mut I2c, timer: &mut GlobalTimer) -> Result<()> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn has_xtal(i2c: &mut I2c) -> Result<bool> {
|
fn has_xtal(i2c: &mut I2c) -> Result<bool> {
|
||||||
Ok((read(i2c, 129)? & 0x01) == 0) // LOSX_INT=0
|
Ok((read(i2c, 129)? & 0x01) == 0) // LOSX_INT=0
|
||||||
}
|
}
|
||||||
|
|
||||||
fn has_ckin(i2c: &mut I2c, input: Input) -> Result<bool> {
|
fn has_ckin(i2c: &mut I2c, input: Input) -> Result<bool> {
|
||||||
match input {
|
match input {
|
||||||
Input::Ckin1 => Ok((read(i2c, 129)? & 0x02) == 0), // LOS1_INT=0
|
Input::Ckin1 => Ok((read(i2c, 129)? & 0x02) == 0), // LOS1_INT=0
|
||||||
Input::Ckin2 => Ok((read(i2c, 129)? & 0x04) == 0), // LOS2_INT=0
|
Input::Ckin2 => Ok((read(i2c, 129)? & 0x04) == 0), // LOS2_INT=0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn locked(i2c: &mut I2c) -> Result<bool> {
|
fn locked(i2c: &mut I2c) -> Result<bool> {
|
||||||
Ok((read(i2c, 130)? & 0x01) == 0) // LOL_INT=0
|
Ok((read(i2c, 130)? & 0x01) == 0) // LOL_INT=0
|
||||||
}
|
}
|
||||||
|
|
||||||
fn monitor_lock(i2c: &mut I2c, timer: &mut GlobalTimer) -> Result<()> {
|
fn monitor_lock(i2c: &mut I2c, timer: &mut GlobalTimer) -> Result<()> {
|
||||||
|
@ -217,11 +211,11 @@ pub fn bypass(i2c: &mut I2c, input: Input, timer: &mut GlobalTimer) -> Result<()
|
||||||
Input::Ckin2 => 0b01,
|
Input::Ckin2 => 0b01,
|
||||||
};
|
};
|
||||||
init(i2c, timer)?;
|
init(i2c, timer)?;
|
||||||
rmw(i2c, 21, |v| v & 0xfe)?; // CKSEL_PIN=0
|
rmw(i2c, 21, |v| v & 0xfe)?; // CKSEL_PIN=0
|
||||||
rmw(i2c, 3, |v| (v & 0x3f) | (cksel_reg << 6))?; // CKSEL_REG
|
rmw(i2c, 3, |v| (v & 0x3f) | (cksel_reg << 6))?; // CKSEL_REG
|
||||||
rmw(i2c, 4, |v| (v & 0x3f) | (0b00 << 6))?; // AUTOSEL_REG=b00
|
rmw(i2c, 4, |v| (v & 0x3f) | (0b00 << 6))?; // AUTOSEL_REG=b00
|
||||||
rmw(i2c, 6, |v| (v & 0xc0) | 0b111111)?; // SFOUT2_REG=b111 SFOUT1_REG=b111
|
rmw(i2c, 6, |v| (v & 0xc0) | 0b111111)?; // SFOUT2_REG=b111 SFOUT1_REG=b111
|
||||||
rmw(i2c, 0, |v| (v & 0xfd) | 0x02)?; // BYPASS_REG=1
|
rmw(i2c, 0, |v| (v & 0xfd) | 0x02)?; // BYPASS_REG=1
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -233,32 +227,32 @@ pub fn setup(i2c: &mut I2c, settings: &FrequencySettings, input: Input, timer: &
|
||||||
};
|
};
|
||||||
|
|
||||||
init(i2c, timer)?;
|
init(i2c, timer)?;
|
||||||
if settings.crystal_as_ckin2 {
|
if settings.crystal_ref {
|
||||||
rmw(i2c, 0, |v| v | 0x40)?; // FREE_RUN=1
|
rmw(i2c, 0, |v| v | 0x40)?; // FREE_RUN=1
|
||||||
}
|
}
|
||||||
rmw(i2c, 2, |v| (v & 0x0f) | (s.bwsel << 4))?;
|
rmw(i2c, 2, |v| (v & 0x0f) | (s.bwsel << 4))?;
|
||||||
rmw(i2c, 21, |v| v & 0xfe)?; // CKSEL_PIN=0
|
rmw(i2c, 21, |v| v & 0xfe)?; // CKSEL_PIN=0
|
||||||
rmw(i2c, 3, |v| (v & 0x2f) | (cksel_reg << 6) | 0x10)?; // CKSEL_REG, SQ_ICAL=1
|
rmw(i2c, 3, |v| (v & 0x2f) | (cksel_reg << 6) | 0x10)?; // CKSEL_REG, SQ_ICAL=1
|
||||||
rmw(i2c, 4, |v| (v & 0x3f) | (0b00 << 6))?; // AUTOSEL_REG=b00
|
rmw(i2c, 4, |v| (v & 0x3f) | (0b00 << 6))?; // AUTOSEL_REG=b00
|
||||||
rmw(i2c, 6, |v| (v & 0xc0) | 0b111111)?; // SFOUT2_REG=b111 SFOUT1_REG=b111
|
rmw(i2c, 6, |v| (v & 0xc0) | 0b111111)?; // SFOUT2_REG=b111 SFOUT1_REG=b111
|
||||||
write(i2c, 25, (s.n1_hs << 5) as u8)?;
|
write(i2c, 25, (s.n1_hs << 5 ) as u8)?;
|
||||||
write(i2c, 31, (s.nc1_ls >> 16) as u8)?;
|
write(i2c, 31, (s.nc1_ls >> 16) as u8)?;
|
||||||
write(i2c, 32, (s.nc1_ls >> 8) as u8)?;
|
write(i2c, 32, (s.nc1_ls >> 8 ) as u8)?;
|
||||||
write(i2c, 33, (s.nc1_ls) as u8)?;
|
write(i2c, 33, (s.nc1_ls) as u8)?;
|
||||||
write(i2c, 34, (s.nc1_ls >> 16) as u8)?; // write to NC2_LS as well
|
write(i2c, 34, (s.nc1_ls >> 16) as u8)?; // write to NC2_LS as well
|
||||||
write(i2c, 35, (s.nc1_ls >> 8) as u8)?;
|
write(i2c, 35, (s.nc1_ls >> 8 ) as u8)?;
|
||||||
write(i2c, 36, (s.nc1_ls) as u8)?;
|
write(i2c, 36, (s.nc1_ls) as u8)?;
|
||||||
write(i2c, 40, (s.n2_hs << 5) as u8 | (s.n2_ls >> 16) as u8)?;
|
write(i2c, 40, (s.n2_hs << 5 ) as u8 | (s.n2_ls >> 16) as u8)?;
|
||||||
write(i2c, 41, (s.n2_ls >> 8) as u8)?;
|
write(i2c, 41, (s.n2_ls >> 8 ) as u8)?;
|
||||||
write(i2c, 42, (s.n2_ls) as u8)?;
|
write(i2c, 42, (s.n2_ls) as u8)?;
|
||||||
write(i2c, 43, (s.n31 >> 16) as u8)?;
|
write(i2c, 43, (s.n31 >> 16) as u8)?;
|
||||||
write(i2c, 44, (s.n31 >> 8) as u8)?;
|
write(i2c, 44, (s.n31 >> 8) as u8)?;
|
||||||
write(i2c, 45, (s.n31) as u8)?;
|
write(i2c, 45, (s.n31) as u8)?;
|
||||||
write(i2c, 46, (s.n32 >> 16) as u8)?;
|
write(i2c, 46, (s.n32 >> 16) as u8)?;
|
||||||
write(i2c, 47, (s.n32 >> 8) as u8)?;
|
write(i2c, 47, (s.n32 >> 8) as u8)?;
|
||||||
write(i2c, 48, (s.n32) as u8)?;
|
write(i2c, 48, (s.n32) as u8)?;
|
||||||
rmw(i2c, 137, |v| v | 0x01)?; // FASTLOCK=1
|
rmw(i2c, 137, |v| v | 0x01)?; // FASTLOCK=1
|
||||||
rmw(i2c, 136, |v| v | 0x40)?; // ICAL=1
|
rmw(i2c, 136, |v| v | 0x40)?; // ICAL=1
|
||||||
|
|
||||||
if !has_xtal(i2c)? {
|
if !has_xtal(i2c)? {
|
||||||
return Err("Si5324 misses XA/XB signal");
|
return Err("Si5324 misses XA/XB signal");
|
||||||
|
@ -276,7 +270,7 @@ pub fn select_input(i2c: &mut I2c, input: Input, timer: &mut GlobalTimer) -> Res
|
||||||
Input::Ckin1 => 0b00,
|
Input::Ckin1 => 0b00,
|
||||||
Input::Ckin2 => 0b01,
|
Input::Ckin2 => 0b01,
|
||||||
};
|
};
|
||||||
rmw(i2c, 3, |v| (v & 0x3f) | (cksel_reg << 6))?;
|
rmw(i2c, 3, |v| (v & 0x3f) | (cksel_reg << 6))?;
|
||||||
if !has_ckin(i2c, input)? {
|
if !has_ckin(i2c, input)? {
|
||||||
return Err("Si5324 misses clock input signal");
|
return Err("Si5324 misses clock input signal");
|
||||||
}
|
}
|
||||||
|
@ -291,12 +285,12 @@ pub mod siphaser {
|
||||||
|
|
||||||
pub fn select_recovered_clock(i2c: &mut I2c, rc: bool, timer: &mut GlobalTimer) -> Result<()> {
|
pub fn select_recovered_clock(i2c: &mut I2c, rc: bool, timer: &mut GlobalTimer) -> Result<()> {
|
||||||
let val = read(i2c, 3)?;
|
let val = read(i2c, 3)?;
|
||||||
write(i2c, 3, (val & 0xdf) | (1 << 5))?; // DHOLD=1
|
write(i2c, 3, (val & 0xdf) | (1 << 5))?; // DHOLD=1
|
||||||
unsafe {
|
unsafe {
|
||||||
csr::siphaser::switch_clocks_write(if rc { 1 } else { 0 });
|
csr::siphaser::switch_clocks_write(if rc { 1 } else { 0 });
|
||||||
}
|
}
|
||||||
let val = read(i2c, 3)?;
|
let val = read(i2c, 3)?;
|
||||||
write(i2c, 3, (val & 0xdf) | (0 << 5))?; // DHOLD=0
|
write(i2c, 3, (val & 0xdf) | (0 << 5))?; // DHOLD=0
|
||||||
monitor_lock(i2c, timer)?;
|
monitor_lock(i2c, timer)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -315,7 +309,9 @@ pub mod siphaser {
|
||||||
csr::siphaser::error_write(1);
|
csr::siphaser::error_write(1);
|
||||||
}
|
}
|
||||||
timer.delay_us(5_000);
|
timer.delay_us(5_000);
|
||||||
unsafe { csr::siphaser::error_read() != 0 }
|
unsafe {
|
||||||
|
csr::siphaser::error_read() != 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_edge(target: bool, timer: &mut GlobalTimer) -> Result<u32> {
|
fn find_edge(target: bool, timer: &mut GlobalTimer) -> Result<u32> {
|
||||||
|
@ -344,19 +340,14 @@ pub mod siphaser {
|
||||||
}
|
}
|
||||||
let width = find_edge(true, timer)? + jitter_margin;
|
let width = find_edge(true, timer)? + jitter_margin;
|
||||||
// width is 360 degrees (one full rotation of the phase between s/h limits) minus jitter
|
// width is 360 degrees (one full rotation of the phase between s/h limits) minus jitter
|
||||||
info!(
|
info!("calibration successful, lead: {}, width: {} ({}deg)", lead, width, width*360/(56*8));
|
||||||
"calibration successful, lead: {}, width: {} ({}deg)",
|
|
||||||
lead,
|
|
||||||
width,
|
|
||||||
width * 360 / (56 * 8)
|
|
||||||
);
|
|
||||||
|
|
||||||
// Apply reverse phase shift for half the width to get into the
|
// Apply reverse phase shift for half the width to get into the
|
||||||
// middle of the working region.
|
// middle of the working region.
|
||||||
for _ in 0..width / 2 {
|
for _ in 0..width/2 {
|
||||||
phase_shift(0, timer);
|
phase_shift(0, timer);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,7 +1,8 @@
|
||||||
use std::{env,
|
use std::env;
|
||||||
fs::File,
|
use std::fs::File;
|
||||||
io::{BufRead, BufReader, Write},
|
use std::io::{BufRead, BufReader, Write};
|
||||||
path::PathBuf};
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
|
||||||
pub fn add_linker_script() {
|
pub fn add_linker_script() {
|
||||||
// Put the linker script somewhere the linker can find it
|
// Put the linker script somewhere the linker can find it
|
||||||
|
|
|
@ -4,7 +4,8 @@ fn main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
mod libc {
|
mod libc {
|
||||||
use std::{env, path::Path};
|
use std::path::Path;
|
||||||
|
use std::env;
|
||||||
|
|
||||||
pub fn compile() {
|
pub fn compile() {
|
||||||
let cfg = &mut cc::Build::new();
|
let cfg = &mut cc::Build::new();
|
||||||
|
@ -31,7 +32,9 @@ mod libc {
|
||||||
cfg.flag("-U_FORTIFY_SOURCE");
|
cfg.flag("-U_FORTIFY_SOURCE");
|
||||||
cfg.define("_FORTIFY_SOURCE", Some("0"));
|
cfg.define("_FORTIFY_SOURCE", Some("0"));
|
||||||
|
|
||||||
let sources = vec!["printf.c"];
|
let sources = vec![
|
||||||
|
"printf.c"
|
||||||
|
];
|
||||||
|
|
||||||
let root = Path::new("./");
|
let root = Path::new("./");
|
||||||
for src in sources {
|
for src in sources {
|
||||||
|
|
|
@ -11,11 +11,9 @@
|
||||||
#![allow(non_upper_case_globals)]
|
#![allow(non_upper_case_globals)]
|
||||||
#![allow(unused)]
|
#![allow(unused)]
|
||||||
|
|
||||||
use core::mem;
|
|
||||||
|
|
||||||
use cslice::CSlice;
|
|
||||||
|
|
||||||
use crate::DwarfReader;
|
use crate::DwarfReader;
|
||||||
|
use core::mem;
|
||||||
|
use cslice::CSlice;
|
||||||
|
|
||||||
pub const DW_EH_PE_omit: u8 = 0xFF;
|
pub const DW_EH_PE_omit: u8 = 0xFF;
|
||||||
pub const DW_EH_PE_absptr: u8 = 0x00;
|
pub const DW_EH_PE_absptr: u8 = 0x00;
|
||||||
|
@ -162,11 +160,15 @@ pub unsafe fn find_eh_action(
|
||||||
if ar_filter == 0 {
|
if ar_filter == 0 {
|
||||||
saw_cleanup = true;
|
saw_cleanup = true;
|
||||||
} else if ar_filter > 0 {
|
} else if ar_filter > 0 {
|
||||||
let catch_type =
|
let catch_type = get_ttype_entry(
|
||||||
get_ttype_entry(ar_filter as usize, ttype_encoding, ttype_base, ttype_table)?;
|
ar_filter as usize,
|
||||||
|
ttype_encoding,
|
||||||
|
ttype_base,
|
||||||
|
ttype_table,
|
||||||
|
)?;
|
||||||
match catch_type {
|
match catch_type {
|
||||||
Some(clause_ptr) if *(clause_ptr as *const u32) == id => {
|
Some(clause_ptr) if *(clause_ptr as *const u32) == id => {
|
||||||
return Ok(EHAction::Catch(lpad));
|
return Ok(EHAction::Catch(lpad))
|
||||||
}
|
}
|
||||||
None => return Ok(EHAction::Catch(lpad)),
|
None => return Ok(EHAction::Catch(lpad)),
|
||||||
_ => {}
|
_ => {}
|
||||||
|
@ -249,11 +251,19 @@ fn get_base(encoding: u8, context: &EHContext<'_>) -> Result<usize, ()> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn read_encoded_pointer(reader: &mut DwarfReader, context: &EHContext<'_>, encoding: u8) -> Result<usize, ()> {
|
unsafe fn read_encoded_pointer(
|
||||||
|
reader: &mut DwarfReader,
|
||||||
|
context: &EHContext<'_>,
|
||||||
|
encoding: u8,
|
||||||
|
) -> Result<usize, ()> {
|
||||||
read_encoded_pointer_with_base(reader, encoding, get_base(encoding, context)?)
|
read_encoded_pointer_with_base(reader, encoding, get_base(encoding, context)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn read_encoded_pointer_with_base(reader: &mut DwarfReader, encoding: u8, base: usize) -> Result<usize, ()> {
|
unsafe fn read_encoded_pointer_with_base(
|
||||||
|
reader: &mut DwarfReader,
|
||||||
|
encoding: u8,
|
||||||
|
base: usize,
|
||||||
|
) -> Result<usize, ()> {
|
||||||
if encoding == DW_EH_PE_omit {
|
if encoding == DW_EH_PE_omit {
|
||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
|
|
|
@ -1451,7 +1451,8 @@ pub const R_AARCH64_TLSDESC_CALL: usize = 569;
|
||||||
pub const R_AARCH64_TLSLE_LDST128_TPREL_LO12: usize = 570;
|
pub const R_AARCH64_TLSLE_LDST128_TPREL_LO12: usize = 570;
|
||||||
pub const R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC: usize = 571;
|
pub const R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC: usize = 571;
|
||||||
pub const R_AARCH64_TLSLD_LDST128_DTPREL_LO12: usize = 572;
|
pub const R_AARCH64_TLSLD_LDST128_DTPREL_LO12: usize = 572;
|
||||||
pub const R_AARCH64_TLSLD_LDST128_DTPREL_LO12_NC: usize = 573;
|
pub const R_AARCH64_TLSLD_LDST128_DTPREL_LO12_NC: usize =
|
||||||
|
573;
|
||||||
pub const R_AARCH64_COPY: usize = 1024;
|
pub const R_AARCH64_COPY: usize = 1024;
|
||||||
pub const R_AARCH64_GLOB_DAT: usize = 1025;
|
pub const R_AARCH64_GLOB_DAT: usize = 1025;
|
||||||
pub const R_AARCH64_JUMP_SLOT: usize = 1026;
|
pub const R_AARCH64_JUMP_SLOT: usize = 1026;
|
||||||
|
@ -2266,9 +2267,7 @@ pub struct Elf32_Ehdr {
|
||||||
pub e_shstrndx: Elf32_Half,
|
pub e_shstrndx: Elf32_Half,
|
||||||
}
|
}
|
||||||
impl Clone for Elf32_Ehdr {
|
impl Clone for Elf32_Ehdr {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self { *self }
|
||||||
*self
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Copy)]
|
#[derive(Debug, Copy)]
|
||||||
|
@ -2289,9 +2288,7 @@ pub struct Elf64_Ehdr {
|
||||||
pub e_shstrndx: Elf64_Half,
|
pub e_shstrndx: Elf64_Half,
|
||||||
}
|
}
|
||||||
impl Clone for Elf64_Ehdr {
|
impl Clone for Elf64_Ehdr {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self { *self }
|
||||||
*self
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Copy)]
|
#[derive(Debug, Copy)]
|
||||||
|
@ -2308,9 +2305,7 @@ pub struct Elf32_Shdr {
|
||||||
pub sh_entsize: Elf32_Word,
|
pub sh_entsize: Elf32_Word,
|
||||||
}
|
}
|
||||||
impl Clone for Elf32_Shdr {
|
impl Clone for Elf32_Shdr {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self { *self }
|
||||||
*self
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Copy)]
|
#[derive(Debug, Copy)]
|
||||||
|
@ -2327,9 +2322,7 @@ pub struct Elf64_Shdr {
|
||||||
pub sh_entsize: Elf64_Xword,
|
pub sh_entsize: Elf64_Xword,
|
||||||
}
|
}
|
||||||
impl Clone for Elf64_Shdr {
|
impl Clone for Elf64_Shdr {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self { *self }
|
||||||
*self
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Copy)]
|
#[derive(Debug, Copy)]
|
||||||
|
@ -2342,9 +2335,7 @@ pub struct Elf32_Sym {
|
||||||
pub st_shndx: Elf32_Section,
|
pub st_shndx: Elf32_Section,
|
||||||
}
|
}
|
||||||
impl Clone for Elf32_Sym {
|
impl Clone for Elf32_Sym {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self { *self }
|
||||||
*self
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Copy)]
|
#[derive(Debug, Copy)]
|
||||||
|
@ -2357,9 +2348,7 @@ pub struct Elf64_Sym {
|
||||||
pub st_size: Elf64_Xword,
|
pub st_size: Elf64_Xword,
|
||||||
}
|
}
|
||||||
impl Clone for Elf64_Sym {
|
impl Clone for Elf64_Sym {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self { *self }
|
||||||
*self
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Copy)]
|
#[derive(Debug, Copy)]
|
||||||
|
@ -2368,9 +2357,7 @@ pub struct Elf32_Syminfo {
|
||||||
pub si_flags: Elf32_Half,
|
pub si_flags: Elf32_Half,
|
||||||
}
|
}
|
||||||
impl Clone for Elf32_Syminfo {
|
impl Clone for Elf32_Syminfo {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self { *self }
|
||||||
*self
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Copy)]
|
#[derive(Debug, Copy)]
|
||||||
|
@ -2379,9 +2366,7 @@ pub struct Elf64_Syminfo {
|
||||||
pub si_flags: Elf64_Half,
|
pub si_flags: Elf64_Half,
|
||||||
}
|
}
|
||||||
impl Clone for Elf64_Syminfo {
|
impl Clone for Elf64_Syminfo {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self { *self }
|
||||||
*self
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Copy)]
|
#[derive(Debug, Copy)]
|
||||||
|
@ -2390,9 +2375,7 @@ pub struct Elf32_Rel {
|
||||||
pub r_info: Elf32_Word,
|
pub r_info: Elf32_Word,
|
||||||
}
|
}
|
||||||
impl Clone for Elf32_Rel {
|
impl Clone for Elf32_Rel {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self { *self }
|
||||||
*self
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Copy)]
|
#[derive(Debug, Copy)]
|
||||||
|
@ -2401,9 +2384,7 @@ pub struct Elf64_Rel {
|
||||||
pub r_info: Elf64_Xword,
|
pub r_info: Elf64_Xword,
|
||||||
}
|
}
|
||||||
impl Clone for Elf64_Rel {
|
impl Clone for Elf64_Rel {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self { *self }
|
||||||
*self
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Copy)]
|
#[derive(Debug, Copy)]
|
||||||
|
@ -2413,9 +2394,7 @@ pub struct Elf32_Rela {
|
||||||
pub r_addend: Elf32_Sword,
|
pub r_addend: Elf32_Sword,
|
||||||
}
|
}
|
||||||
impl Clone for Elf32_Rela {
|
impl Clone for Elf32_Rela {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self { *self }
|
||||||
*self
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Copy)]
|
#[derive(Debug, Copy)]
|
||||||
|
@ -2425,9 +2404,7 @@ pub struct Elf64_Rela {
|
||||||
pub r_addend: Elf64_Sxword,
|
pub r_addend: Elf64_Sxword,
|
||||||
}
|
}
|
||||||
impl Clone for Elf64_Rela {
|
impl Clone for Elf64_Rela {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self { *self }
|
||||||
*self
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Copy)]
|
#[derive(Debug, Copy)]
|
||||||
|
@ -2442,9 +2419,7 @@ pub struct Elf32_Phdr {
|
||||||
pub p_align: Elf32_Word,
|
pub p_align: Elf32_Word,
|
||||||
}
|
}
|
||||||
impl Clone for Elf32_Phdr {
|
impl Clone for Elf32_Phdr {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self { *self }
|
||||||
*self
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Copy)]
|
#[derive(Debug, Copy)]
|
||||||
|
@ -2459,9 +2434,7 @@ pub struct Elf64_Phdr {
|
||||||
pub p_align: Elf64_Xword,
|
pub p_align: Elf64_Xword,
|
||||||
}
|
}
|
||||||
impl Clone for Elf64_Phdr {
|
impl Clone for Elf64_Phdr {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self { *self }
|
||||||
*self
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Copy)]
|
#[derive(Copy)]
|
||||||
|
@ -2476,14 +2449,10 @@ pub union Elf32_Dyn__bindgen_ty_1 {
|
||||||
pub d_ptr: Elf32_Addr,
|
pub d_ptr: Elf32_Addr,
|
||||||
}
|
}
|
||||||
impl Clone for Elf32_Dyn__bindgen_ty_1 {
|
impl Clone for Elf32_Dyn__bindgen_ty_1 {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self { *self }
|
||||||
*self
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
impl Clone for Elf32_Dyn {
|
impl Clone for Elf32_Dyn {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self { *self }
|
||||||
*self
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Copy)]
|
#[derive(Copy)]
|
||||||
|
@ -2498,14 +2467,10 @@ pub union Elf64_Dyn__bindgen_ty_1 {
|
||||||
pub d_ptr: Elf64_Addr,
|
pub d_ptr: Elf64_Addr,
|
||||||
}
|
}
|
||||||
impl Clone for Elf64_Dyn__bindgen_ty_1 {
|
impl Clone for Elf64_Dyn__bindgen_ty_1 {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self { *self }
|
||||||
*self
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
impl Clone for Elf64_Dyn {
|
impl Clone for Elf64_Dyn {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self { *self }
|
||||||
*self
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Copy)]
|
#[derive(Debug, Copy)]
|
||||||
|
@ -2519,9 +2484,7 @@ pub struct Elf32_Verdef {
|
||||||
pub vd_next: Elf32_Word,
|
pub vd_next: Elf32_Word,
|
||||||
}
|
}
|
||||||
impl Clone for Elf32_Verdef {
|
impl Clone for Elf32_Verdef {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self { *self }
|
||||||
*self
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Copy)]
|
#[derive(Debug, Copy)]
|
||||||
|
@ -2535,9 +2498,7 @@ pub struct Elf64_Verdef {
|
||||||
pub vd_next: Elf64_Word,
|
pub vd_next: Elf64_Word,
|
||||||
}
|
}
|
||||||
impl Clone for Elf64_Verdef {
|
impl Clone for Elf64_Verdef {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self { *self }
|
||||||
*self
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Copy)]
|
#[derive(Debug, Copy)]
|
||||||
|
@ -2546,9 +2507,7 @@ pub struct Elf32_Verdaux {
|
||||||
pub vda_next: Elf32_Word,
|
pub vda_next: Elf32_Word,
|
||||||
}
|
}
|
||||||
impl Clone for Elf32_Verdaux {
|
impl Clone for Elf32_Verdaux {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self { *self }
|
||||||
*self
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Copy)]
|
#[derive(Debug, Copy)]
|
||||||
|
@ -2557,9 +2516,7 @@ pub struct Elf64_Verdaux {
|
||||||
pub vda_next: Elf64_Word,
|
pub vda_next: Elf64_Word,
|
||||||
}
|
}
|
||||||
impl Clone for Elf64_Verdaux {
|
impl Clone for Elf64_Verdaux {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self { *self }
|
||||||
*self
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Copy)]
|
#[derive(Debug, Copy)]
|
||||||
|
@ -2571,9 +2528,7 @@ pub struct Elf32_Verneed {
|
||||||
pub vn_next: Elf32_Word,
|
pub vn_next: Elf32_Word,
|
||||||
}
|
}
|
||||||
impl Clone for Elf32_Verneed {
|
impl Clone for Elf32_Verneed {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self { *self }
|
||||||
*self
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Copy)]
|
#[derive(Debug, Copy)]
|
||||||
|
@ -2585,9 +2540,7 @@ pub struct Elf64_Verneed {
|
||||||
pub vn_next: Elf64_Word,
|
pub vn_next: Elf64_Word,
|
||||||
}
|
}
|
||||||
impl Clone for Elf64_Verneed {
|
impl Clone for Elf64_Verneed {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self { *self }
|
||||||
*self
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Copy)]
|
#[derive(Debug, Copy)]
|
||||||
|
@ -2599,9 +2552,7 @@ pub struct Elf32_Vernaux {
|
||||||
pub vna_next: Elf32_Word,
|
pub vna_next: Elf32_Word,
|
||||||
}
|
}
|
||||||
impl Clone for Elf32_Vernaux {
|
impl Clone for Elf32_Vernaux {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self { *self }
|
||||||
*self
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Copy)]
|
#[derive(Debug, Copy)]
|
||||||
|
@ -2613,9 +2564,7 @@ pub struct Elf64_Vernaux {
|
||||||
pub vna_next: Elf64_Word,
|
pub vna_next: Elf64_Word,
|
||||||
}
|
}
|
||||||
impl Clone for Elf64_Vernaux {
|
impl Clone for Elf64_Vernaux {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self { *self }
|
||||||
*self
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Copy)]
|
#[derive(Copy)]
|
||||||
|
@ -2629,14 +2578,10 @@ pub union Elf32_auxv_t__bindgen_ty_1 {
|
||||||
pub a_val: u32,
|
pub a_val: u32,
|
||||||
}
|
}
|
||||||
impl Clone for Elf32_auxv_t__bindgen_ty_1 {
|
impl Clone for Elf32_auxv_t__bindgen_ty_1 {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self { *self }
|
||||||
*self
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
impl Clone for Elf32_auxv_t {
|
impl Clone for Elf32_auxv_t {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self { *self }
|
||||||
*self
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Copy)]
|
#[derive(Copy)]
|
||||||
|
@ -2650,14 +2595,10 @@ pub union Elf64_auxv_t__bindgen_ty_1 {
|
||||||
pub a_val: u64,
|
pub a_val: u64,
|
||||||
}
|
}
|
||||||
impl Clone for Elf64_auxv_t__bindgen_ty_1 {
|
impl Clone for Elf64_auxv_t__bindgen_ty_1 {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self { *self }
|
||||||
*self
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
impl Clone for Elf64_auxv_t {
|
impl Clone for Elf64_auxv_t {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self { *self }
|
||||||
*self
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Copy)]
|
#[derive(Debug, Copy)]
|
||||||
|
@ -2667,9 +2608,7 @@ pub struct Elf32_Nhdr {
|
||||||
pub n_type: Elf32_Word,
|
pub n_type: Elf32_Word,
|
||||||
}
|
}
|
||||||
impl Clone for Elf32_Nhdr {
|
impl Clone for Elf32_Nhdr {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self { *self }
|
||||||
*self
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Copy)]
|
#[derive(Debug, Copy)]
|
||||||
|
@ -2679,9 +2618,7 @@ pub struct Elf64_Nhdr {
|
||||||
pub n_type: Elf64_Word,
|
pub n_type: Elf64_Word,
|
||||||
}
|
}
|
||||||
impl Clone for Elf64_Nhdr {
|
impl Clone for Elf64_Nhdr {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self { *self }
|
||||||
*self
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Copy)]
|
#[derive(Debug, Copy)]
|
||||||
|
@ -2693,9 +2630,7 @@ pub struct Elf32_Move {
|
||||||
pub m_stride: Elf32_Half,
|
pub m_stride: Elf32_Half,
|
||||||
}
|
}
|
||||||
impl Clone for Elf32_Move {
|
impl Clone for Elf32_Move {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self { *self }
|
||||||
*self
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Copy)]
|
#[derive(Debug, Copy)]
|
||||||
|
@ -2707,9 +2642,7 @@ pub struct Elf64_Move {
|
||||||
pub m_stride: Elf64_Half,
|
pub m_stride: Elf64_Half,
|
||||||
}
|
}
|
||||||
impl Clone for Elf64_Move {
|
impl Clone for Elf64_Move {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self { *self }
|
||||||
*self
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Copy)]
|
#[derive(Copy)]
|
||||||
|
@ -2724,9 +2657,7 @@ pub struct Elf32_gptab__bindgen_ty_1 {
|
||||||
pub gt_unused: Elf32_Word,
|
pub gt_unused: Elf32_Word,
|
||||||
}
|
}
|
||||||
impl Clone for Elf32_gptab__bindgen_ty_1 {
|
impl Clone for Elf32_gptab__bindgen_ty_1 {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self { *self }
|
||||||
*self
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Copy)]
|
#[derive(Debug, Copy)]
|
||||||
|
@ -2735,14 +2666,10 @@ pub struct Elf32_gptab__bindgen_ty_2 {
|
||||||
pub gt_bytes: Elf32_Word,
|
pub gt_bytes: Elf32_Word,
|
||||||
}
|
}
|
||||||
impl Clone for Elf32_gptab__bindgen_ty_2 {
|
impl Clone for Elf32_gptab__bindgen_ty_2 {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self { *self }
|
||||||
*self
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
impl Clone for Elf32_gptab {
|
impl Clone for Elf32_gptab {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self { *self }
|
||||||
*self
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Copy)]
|
#[derive(Debug, Copy)]
|
||||||
|
@ -2752,9 +2679,7 @@ pub struct Elf32_RegInfo {
|
||||||
pub ri_gp_value: Elf32_Sword,
|
pub ri_gp_value: Elf32_Sword,
|
||||||
}
|
}
|
||||||
impl Clone for Elf32_RegInfo {
|
impl Clone for Elf32_RegInfo {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self { *self }
|
||||||
*self
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Copy)]
|
#[derive(Debug, Copy)]
|
||||||
|
@ -2765,9 +2690,7 @@ pub struct Elf_Options {
|
||||||
pub info: Elf32_Word,
|
pub info: Elf32_Word,
|
||||||
}
|
}
|
||||||
impl Clone for Elf_Options {
|
impl Clone for Elf_Options {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self { *self }
|
||||||
*self
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Copy)]
|
#[derive(Debug, Copy)]
|
||||||
|
@ -2776,9 +2699,7 @@ pub struct Elf_Options_Hw {
|
||||||
pub hwp_flags2: Elf32_Word,
|
pub hwp_flags2: Elf32_Word,
|
||||||
}
|
}
|
||||||
impl Clone for Elf_Options_Hw {
|
impl Clone for Elf_Options_Hw {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self { *self }
|
||||||
*self
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Copy)]
|
#[derive(Debug, Copy)]
|
||||||
|
@ -2790,9 +2711,7 @@ pub struct Elf32_Lib {
|
||||||
pub l_flags: Elf32_Word,
|
pub l_flags: Elf32_Word,
|
||||||
}
|
}
|
||||||
impl Clone for Elf32_Lib {
|
impl Clone for Elf32_Lib {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self { *self }
|
||||||
*self
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Copy)]
|
#[derive(Debug, Copy)]
|
||||||
|
@ -2804,31 +2723,17 @@ pub struct Elf64_Lib {
|
||||||
pub l_flags: Elf64_Word,
|
pub l_flags: Elf64_Word,
|
||||||
}
|
}
|
||||||
impl Clone for Elf64_Lib {
|
impl Clone for Elf64_Lib {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self { *self }
|
||||||
*self
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
pub type Elf32_Conflict = Elf32_Addr;
|
pub type Elf32_Conflict = Elf32_Addr;
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct EXIDX_Entry(u32, u32);
|
pub struct EXIDX_Entry(u32, u32);
|
||||||
|
|
||||||
pub fn ELF32_R_SYM(info: Elf32_Word) -> Elf32_Word {
|
pub fn ELF32_R_SYM(info: Elf32_Word) -> Elf32_Word { info >> 8 }
|
||||||
info >> 8
|
pub fn ELF32_R_TYPE(info: Elf32_Word) -> u8 { info as u8 }
|
||||||
}
|
pub fn ELF32_R_INFO(sym: Elf32_Word, ty: u8) -> Elf32_Word { sym << 8 | ty as Elf32_Word }
|
||||||
pub fn ELF32_R_TYPE(info: Elf32_Word) -> u8 {
|
|
||||||
info as u8
|
|
||||||
}
|
|
||||||
pub fn ELF32_R_INFO(sym: Elf32_Word, ty: u8) -> Elf32_Word {
|
|
||||||
sym << 8 | ty as Elf32_Word
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn ELF32_ST_BIND(info: u8) -> u8 {
|
pub fn ELF32_ST_BIND(info: u8) -> u8 { info >> 4 }
|
||||||
info >> 4
|
pub fn ELF32_ST_TYPE(info: u8) -> u8 { info & 0xf }
|
||||||
}
|
pub fn ELF32_ST_INFO(bind: u8, ty: u8) -> u8 { (bind << 4) | (ty & 0xf) }
|
||||||
pub fn ELF32_ST_TYPE(info: u8) -> u8 {
|
|
||||||
info & 0xf
|
|
||||||
}
|
|
||||||
pub fn ELF32_ST_INFO(bind: u8, ty: u8) -> u8 {
|
|
||||||
(bind << 4) | (ty & 0xf)
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
use core::{mem,
|
use core::{mem, ptr, ops::{Deref, Range}};
|
||||||
ops::{Deref, Range},
|
use super::{
|
||||||
ptr};
|
Arch,
|
||||||
|
elf::*,
|
||||||
use super::{elf::*, Arch};
|
};
|
||||||
|
|
||||||
fn read_unaligned<T: Copy>(data: &[u8], offset: usize) -> Option<T> {
|
fn read_unaligned<T: Copy>(data: &[u8], offset: usize) -> Option<T> {
|
||||||
if data.len() < offset + mem::size_of::<T>() {
|
if data.len() < offset + mem::size_of::<T>() {
|
||||||
|
@ -31,40 +31,14 @@ impl<'a> File<'a> {
|
||||||
|
|
||||||
pub fn arch(&self) -> Option<Arch> {
|
pub fn arch(&self) -> Option<Arch> {
|
||||||
const IDENT_OPENRISC: [u8; EI_NIDENT] = [
|
const IDENT_OPENRISC: [u8; EI_NIDENT] = [
|
||||||
ELFMAG0,
|
ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3,
|
||||||
ELFMAG1,
|
ELFCLASS32, ELFDATA2MSB, EV_CURRENT, ELFOSABI_NONE,
|
||||||
ELFMAG2,
|
/* ABI version */ 0, /* padding */ 0, 0, 0, 0, 0, 0, 0
|
||||||
ELFMAG3,
|
|
||||||
ELFCLASS32,
|
|
||||||
ELFDATA2MSB,
|
|
||||||
EV_CURRENT,
|
|
||||||
ELFOSABI_NONE,
|
|
||||||
/* ABI version */ 0,
|
|
||||||
/* padding */ 0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
];
|
];
|
||||||
const IDENT_ARM: [u8; EI_NIDENT] = [
|
const IDENT_ARM: [u8; EI_NIDENT] = [
|
||||||
ELFMAG0,
|
ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3,
|
||||||
ELFMAG1,
|
ELFCLASS32, ELFDATA2LSB, EV_CURRENT, ELFOSABI_NONE,
|
||||||
ELFMAG2,
|
/* ABI version */ 0, /* padding */ 0, 0, 0, 0, 0, 0, 0
|
||||||
ELFMAG3,
|
|
||||||
ELFCLASS32,
|
|
||||||
ELFDATA2LSB,
|
|
||||||
EV_CURRENT,
|
|
||||||
ELFOSABI_NONE,
|
|
||||||
/* ABI version */ 0,
|
|
||||||
/* padding */ 0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
];
|
];
|
||||||
|
|
||||||
match (self.ehdr.e_ident, self.ehdr.e_machine) {
|
match (self.ehdr.e_ident, self.ehdr.e_machine) {
|
||||||
|
@ -74,14 +48,16 @@ impl<'a> File<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn program_headers<'b>(&'b self) -> impl Iterator<Item = Option<Elf32_Phdr>> + 'b {
|
pub fn program_headers<'b>(&'b self) -> impl Iterator<Item = Option<Elf32_Phdr>> + 'b
|
||||||
|
{
|
||||||
(0..self.ehdr.e_phnum).map(move |i| {
|
(0..self.ehdr.e_phnum).map(move |i| {
|
||||||
let phdr_off = self.ehdr.e_phoff as usize + mem::size_of::<Elf32_Phdr>() * i as usize;
|
let phdr_off = self.ehdr.e_phoff as usize + mem::size_of::<Elf32_Phdr>() * i as usize;
|
||||||
self.read_unaligned::<Elf32_Phdr>(phdr_off)
|
self.read_unaligned::<Elf32_Phdr>(phdr_off)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn section_headers<'b>(&'b self) -> impl Iterator<Item = Option<Elf32_Shdr>> + 'b {
|
pub fn section_headers<'b>(&'b self) -> impl Iterator<Item = Option<Elf32_Shdr>> + 'b
|
||||||
|
{
|
||||||
(0..self.ehdr.e_shnum).map(move |i| {
|
(0..self.ehdr.e_shnum).map(move |i| {
|
||||||
let shdr_off = self.ehdr.e_shoff as usize + mem::size_of::<Elf32_Shdr>() * i as usize;
|
let shdr_off = self.ehdr.e_shoff as usize + mem::size_of::<Elf32_Shdr>() * i as usize;
|
||||||
self.read_unaligned::<Elf32_Shdr>(shdr_off)
|
self.read_unaligned::<Elf32_Shdr>(shdr_off)
|
||||||
|
|
|
@ -1,9 +1,13 @@
|
||||||
|
use core::{
|
||||||
|
ops::{Deref, DerefMut, Range},
|
||||||
|
mem,
|
||||||
|
slice,
|
||||||
|
};
|
||||||
use alloc::alloc::{alloc_zeroed, dealloc, Layout, LayoutError};
|
use alloc::alloc::{alloc_zeroed, dealloc, Layout, LayoutError};
|
||||||
use core::{mem,
|
use super::{
|
||||||
ops::{Deref, DerefMut, Range},
|
elf::*,
|
||||||
slice};
|
Error,
|
||||||
|
};
|
||||||
use super::{elf::*, Error};
|
|
||||||
|
|
||||||
pub struct DynamicSection {
|
pub struct DynamicSection {
|
||||||
pub strtab: Range<usize>,
|
pub strtab: Range<usize>,
|
||||||
|
@ -30,12 +34,17 @@ impl Image {
|
||||||
slice::from_raw_parts_mut(ptr, size)
|
slice::from_raw_parts_mut(ptr, size)
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Image { layout, data })
|
Ok(Image {
|
||||||
|
layout,
|
||||||
|
data,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// assumes that self.data is properly aligned
|
/// assumes that self.data is properly aligned
|
||||||
pub(crate) fn get_ref<T>(&self, offset: usize) -> Option<&T>
|
pub(crate) fn get_ref<T>(&self, offset: usize) -> Option<&T>
|
||||||
where T: Copy {
|
where
|
||||||
|
T: Copy,
|
||||||
|
{
|
||||||
if self.data.len() < offset + mem::size_of::<T>() {
|
if self.data.len() < offset + mem::size_of::<T>() {
|
||||||
None
|
None
|
||||||
} else if (self.data.as_ptr() as usize + offset) & (mem::align_of::<T>() - 1) != 0 {
|
} else if (self.data.as_ptr() as usize + offset) & (mem::align_of::<T>() - 1) != 0 {
|
||||||
|
@ -57,53 +66,55 @@ impl Image {
|
||||||
unsafe { slice::from_raw_parts(ptr, len) }
|
unsafe { slice::from_raw_parts(ptr, len) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dyn_headers<'a>(&'a self, range: Range<usize>) -> impl Iterator<Item = &'a Elf32_Dyn> + 'a {
|
fn dyn_headers<'a>(&'a self, range: Range<usize>) ->
|
||||||
|
impl Iterator<Item = &'a Elf32_Dyn> + 'a
|
||||||
|
{
|
||||||
range
|
range
|
||||||
.step_by(mem::size_of::<Elf32_Dyn>())
|
.step_by(mem::size_of::<Elf32_Dyn>())
|
||||||
.filter_map(move |offset| self.get_ref::<Elf32_Dyn>(offset))
|
.filter_map(move |offset| {
|
||||||
|
self.get_ref::<Elf32_Dyn>(offset)
|
||||||
|
})
|
||||||
.take_while(|d| unsafe { d.d_un.d_val } as i32 != DT_NULL)
|
.take_while(|d| unsafe { d.d_un.d_val } as i32 != DT_NULL)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dyn_section(&self, range: Range<usize>) -> Result<DynamicSection, Error> {
|
pub fn dyn_section(&self, range: Range<usize>) -> Result<DynamicSection, Error> {
|
||||||
let (mut strtab_off, mut strtab_sz) = (0, 0);
|
let (mut strtab_off, mut strtab_sz) = (0, 0);
|
||||||
let (mut rel_off, mut rel_sz) = (0, 0);
|
let (mut rel_off, mut rel_sz) = (0, 0);
|
||||||
let (mut rela_off, mut rela_sz) = (0, 0);
|
let (mut rela_off, mut rela_sz) = (0, 0);
|
||||||
let (mut pltrel_off, mut pltrel_sz) = (0, 0);
|
let (mut pltrel_off, mut pltrel_sz) = (0, 0);
|
||||||
let (mut hash_off, mut hash_sz) = (0, 0);
|
let (mut hash_off, mut hash_sz) = (0, 0);
|
||||||
let mut symtab_off = 0;
|
let mut symtab_off = 0;
|
||||||
let mut sym_ent = 0;
|
let mut sym_ent = 0;
|
||||||
let mut rel_ent = 0;
|
let mut rel_ent = 0;
|
||||||
let mut rela_ent = 0;
|
let mut rela_ent = 0;
|
||||||
let mut nbucket = 0;
|
let mut nbucket = 0;
|
||||||
let mut nchain = 0;
|
let mut nchain = 0;
|
||||||
|
|
||||||
for dyn_header in self.dyn_headers(range) {
|
for dyn_header in self.dyn_headers(range) {
|
||||||
let val = unsafe { dyn_header.d_un.d_val } as usize;
|
let val = unsafe { dyn_header.d_un.d_val } as usize;
|
||||||
match dyn_header.d_tag {
|
match dyn_header.d_tag {
|
||||||
DT_NULL => break,
|
DT_NULL => break,
|
||||||
DT_STRTAB => strtab_off = val,
|
DT_STRTAB => strtab_off = val,
|
||||||
DT_STRSZ => strtab_sz = val,
|
DT_STRSZ => strtab_sz = val,
|
||||||
DT_SYMTAB => symtab_off = val,
|
DT_SYMTAB => symtab_off = val,
|
||||||
DT_SYMENT => sym_ent = val,
|
DT_SYMENT => sym_ent = val,
|
||||||
DT_REL => rel_off = val,
|
DT_REL => rel_off = val,
|
||||||
DT_RELSZ => rel_sz = val,
|
DT_RELSZ => rel_sz = val,
|
||||||
DT_RELENT => rel_ent = val,
|
DT_RELENT => rel_ent = val,
|
||||||
DT_RELA => rela_off = val,
|
DT_RELA => rela_off = val,
|
||||||
DT_RELASZ => rela_sz = val,
|
DT_RELASZ => rela_sz = val,
|
||||||
DT_RELAENT => rela_ent = val,
|
DT_RELAENT => rela_ent = val,
|
||||||
DT_JMPREL => pltrel_off = val,
|
DT_JMPREL => pltrel_off = val,
|
||||||
DT_PLTRELSZ => pltrel_sz = val,
|
DT_PLTRELSZ => pltrel_sz = val,
|
||||||
DT_HASH => {
|
DT_HASH => {
|
||||||
nbucket = *self
|
nbucket = *self.get_ref::<Elf32_Word>(val + 0)
|
||||||
.get_ref::<Elf32_Word>(val + 0)
|
|
||||||
.ok_or("cannot read hash bucket count")? as usize;
|
.ok_or("cannot read hash bucket count")? as usize;
|
||||||
nchain = *self
|
nchain = *self.get_ref::<Elf32_Word>(val + 4)
|
||||||
.get_ref::<Elf32_Word>(val + 4)
|
|
||||||
.ok_or("cannot read hash chain count")? as usize;
|
.ok_or("cannot read hash chain count")? as usize;
|
||||||
hash_off = val + 8;
|
hash_off = val + 8;
|
||||||
hash_sz = (nbucket + nchain) * mem::size_of::<Elf32_Word>();
|
hash_sz = (nbucket + nchain) * mem::size_of::<Elf32_Word>();
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => ()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,28 +123,28 @@ impl Image {
|
||||||
let symtab_sz = nchain * mem::size_of::<Elf32_Sym>();
|
let symtab_sz = nchain * mem::size_of::<Elf32_Sym>();
|
||||||
|
|
||||||
if strtab_off + strtab_sz > self.data.len() {
|
if strtab_off + strtab_sz > self.data.len() {
|
||||||
return Err("invalid strtab offset/size")?;
|
return Err("invalid strtab offset/size")?
|
||||||
}
|
}
|
||||||
if symtab_off + symtab_sz > self.data.len() {
|
if symtab_off + symtab_sz > self.data.len() {
|
||||||
return Err("invalid symtab offset/size")?;
|
return Err("invalid symtab offset/size")?
|
||||||
}
|
}
|
||||||
if sym_ent != mem::size_of::<Elf32_Sym>() {
|
if sym_ent != mem::size_of::<Elf32_Sym>() {
|
||||||
return Err("incorrect symbol entry size")?;
|
return Err("incorrect symbol entry size")?
|
||||||
}
|
}
|
||||||
if rel_off + rel_sz > self.data.len() {
|
if rel_off + rel_sz > self.data.len() {
|
||||||
return Err("invalid rel offset/size")?;
|
return Err("invalid rel offset/size")?
|
||||||
}
|
}
|
||||||
if rel_ent != 0 && rel_ent != mem::size_of::<Elf32_Rel>() {
|
if rel_ent != 0 && rel_ent != mem::size_of::<Elf32_Rel>() {
|
||||||
return Err("incorrect relocation entry size")?;
|
return Err("incorrect relocation entry size")?
|
||||||
}
|
}
|
||||||
if rela_off + rela_sz > self.data.len() {
|
if rela_off + rela_sz > self.data.len() {
|
||||||
return Err("invalid rela offset/size")?;
|
return Err("invalid rela offset/size")?
|
||||||
}
|
}
|
||||||
if rela_ent != 0 && rela_ent != mem::size_of::<Elf32_Rela>() {
|
if rela_ent != 0 && rela_ent != mem::size_of::<Elf32_Rela>() {
|
||||||
return Err("incorrect relocation entry size")?;
|
return Err("incorrect relocation entry size")?
|
||||||
}
|
}
|
||||||
if pltrel_off + pltrel_sz > self.data.len() {
|
if pltrel_off + pltrel_sz > self.data.len() {
|
||||||
return Err("invalid pltrel offset/size")?;
|
return Err("invalid pltrel offset/size")?
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(DynamicSection {
|
Ok(DynamicSection {
|
||||||
|
@ -154,7 +165,7 @@ impl Image {
|
||||||
|
|
||||||
pub fn write(&self, offset: usize, value: Elf32_Word) -> Result<(), Error> {
|
pub fn write(&self, offset: usize, value: Elf32_Word) -> Result<(), Error> {
|
||||||
if offset + mem::size_of::<Elf32_Addr>() > self.data.len() {
|
if offset + mem::size_of::<Elf32_Addr>() > self.data.len() {
|
||||||
return Err("relocation out of image bounds")?;
|
return Err("relocation out of image bounds")?
|
||||||
}
|
}
|
||||||
|
|
||||||
let ptr = (self.data.as_ptr() as usize + offset) as *mut Elf32_Addr;
|
let ptr = (self.data.as_ptr() as usize + offset) as *mut Elf32_Addr;
|
||||||
|
|
|
@ -1,14 +1,13 @@
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
extern crate libcortex_a9;
|
|
||||||
extern crate log;
|
extern crate log;
|
||||||
|
extern crate libcortex_a9;
|
||||||
|
|
||||||
use alloc::string::String;
|
|
||||||
use core::{convert, fmt, ops::Range, str};
|
use core::{convert, fmt, ops::Range, str};
|
||||||
|
use alloc::string::String;
|
||||||
use elf::*;
|
|
||||||
use log::{debug, trace};
|
use log::{debug, trace};
|
||||||
|
use elf::*;
|
||||||
|
|
||||||
pub mod elf;
|
pub mod elf;
|
||||||
mod file;
|
mod file;
|
||||||
|
@ -22,10 +21,11 @@ pub enum Arch {
|
||||||
OpenRisc,
|
OpenRisc,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
Parsing(&'static str),
|
Parsing(&'static str),
|
||||||
Lookup(String),
|
Lookup(String)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl convert::From<&'static str> for Error {
|
impl convert::From<&'static str> for Error {
|
||||||
|
@ -37,8 +37,10 @@ impl convert::From<&'static str> for Error {
|
||||||
impl fmt::Display for Error {
|
impl fmt::Display for Error {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
&Error::Parsing(desc) => write!(f, "parse error: {}", desc),
|
&Error::Parsing(desc) =>
|
||||||
&Error::Lookup(ref sym) => write!(f, "symbol lookup error: {}", sym),
|
write!(f, "parse error: {}", desc),
|
||||||
|
&Error::Lookup(ref sym) =>
|
||||||
|
write!(f, "symbol lookup error: {}", sym),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -101,22 +103,20 @@ impl Library {
|
||||||
let mut index = self.hash_bucket()[hash as usize % self.hash_bucket().len()] as usize;
|
let mut index = self.hash_bucket()[hash as usize % self.hash_bucket().len()] as usize;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
if index == STN_UNDEF {
|
if index == STN_UNDEF { return None }
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
let sym = &self.symtab()[index];
|
let sym = &self.symtab()[index];
|
||||||
let sym_name_off = sym.st_name as usize;
|
let sym_name_off = sym.st_name as usize;
|
||||||
match self.strtab().get(sym_name_off..sym_name_off + name.len()) {
|
match self.strtab().get(sym_name_off..sym_name_off + name.len()) {
|
||||||
Some(sym_name) if sym_name == name => {
|
Some(sym_name) if sym_name == name => {
|
||||||
if ELF32_ST_BIND(sym.st_info) & STB_GLOBAL == 0 {
|
if ELF32_ST_BIND(sym.st_info) & STB_GLOBAL == 0 {
|
||||||
return None;
|
return None
|
||||||
}
|
}
|
||||||
|
|
||||||
match sym.st_shndx {
|
match sym.st_shndx {
|
||||||
SHN_UNDEF => return None,
|
SHN_UNDEF => return None,
|
||||||
SHN_ABS => return Some(self.image.ptr() as u32 + sym.st_value),
|
SHN_ABS => return Some(self.image.ptr() as u32 + sym.st_value),
|
||||||
_ => return Some(self.image.ptr() as u32 + sym.st_value),
|
_ => return Some(self.image.ptr() as u32 + sym.st_value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
|
@ -127,16 +127,10 @@ impl Library {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn name_starting_at(&self, offset: usize) -> Result<&[u8], Error> {
|
pub fn name_starting_at(&self, offset: usize) -> Result<&[u8], Error> {
|
||||||
let size = self
|
let size = self.strtab().iter().skip(offset).position(|&x| x == 0)
|
||||||
.strtab()
|
.ok_or("symbol in symbol table not null-terminated")?;
|
||||||
.iter()
|
Ok(self.strtab().get(offset..offset + size)
|
||||||
.skip(offset)
|
.ok_or("cannot read symbol name")?)
|
||||||
.position(|&x| x == 0)
|
|
||||||
.ok_or("symbol in symbol table not null-terminated")?;
|
|
||||||
Ok(self
|
|
||||||
.strtab()
|
|
||||||
.get(offset..offset + size)
|
|
||||||
.ok_or("cannot read symbol name")?)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Rebind Rela by `name` to a new `addr`
|
/// Rebind Rela by `name` to a new `addr`
|
||||||
|
@ -149,59 +143,53 @@ impl Library {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load(data: &[u8], resolve: &dyn Fn(&[u8]) -> Option<Elf32_Word>) -> Result<Library, Error> {
|
pub fn load(
|
||||||
|
data: &[u8],
|
||||||
|
resolve: &dyn Fn(&[u8]) -> Option<Elf32_Word>
|
||||||
|
) -> Result<Library, Error> {
|
||||||
// validate ELF file
|
// validate ELF file
|
||||||
let file = file::File::new(data).ok_or("cannot read ELF header")?;
|
let file = file::File::new(data)
|
||||||
|
.ok_or("cannot read ELF header")?;
|
||||||
if file.ehdr.e_type != ET_DYN {
|
if file.ehdr.e_type != ET_DYN {
|
||||||
return Err("not a shared library")?;
|
return Err("not a shared library")?
|
||||||
}
|
}
|
||||||
let arch = file.arch().ok_or("not for a supported architecture")?;
|
let arch = file.arch()
|
||||||
|
.ok_or("not for a supported architecture")?;
|
||||||
|
|
||||||
// prepare target memory
|
// prepare target memory
|
||||||
let image_size = file
|
let image_size = file.program_headers()
|
||||||
.program_headers()
|
|
||||||
.filter_map(|phdr| phdr.map(|phdr| phdr.p_vaddr + phdr.p_memsz))
|
.filter_map(|phdr| phdr.map(|phdr| phdr.p_vaddr + phdr.p_memsz))
|
||||||
.max()
|
.max()
|
||||||
.unwrap_or(0) as usize;
|
.unwrap_or(0) as usize;
|
||||||
let image_align = file
|
let image_align = file.program_headers()
|
||||||
.program_headers()
|
.filter_map(|phdr| phdr.and_then(|phdr| {
|
||||||
.filter_map(|phdr| {
|
if phdr.p_type == PT_LOAD {
|
||||||
phdr.and_then(|phdr| {
|
Some(phdr.p_align)
|
||||||
if phdr.p_type == PT_LOAD {
|
} else {
|
||||||
Some(phdr.p_align)
|
None
|
||||||
} else {
|
}
|
||||||
None
|
}))
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.max()
|
.max()
|
||||||
.unwrap_or(4) as usize;
|
.unwrap_or(4) as usize;
|
||||||
// 1 image for all segments
|
// 1 image for all segments
|
||||||
let mut image = image::Image::new(image_size, image_align).map_err(|_| "cannot allocate target image")?;
|
let mut image = image::Image::new(image_size, image_align)
|
||||||
debug!(
|
.map_err(|_| "cannot allocate target image")?;
|
||||||
"ELF target: {} bytes, align to {:X}, allocated at {:08X}",
|
debug!("ELF target: {} bytes, align to {:X}, allocated at {:08X}", image_size, image_align, image.ptr() as usize);
|
||||||
image_size,
|
|
||||||
image_align,
|
|
||||||
image.ptr() as usize
|
|
||||||
);
|
|
||||||
|
|
||||||
// LOAD
|
// LOAD
|
||||||
for phdr in file.program_headers() {
|
for phdr in file.program_headers() {
|
||||||
let phdr = phdr.ok_or("cannot read program header")?;
|
let phdr = phdr.ok_or("cannot read program header")?;
|
||||||
trace!(
|
trace!("Program header: {:08X}+{:08X} to {:08X}",
|
||||||
"Program header: {:08X}+{:08X} to {:08X}",
|
phdr.p_offset, phdr.p_filesz,
|
||||||
phdr.p_offset,
|
image.ptr() as u32
|
||||||
phdr.p_filesz,
|
|
||||||
image.ptr() as u32
|
|
||||||
);
|
);
|
||||||
let file_range = phdr.p_offset as usize..(phdr.p_offset + phdr.p_filesz) as usize;
|
let file_range = phdr.p_offset as usize..(phdr.p_offset + phdr.p_filesz) as usize;
|
||||||
match phdr.p_type {
|
match phdr.p_type {
|
||||||
PT_LOAD => {
|
PT_LOAD => {
|
||||||
let src = file
|
let src = file.get(file_range)
|
||||||
.get(file_range)
|
|
||||||
.ok_or("program header requests an out of bounds load (in file)")?;
|
.ok_or("program header requests an out of bounds load (in file)")?;
|
||||||
let dst = image
|
let dst = image.get_mut(phdr.p_vaddr as usize..
|
||||||
.get_mut(phdr.p_vaddr as usize..(phdr.p_vaddr + phdr.p_filesz) as usize)
|
(phdr.p_vaddr + phdr.p_filesz) as usize)
|
||||||
.ok_or("program header requests an out of bounds load (in target)")?;
|
.ok_or("program header requests an out of bounds load (in target)")?;
|
||||||
dst.copy_from_slice(src);
|
dst.copy_from_slice(src);
|
||||||
}
|
}
|
||||||
|
@ -215,9 +203,9 @@ pub fn load(data: &[u8], resolve: &dyn Fn(&[u8]) -> Option<Elf32_Word>) -> Resul
|
||||||
let shdr = shdr.ok_or("cannot read section header")?;
|
let shdr = shdr.ok_or("cannot read section header")?;
|
||||||
match shdr.sh_type as usize {
|
match shdr.sh_type as usize {
|
||||||
SHT_ARM_EXIDX => {
|
SHT_ARM_EXIDX => {
|
||||||
let range = shdr.sh_addr as usize..(shdr.sh_addr + shdr.sh_size) as usize;
|
let range = shdr.sh_addr as usize..
|
||||||
let _ = image
|
(shdr.sh_addr + shdr.sh_size) as usize;
|
||||||
.get(range.clone())
|
let _ = image.get(range.clone())
|
||||||
.ok_or("section header specifies EXIDX outside of image (in target)")?;
|
.ok_or("section header specifies EXIDX outside of image (in target)")?;
|
||||||
exidx = Some(range);
|
exidx = Some(range);
|
||||||
}
|
}
|
||||||
|
@ -226,14 +214,11 @@ pub fn load(data: &[u8], resolve: &dyn Fn(&[u8]) -> Option<Elf32_Word>) -> Resul
|
||||||
}
|
}
|
||||||
|
|
||||||
// relocate DYNAMIC
|
// relocate DYNAMIC
|
||||||
let dyn_range = file.dyn_header_vaddr().ok_or("cannot find a dynamic header")?;
|
let dyn_range = file.dyn_header_vaddr()
|
||||||
|
.ok_or("cannot find a dynamic header")?;
|
||||||
let dyn_section = image.dyn_section(dyn_range.clone())?;
|
let dyn_section = image.dyn_section(dyn_range.clone())?;
|
||||||
debug!(
|
debug!("Relocating {} rela, {} rel, {} pltrel",
|
||||||
"Relocating {} rela, {} rel, {} pltrel",
|
dyn_section.rela.len(), dyn_section.rel.len(), dyn_section.pltrel.len());
|
||||||
dyn_section.rela.len(),
|
|
||||||
dyn_section.rel.len(),
|
|
||||||
dyn_section.pltrel.len()
|
|
||||||
);
|
|
||||||
let lib = Library {
|
let lib = Library {
|
||||||
arch,
|
arch,
|
||||||
image,
|
image,
|
||||||
|
|
|
@ -1,10 +1,16 @@
|
||||||
use alloc::string::String;
|
use alloc::string::String;
|
||||||
|
|
||||||
use libcortex_a9::{asm::{dsb, isb},
|
|
||||||
cache::{bpiall, dcci_slice, iciallu}};
|
|
||||||
use log::trace;
|
use log::trace;
|
||||||
|
use super::{
|
||||||
use super::{elf::*, image::Image, Arch, Error, Library};
|
Arch,
|
||||||
|
elf::*,
|
||||||
|
Error,
|
||||||
|
image::Image,
|
||||||
|
Library,
|
||||||
|
};
|
||||||
|
use libcortex_a9::{
|
||||||
|
cache::{dcci_slice, iciallu, bpiall},
|
||||||
|
asm::{dsb, isb},
|
||||||
|
};
|
||||||
|
|
||||||
pub trait Relocatable {
|
pub trait Relocatable {
|
||||||
fn offset(&self) -> usize;
|
fn offset(&self) -> usize;
|
||||||
|
@ -60,18 +66,25 @@ enum RelType {
|
||||||
impl RelType {
|
impl RelType {
|
||||||
pub fn new(arch: Arch, type_info: u8) -> Option<Self> {
|
pub fn new(arch: Arch, type_info: u8) -> Option<Self> {
|
||||||
match type_info {
|
match type_info {
|
||||||
R_OR1K_NONE if arch == Arch::OpenRisc => Some(RelType::None),
|
R_OR1K_NONE if arch == Arch::OpenRisc =>
|
||||||
R_ARM_NONE if arch == Arch::Arm => Some(RelType::None),
|
Some(RelType::None),
|
||||||
|
R_ARM_NONE if arch == Arch::Arm =>
|
||||||
|
Some(RelType::None),
|
||||||
|
|
||||||
R_OR1K_RELATIVE if arch == Arch::OpenRisc => Some(RelType::Relative),
|
R_OR1K_RELATIVE if arch == Arch::OpenRisc =>
|
||||||
R_ARM_RELATIVE if arch == Arch::Arm => Some(RelType::Relative),
|
Some(RelType::Relative),
|
||||||
|
R_ARM_RELATIVE if arch == Arch::Arm =>
|
||||||
|
Some(RelType::Relative),
|
||||||
|
|
||||||
R_OR1K_32 | R_OR1K_GLOB_DAT | R_OR1K_JMP_SLOT if arch == Arch::OpenRisc => Some(RelType::LookupAbs),
|
R_OR1K_32 | R_OR1K_GLOB_DAT | R_OR1K_JMP_SLOT
|
||||||
R_ARM_GLOB_DAT | R_ARM_JUMP_SLOT | R_ARM_ABS32 if arch == Arch::Arm => Some(RelType::LookupAbs),
|
if arch == Arch::OpenRisc => Some(RelType::LookupAbs),
|
||||||
|
R_ARM_GLOB_DAT | R_ARM_JUMP_SLOT | R_ARM_ABS32
|
||||||
|
if arch == Arch::Arm => Some(RelType::LookupAbs),
|
||||||
|
|
||||||
R_ARM_PREL31 if arch == Arch::Arm => Some(RelType::LookupRel),
|
R_ARM_PREL31 if arch == Arch::Arm => Some(RelType::LookupRel),
|
||||||
|
|
||||||
_ => None,
|
_ =>
|
||||||
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -83,25 +96,22 @@ fn format_sym_name(sym_name: &[u8]) -> String {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn relocate<R: Relocatable>(
|
pub fn relocate<R: Relocatable>(
|
||||||
arch: Arch,
|
arch: Arch, lib: &Library,
|
||||||
lib: &Library,
|
rel: &R, resolve: &dyn Fn(&[u8]) -> Option<Elf32_Word>
|
||||||
rel: &R,
|
|
||||||
resolve: &dyn Fn(&[u8]) -> Option<Elf32_Word>,
|
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let sym;
|
let sym;
|
||||||
if rel.sym_info() == 0 {
|
if rel.sym_info() == 0 {
|
||||||
sym = None;
|
sym = None;
|
||||||
} else {
|
} else {
|
||||||
sym = Some(
|
sym = Some(lib.symtab().get(rel.sym_info() as usize)
|
||||||
lib.symtab()
|
.ok_or("symbol out of bounds of symbol table")?)
|
||||||
.get(rel.sym_info() as usize)
|
|
||||||
.ok_or("symbol out of bounds of symbol table")?,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let rel_type = RelType::new(arch, rel.type_info()).ok_or("unsupported relocation type")?;
|
let rel_type = RelType::new(arch, rel.type_info())
|
||||||
|
.ok_or("unsupported relocation type")?;
|
||||||
let value = match rel_type {
|
let value = match rel_type {
|
||||||
RelType::None => return Ok(()),
|
RelType::None =>
|
||||||
|
return Ok(()),
|
||||||
|
|
||||||
RelType::Relative => {
|
RelType::Relative => {
|
||||||
let addend = rel.addend(&lib.image);
|
let addend = rel.addend(&lib.image);
|
||||||
|
@ -122,48 +132,42 @@ pub fn relocate<R: Relocatable>(
|
||||||
addr
|
addr
|
||||||
} else {
|
} else {
|
||||||
// We couldn't find it anywhere.
|
// We couldn't find it anywhere.
|
||||||
return Err(Error::Lookup(format_sym_name(sym_name)));
|
return Err(Error::Lookup(format_sym_name(sym_name)))
|
||||||
};
|
};
|
||||||
|
|
||||||
match rel_type {
|
match rel_type {
|
||||||
RelType::LookupAbs => sym_addr,
|
RelType::LookupAbs => sym_addr,
|
||||||
RelType::LookupRel => {
|
RelType::LookupRel =>
|
||||||
sym_addr.wrapping_sub(lib.image.ptr().wrapping_offset(rel.offset() as isize) as Elf32_Addr)
|
sym_addr.wrapping_sub(
|
||||||
}
|
lib.image.ptr().wrapping_offset(rel.offset() as isize) as Elf32_Addr),
|
||||||
_ => unreachable!(),
|
_ => unreachable!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
match rel.type_info() {
|
match rel.type_info() {
|
||||||
R_ARM_PREL31 => {
|
R_ARM_PREL31 => {
|
||||||
let reloc_word = lib
|
let reloc_word = lib.image.get_ref::<Elf32_Word>(rel.offset())
|
||||||
.image
|
.ok_or("relocation offset cannot be read")?;
|
||||||
.get_ref::<Elf32_Word>(rel.offset())
|
lib.image.write(rel.offset(), (reloc_word & 0x80000000) | (value & 0x7FFFFFFF))
|
||||||
.ok_or("relocation offset cannot be read")?;
|
},
|
||||||
lib.image
|
|
||||||
.write(rel.offset(), (reloc_word & 0x80000000) | (value & 0x7FFFFFFF))
|
|
||||||
}
|
|
||||||
|
|
||||||
_ => lib.image.write(rel.offset(), value),
|
_ => lib.image.write(rel.offset(), value),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn rebind(arch: Arch, lib: &Library, name: &[u8], value: Elf32_Word) -> Result<(), Error> {
|
pub fn rebind(
|
||||||
|
arch: Arch, lib: &Library, name: &[u8], value: Elf32_Word
|
||||||
|
) -> Result<(), Error> {
|
||||||
fn rebind_symbol_to_value<R: Relocatable>(
|
fn rebind_symbol_to_value<R: Relocatable>(
|
||||||
arch: Arch,
|
arch: Arch, lib: &Library,name: &[u8], value: Elf32_Word, relocs: &[R]
|
||||||
lib: &Library,
|
|
||||||
name: &[u8],
|
|
||||||
value: Elf32_Word,
|
|
||||||
relocs: &[R],
|
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
for reloc in relocs {
|
for reloc in relocs {
|
||||||
let rel_type = RelType::new(arch, reloc.type_info()).ok_or("unsupported relocation type")?;
|
let rel_type = RelType::new(arch, reloc.type_info())
|
||||||
|
.ok_or("unsupported relocation type")?;
|
||||||
match rel_type {
|
match rel_type {
|
||||||
RelType::LookupAbs => {
|
RelType::LookupAbs => {
|
||||||
let sym = lib
|
let sym = lib.symtab().get(reloc.sym_info() as usize)
|
||||||
.symtab()
|
|
||||||
.get(reloc.sym_info() as usize)
|
|
||||||
.ok_or("symbol out of bounds of symbol table")?;
|
.ok_or("symbol out of bounds of symbol table")?;
|
||||||
let sym_name = lib.name_starting_at(sym.st_name as usize)?;
|
let sym_name = lib.name_starting_at(sym.st_name as usize)?;
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
use core_io::{Error as IoError, Read, Write};
|
use core_io::{Read, Write, Error as IoError};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Cursor<T> {
|
pub struct Cursor<T> {
|
||||||
inner: T,
|
inner: T,
|
||||||
pos: usize,
|
pos: usize
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Cursor<T> {
|
impl<T> Cursor<T> {
|
||||||
|
@ -39,6 +39,7 @@ impl<T> Cursor<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: AsRef<[u8]>> Read for Cursor<T> {
|
impl<T: AsRef<[u8]>> Read for Cursor<T> {
|
||||||
|
|
||||||
fn read(&mut self, buf: &mut [u8]) -> Result<usize, IoError> {
|
fn read(&mut self, buf: &mut [u8]) -> Result<usize, IoError> {
|
||||||
let data = &self.inner.as_ref()[self.pos..];
|
let data = &self.inner.as_ref()[self.pos..];
|
||||||
let len = buf.len().min(data.len());
|
let len = buf.len().min(data.len());
|
||||||
|
@ -49,9 +50,10 @@ impl<T: AsRef<[u8]>> Read for Cursor<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Write for Cursor<&mut [u8]> {
|
impl Write for Cursor<&mut [u8]> {
|
||||||
|
|
||||||
fn write(&mut self, buf: &[u8]) -> Result<usize, IoError> {
|
fn write(&mut self, buf: &[u8]) -> Result<usize, IoError> {
|
||||||
let data = &mut self.inner[self.pos..];
|
let data = &mut self.inner[self.pos..];
|
||||||
let len = buf.len().min(data.len());
|
let len = buf.len().min(data.len());
|
||||||
data[..len].copy_from_slice(&buf[..len]);
|
data[..len].copy_from_slice(&buf[..len]);
|
||||||
self.pos += len;
|
self.pos += len;
|
||||||
Ok(len)
|
Ok(len)
|
||||||
|
@ -65,6 +67,7 @@ impl Write for Cursor<&mut [u8]> {
|
||||||
|
|
||||||
#[cfg(feature = "alloc")]
|
#[cfg(feature = "alloc")]
|
||||||
impl Write for Cursor<::alloc::Vec<u8>> {
|
impl Write for Cursor<::alloc::Vec<u8>> {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn write(&mut self, buf: &[u8]) -> Result<usize, IoError> {
|
fn write(&mut self, buf: &[u8]) -> Result<usize, IoError> {
|
||||||
self.inner.extend_from_slice(buf);
|
self.inner.extend_from_slice(buf);
|
||||||
|
|
|
@ -16,7 +16,7 @@ pub mod cursor;
|
||||||
pub mod proto;
|
pub mod proto;
|
||||||
|
|
||||||
pub use cursor::Cursor;
|
pub use cursor::Cursor;
|
||||||
#[cfg(all(feature = "byteorder", feature = "alloc"))]
|
|
||||||
pub use proto::ReadStringError;
|
|
||||||
#[cfg(feature = "byteorder")]
|
#[cfg(feature = "byteorder")]
|
||||||
pub use proto::{ProtoRead, ProtoWrite};
|
pub use proto::{ProtoRead, ProtoWrite};
|
||||||
|
#[cfg(all(feature = "byteorder", feature = "alloc"))]
|
||||||
|
pub use proto::ReadStringError;
|
|
@ -1,14 +1,15 @@
|
||||||
use alloc::{string::String, vec};
|
|
||||||
use core::str::Utf8Error;
|
use core::str::Utf8Error;
|
||||||
|
|
||||||
use byteorder::{ByteOrder, NativeEndian};
|
use byteorder::{ByteOrder, NativeEndian};
|
||||||
use core_io::{Error as IoError, Read, Write};
|
use alloc::vec;
|
||||||
|
use alloc::string::String;
|
||||||
|
|
||||||
|
use core_io::{Read, Write, Error as IoError};
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub enum ReadStringError<T> {
|
pub enum ReadStringError<T> {
|
||||||
Utf8(Utf8Error),
|
Utf8(Utf8Error),
|
||||||
Other(T),
|
Other(T)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ProtoRead {
|
pub trait ProtoRead {
|
||||||
|
@ -140,9 +141,7 @@ pub trait ProtoWrite {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> ProtoRead for T
|
impl<T> ProtoRead for T where T: Read + ?Sized {
|
||||||
where T: Read + ?Sized
|
|
||||||
{
|
|
||||||
type ReadError = IoError;
|
type ReadError = IoError;
|
||||||
|
|
||||||
fn read_exact(&mut self, buf: &mut [u8]) -> Result<(), Self::ReadError> {
|
fn read_exact(&mut self, buf: &mut [u8]) -> Result<(), Self::ReadError> {
|
||||||
|
@ -150,9 +149,7 @@ where T: Read + ?Sized
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> ProtoWrite for T
|
impl<T> ProtoWrite for T where T: Write + ?Sized {
|
||||||
where T: Write + ?Sized
|
|
||||||
{
|
|
||||||
type WriteError = IoError;
|
type WriteError = IoError;
|
||||||
|
|
||||||
fn write_all(&mut self, buf: &[u8]) -> Result<(), Self::WriteError> {
|
fn write_all(&mut self, buf: &[u8]) -> Result<(), Self::WriteError> {
|
||||||
|
|
|
@ -1,25 +1,27 @@
|
||||||
use libc::{c_int, c_void};
|
use libc::{c_void, c_int};
|
||||||
|
|
||||||
use crate::libunwind as uw;
|
use crate::libunwind as uw;
|
||||||
|
|
||||||
const UW_REG_SP: c_int = 13;
|
const UW_REG_SP: c_int = 13;
|
||||||
|
|
||||||
pub fn backtrace<F>(f: F) -> Result<(), uw::_Unwind_Reason_Code>
|
pub fn backtrace<F>(f: F) -> Result<(), uw::_Unwind_Reason_Code>
|
||||||
where F: FnMut(usize) -> () {
|
where F: FnMut(usize) -> ()
|
||||||
|
{
|
||||||
struct TraceContext<F> {
|
struct TraceContext<F> {
|
||||||
step_fn: F,
|
step_fn: F,
|
||||||
prev_sp: uw::_Unwind_Word,
|
prev_sp: uw::_Unwind_Word
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" fn trace<F>(context: *mut uw::_Unwind_Context, arg: *mut c_void) -> uw::_Unwind_Reason_Code
|
extern fn trace<F>(context: *mut uw::_Unwind_Context, arg: *mut c_void)
|
||||||
where F: FnMut(usize) -> () {
|
-> uw::_Unwind_Reason_Code
|
||||||
|
where F: FnMut(usize) -> ()
|
||||||
|
{
|
||||||
unsafe {
|
unsafe {
|
||||||
let trace_context = &mut *(arg as *mut TraceContext<F>);
|
let trace_context = &mut *(arg as *mut TraceContext<F>);
|
||||||
|
|
||||||
// Detect the root of a libfringe thread
|
// Detect the root of a libfringe thread
|
||||||
let cur_sp = uw::_Unwind_GetGR(context, UW_REG_SP);
|
let cur_sp = uw::_Unwind_GetGR(context, UW_REG_SP);
|
||||||
if cur_sp == trace_context.prev_sp {
|
if cur_sp == trace_context.prev_sp {
|
||||||
return uw::_URC_END_OF_STACK;
|
return uw::_URC_END_OF_STACK
|
||||||
} else {
|
} else {
|
||||||
trace_context.prev_sp = cur_sp;
|
trace_context.prev_sp = cur_sp;
|
||||||
}
|
}
|
||||||
|
@ -33,7 +35,7 @@ where F: FnMut(usize) -> () {
|
||||||
let mut trace_context = TraceContext { step_fn: f, prev_sp: 0 };
|
let mut trace_context = TraceContext { step_fn: f, prev_sp: 0 };
|
||||||
match uw::_Unwind_Backtrace(trace::<F>, &mut trace_context as *mut _ as *mut c_void) {
|
match uw::_Unwind_Backtrace(trace::<F>, &mut trace_context as *mut _ as *mut c_void) {
|
||||||
uw::_URC_NO_REASON => Ok(()),
|
uw::_URC_NO_REASON => Ok(()),
|
||||||
err => Err(err),
|
err => Err(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,8 @@ fn main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
mod llvm_libunwind {
|
mod llvm_libunwind {
|
||||||
use std::{env, path::Path};
|
use std::path::Path;
|
||||||
|
use std::env;
|
||||||
|
|
||||||
fn setup_options(cfg: &mut cc::Build) {
|
fn setup_options(cfg: &mut cc::Build) {
|
||||||
cfg.no_default_flags(true);
|
cfg.no_default_flags(true);
|
||||||
|
@ -81,7 +82,11 @@ mod llvm_libunwind {
|
||||||
cfg.flag("-fvisibility=hidden");
|
cfg.flag("-fvisibility=hidden");
|
||||||
cfg.flag_if_supported("-fvisibility-global-new-delete-hidden");
|
cfg.flag_if_supported("-fvisibility-global-new-delete-hidden");
|
||||||
|
|
||||||
let unwind_sources = vec!["Unwind-EHABI.cpp", "Unwind-seh.cpp", "libunwind.cpp"];
|
let unwind_sources = vec![
|
||||||
|
"Unwind-EHABI.cpp",
|
||||||
|
"Unwind-seh.cpp",
|
||||||
|
"libunwind.cpp"
|
||||||
|
];
|
||||||
|
|
||||||
let root = Path::new("../llvm_libunwind");
|
let root = Path::new("../llvm_libunwind");
|
||||||
cfg.include(root.join("include"));
|
cfg.include(root.join("include"));
|
||||||
|
|
|
@ -21,7 +21,8 @@ pub use _Unwind_Reason_Code::*;
|
||||||
pub type _Unwind_Exception_Class = u64;
|
pub type _Unwind_Exception_Class = u64;
|
||||||
pub type _Unwind_Word = uintptr_t;
|
pub type _Unwind_Word = uintptr_t;
|
||||||
pub type _Unwind_Ptr = uintptr_t;
|
pub type _Unwind_Ptr = uintptr_t;
|
||||||
pub type _Unwind_Trace_Fn = extern "C" fn(ctx: *mut _Unwind_Context, arg: *mut c_void) -> _Unwind_Reason_Code;
|
pub type _Unwind_Trace_Fn =
|
||||||
|
extern "C" fn(ctx: *mut _Unwind_Context, arg: *mut c_void) -> _Unwind_Reason_Code;
|
||||||
|
|
||||||
#[cfg(target_arch = "x86")]
|
#[cfg(target_arch = "x86")]
|
||||||
pub const unwinder_private_data_size: usize = 5;
|
pub const unwinder_private_data_size: usize = 5;
|
||||||
|
@ -278,6 +279,7 @@ if #[cfg(all(windows, target_arch = "x86_64", target_env = "gnu"))] {
|
||||||
} // cfg_if!
|
} // cfg_if!
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
extern "C" fn abort() {
|
extern fn abort() {
|
||||||
panic!("Abort!");
|
panic!("Abort!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,8 @@ use libboard_zynq::smoltcp::Error;
|
||||||
use libcortex_a9::cache;
|
use libcortex_a9::cache;
|
||||||
use log::{debug, info, warn};
|
use log::{debug, info, warn};
|
||||||
|
|
||||||
use crate::{pl, proto_async::*};
|
use crate::proto_async::*;
|
||||||
|
use crate::pl;
|
||||||
|
|
||||||
const BUFFER_SIZE: usize = 512 * 1024;
|
const BUFFER_SIZE: usize = 512 * 1024;
|
||||||
|
|
||||||
|
@ -12,7 +13,9 @@ struct Buffer {
|
||||||
data: [u8; BUFFER_SIZE],
|
data: [u8; BUFFER_SIZE],
|
||||||
}
|
}
|
||||||
|
|
||||||
static mut BUFFER: Buffer = Buffer { data: [0; BUFFER_SIZE] };
|
static mut BUFFER: Buffer = Buffer {
|
||||||
|
data: [0; BUFFER_SIZE]
|
||||||
|
};
|
||||||
|
|
||||||
fn arm() {
|
fn arm() {
|
||||||
debug!("arming RTIO analyzer");
|
debug!("arming RTIO analyzer");
|
||||||
|
@ -43,7 +46,7 @@ struct Header {
|
||||||
total_byte_count: u64,
|
total_byte_count: u64,
|
||||||
error_occurred: bool,
|
error_occurred: bool,
|
||||||
log_channel: u8,
|
log_channel: u8,
|
||||||
dds_onehot_sel: bool,
|
dds_onehot_sel: bool
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn write_header(stream: &mut TcpStream, header: &Header) -> Result<(), Error> {
|
async fn write_header(stream: &mut TcpStream, header: &Header) -> Result<(), Error> {
|
||||||
|
@ -75,14 +78,10 @@ async fn handle_connection(stream: &mut TcpStream) -> Result<(), Error> {
|
||||||
|
|
||||||
let header = Header {
|
let header = Header {
|
||||||
total_byte_count: total_byte_count,
|
total_byte_count: total_byte_count,
|
||||||
sent_bytes: if wraparound {
|
sent_bytes: if wraparound { BUFFER_SIZE as u32 } else { total_byte_count as u32 },
|
||||||
BUFFER_SIZE as u32
|
|
||||||
} else {
|
|
||||||
total_byte_count as u32
|
|
||||||
},
|
|
||||||
error_occurred: overflow_occurred | bus_error_occurred,
|
error_occurred: overflow_occurred | bus_error_occurred,
|
||||||
log_channel: pl::csr::CONFIG_RTIO_LOG_CHANNEL as u8,
|
log_channel: pl::csr::CONFIG_RTIO_LOG_CHANNEL as u8,
|
||||||
dds_onehot_sel: true, // kept for backward compatibility of analyzer dumps
|
dds_onehot_sel: true // kept for backward compatibility of analyzer dumps
|
||||||
};
|
};
|
||||||
debug!("{:?}", header);
|
debug!("{:?}", header);
|
||||||
|
|
||||||
|
|
|
@ -1,33 +1,37 @@
|
||||||
use alloc::{collections::BTreeMap, rc::Rc, string::String, vec, vec::Vec};
|
use core::fmt;
|
||||||
use core::{cell::RefCell, fmt, slice, str};
|
use core::cell::RefCell;
|
||||||
|
use alloc::{vec, vec::Vec, string::String, collections::BTreeMap, rc::Rc};
|
||||||
|
use log::{info, warn, error};
|
||||||
use cslice::CSlice;
|
use cslice::CSlice;
|
||||||
use futures::{future::FutureExt, select_biased};
|
|
||||||
use libasync::{smoltcp::{Sockets, TcpStream},
|
|
||||||
task};
|
|
||||||
use libboard_artiq::drtio_routing;
|
|
||||||
#[cfg(feature = "target_kasli_soc")]
|
|
||||||
use libboard_zynq::error_led::ErrorLED;
|
|
||||||
use libboard_zynq::{self as zynq,
|
|
||||||
smoltcp::{self,
|
|
||||||
iface::{EthernetInterfaceBuilder, NeighborCache},
|
|
||||||
time::Instant,
|
|
||||||
wire::IpCidr},
|
|
||||||
timer::GlobalTimer};
|
|
||||||
use libconfig::{net_settings, Config};
|
|
||||||
use libcortex_a9::{mutex::Mutex,
|
|
||||||
semaphore::Semaphore,
|
|
||||||
sync_channel::{Receiver, Sender}};
|
|
||||||
use log::{error, info, warn};
|
|
||||||
use num_derive::{FromPrimitive, ToPrimitive};
|
use num_derive::{FromPrimitive, ToPrimitive};
|
||||||
use num_traits::{FromPrimitive, ToPrimitive};
|
use num_traits::{FromPrimitive, ToPrimitive};
|
||||||
|
|
||||||
|
use libboard_zynq::{
|
||||||
|
self as zynq,
|
||||||
|
smoltcp::{
|
||||||
|
self,
|
||||||
|
wire::IpCidr,
|
||||||
|
iface::{NeighborCache, EthernetInterfaceBuilder},
|
||||||
|
time::Instant,
|
||||||
|
},
|
||||||
|
timer::GlobalTimer,
|
||||||
|
};
|
||||||
|
use libcortex_a9::{semaphore::Semaphore, mutex::Mutex, sync_channel::{Sender, Receiver}};
|
||||||
|
use futures::{select_biased, future::FutureExt};
|
||||||
|
use libasync::{smoltcp::{Sockets, TcpStream}, task};
|
||||||
|
use libconfig::{Config, net_settings};
|
||||||
|
use libboard_artiq::drtio_routing;
|
||||||
|
|
||||||
|
use crate::proto_async::*;
|
||||||
|
use crate::kernel;
|
||||||
|
use crate::rpc;
|
||||||
|
use crate::moninj;
|
||||||
|
use crate::mgmt;
|
||||||
|
use crate::analyzer;
|
||||||
|
use crate::rtio_mgt;
|
||||||
#[cfg(has_drtio)]
|
#[cfg(has_drtio)]
|
||||||
use crate::pl;
|
use crate::pl;
|
||||||
use crate::{analyzer, kernel, mgmt, moninj,
|
|
||||||
proto_async::*,
|
|
||||||
rpc, rtio_dma,
|
|
||||||
rtio_mgt::{self, resolve_channel_name}};
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
|
@ -43,9 +47,9 @@ impl fmt::Display for Error {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Error::NetworkError(error) => write!(f, "network error: {}", error),
|
Error::NetworkError(error) => write!(f, "network error: {}", error),
|
||||||
Error::UnexpectedPattern => write!(f, "unexpected pattern"),
|
Error::UnexpectedPattern => write!(f, "unexpected pattern"),
|
||||||
Error::UnrecognizedPacket => write!(f, "unrecognized packet"),
|
Error::UnrecognizedPacket => write!(f, "unrecognized packet"),
|
||||||
Error::BufferExhausted => write!(f, "buffer exhausted"),
|
Error::BufferExhausted => write!(f, "buffer exhausted"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -79,18 +83,18 @@ enum Reply {
|
||||||
}
|
}
|
||||||
|
|
||||||
static CACHE_STORE: Mutex<BTreeMap<String, Vec<i32>>> = Mutex::new(BTreeMap::new());
|
static CACHE_STORE: Mutex<BTreeMap<String, Vec<i32>>> = Mutex::new(BTreeMap::new());
|
||||||
|
static DMA_RECORD_STORE: Mutex<BTreeMap<String, (Vec<u8>, i64)>> = Mutex::new(BTreeMap::new());
|
||||||
|
|
||||||
async fn write_header(stream: &TcpStream, reply: Reply) -> Result<()> {
|
async fn write_header(stream: &TcpStream, reply: Reply) -> Result<()> {
|
||||||
stream
|
stream.send_slice(&[0x5a, 0x5a, 0x5a, 0x5a, reply.to_u8().unwrap()]).await?;
|
||||||
.send_slice(&[0x5a, 0x5a, 0x5a, 0x5a, reply.to_u8().unwrap()])
|
|
||||||
.await?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn read_request(stream: &TcpStream, allow_close: bool) -> Result<Option<Request>> {
|
async fn read_request(stream: &TcpStream, allow_close: bool) -> Result<Option<Request>> {
|
||||||
match expect(stream, &[0x5a, 0x5a, 0x5a, 0x5a]).await {
|
match expect(stream, &[0x5a, 0x5a, 0x5a, 0x5a]).await {
|
||||||
Ok(true) => {}
|
Ok(true) => {}
|
||||||
Ok(false) => return Err(Error::UnexpectedPattern),
|
Ok(false) =>
|
||||||
|
return Err(Error::UnexpectedPattern),
|
||||||
Err(smoltcp::Error::Finished) => {
|
Err(smoltcp::Error::Finished) => {
|
||||||
if allow_close {
|
if allow_close {
|
||||||
info!("peer closed connection");
|
info!("peer closed connection");
|
||||||
|
@ -99,12 +103,11 @@ async fn read_request(stream: &TcpStream, allow_close: bool) -> Result<Option<Re
|
||||||
error!("peer unexpectedly closed connection");
|
error!("peer unexpectedly closed connection");
|
||||||
return Err(smoltcp::Error::Finished)?;
|
return Err(smoltcp::Error::Finished)?;
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
Err(e) => return Err(e)?,
|
Err(e) =>
|
||||||
|
return Err(e)?,
|
||||||
}
|
}
|
||||||
Ok(Some(
|
Ok(Some(FromPrimitive::from_i8(read_i8(&stream).await?).ok_or(Error::UnrecognizedPacket)?))
|
||||||
FromPrimitive::from_i8(read_i8(&stream).await?).ok_or(Error::UnrecognizedPacket)?,
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn read_bytes(stream: &TcpStream, max_length: usize) -> Result<Vec<u8>> {
|
async fn read_bytes(stream: &TcpStream, max_length: usize) -> Result<Vec<u8>> {
|
||||||
|
@ -123,7 +126,9 @@ async fn fast_send(sender: &mut Sender<'_, kernel::Message>, content: kernel::Me
|
||||||
let mut content = content;
|
let mut content = content;
|
||||||
for _ in 0..RETRY_LIMIT {
|
for _ in 0..RETRY_LIMIT {
|
||||||
match sender.try_send(content) {
|
match sender.try_send(content) {
|
||||||
Ok(()) => return,
|
Ok(()) => {
|
||||||
|
return
|
||||||
|
},
|
||||||
Err(v) => {
|
Err(v) => {
|
||||||
content = v;
|
content = v;
|
||||||
}
|
}
|
||||||
|
@ -135,8 +140,10 @@ async fn fast_send(sender: &mut Sender<'_, kernel::Message>, content: kernel::Me
|
||||||
async fn fast_recv(receiver: &mut Receiver<'_, kernel::Message>) -> kernel::Message {
|
async fn fast_recv(receiver: &mut Receiver<'_, kernel::Message>) -> kernel::Message {
|
||||||
for _ in 0..RETRY_LIMIT {
|
for _ in 0..RETRY_LIMIT {
|
||||||
match receiver.try_recv() {
|
match receiver.try_recv() {
|
||||||
Ok(v) => return v,
|
Ok(v) => {
|
||||||
Err(()) => (),
|
return v;
|
||||||
|
},
|
||||||
|
Err(()) => ()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
receiver.async_recv().await
|
receiver.async_recv().await
|
||||||
|
@ -152,14 +159,7 @@ async fn write_exception_string(stream: &TcpStream, s: CSlice<'static, u8>) -> R
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_run_kernel(
|
async fn handle_run_kernel(stream: Option<&TcpStream>, control: &Rc<RefCell<kernel::Control>>, _up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>) -> Result<()> {
|
||||||
stream: Option<&TcpStream>,
|
|
||||||
control: &Rc<RefCell<kernel::Control>>,
|
|
||||||
_up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>,
|
|
||||||
aux_mutex: &Rc<Mutex<bool>>,
|
|
||||||
routing_table: &drtio_routing::RoutingTable,
|
|
||||||
timer: GlobalTimer,
|
|
||||||
) -> Result<()> {
|
|
||||||
control.borrow_mut().tx.async_send(kernel::Message::StartRequest).await;
|
control.borrow_mut().tx.async_send(kernel::Message::StartRequest).await;
|
||||||
loop {
|
loop {
|
||||||
let reply = control.borrow_mut().rx.async_recv().await;
|
let reply = control.borrow_mut().rx.async_recv().await;
|
||||||
|
@ -167,7 +167,7 @@ async fn handle_run_kernel(
|
||||||
kernel::Message::RpcSend { is_async, data } => {
|
kernel::Message::RpcSend { is_async, data } => {
|
||||||
if stream.is_none() {
|
if stream.is_none() {
|
||||||
error!("Unexpected RPC from startup/idle kernel!");
|
error!("Unexpected RPC from startup/idle kernel!");
|
||||||
break;
|
break
|
||||||
}
|
}
|
||||||
let stream = stream.unwrap();
|
let stream = stream.unwrap();
|
||||||
write_header(stream, Reply::RPCRequest).await?;
|
write_header(stream, Reply::RPCRequest).await?;
|
||||||
|
@ -194,64 +194,46 @@ async fn handle_run_kernel(
|
||||||
fast_send(&mut control.tx, kernel::Message::RpcRecvReply(Ok(size))).await;
|
fast_send(&mut control.tx, kernel::Message::RpcRecvReply(Ok(size))).await;
|
||||||
match fast_recv(&mut control.rx).await {
|
match fast_recv(&mut control.rx).await {
|
||||||
kernel::Message::RpcRecvRequest(slot) => slot,
|
kernel::Message::RpcRecvRequest(slot) => slot,
|
||||||
other => {
|
other => panic!("expected nested value slot from kernel CPU, not {:?}", other),
|
||||||
panic!("expected nested value slot from kernel CPU, not {:?}", other)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
}).await?;
|
||||||
.await?;
|
control.borrow_mut().tx.async_send(kernel::Message::RpcRecvReply(Ok(0))).await;
|
||||||
control
|
},
|
||||||
.borrow_mut()
|
|
||||||
.tx
|
|
||||||
.async_send(kernel::Message::RpcRecvReply(Ok(0)))
|
|
||||||
.await;
|
|
||||||
}
|
|
||||||
Request::RPCException => {
|
Request::RPCException => {
|
||||||
let mut control = control.borrow_mut();
|
let mut control = control.borrow_mut();
|
||||||
match control.rx.async_recv().await {
|
match control.rx.async_recv().await {
|
||||||
kernel::Message::RpcRecvRequest(_) => (),
|
kernel::Message::RpcRecvRequest(_) => (),
|
||||||
other => panic!("expected (ignored) root value slot from kernel CPU, not {:?}", other),
|
other => panic!("expected (ignored) root value slot from kernel CPU, not {:?}", other),
|
||||||
}
|
}
|
||||||
let id = read_i32(stream).await? as u32;
|
let id = read_i32(stream).await? as u32;
|
||||||
let message = read_i32(stream).await? as u32;
|
let message = read_i32(stream).await? as u32;
|
||||||
let param = [
|
let param = [read_i64(stream).await?,
|
||||||
read_i64(stream).await?,
|
read_i64(stream).await?,
|
||||||
read_i64(stream).await?,
|
read_i64(stream).await?];
|
||||||
read_i64(stream).await?,
|
let file = read_i32(stream).await? as u32;
|
||||||
];
|
let line = read_i32(stream).await?;
|
||||||
let file = read_i32(stream).await? as u32;
|
let column = read_i32(stream).await?;
|
||||||
let line = read_i32(stream).await?;
|
|
||||||
let column = read_i32(stream).await?;
|
|
||||||
let function = read_i32(stream).await? as u32;
|
let function = read_i32(stream).await? as u32;
|
||||||
control
|
control.tx.async_send(kernel::Message::RpcRecvReply(Err(kernel::RPCException {
|
||||||
.tx
|
id, message, param, file, line, column, function
|
||||||
.async_send(kernel::Message::RpcRecvReply(Err(kernel::RPCException {
|
}))).await;
|
||||||
id,
|
},
|
||||||
message,
|
|
||||||
param,
|
|
||||||
file,
|
|
||||||
line,
|
|
||||||
column,
|
|
||||||
function,
|
|
||||||
})))
|
|
||||||
.await;
|
|
||||||
}
|
|
||||||
_ => {
|
_ => {
|
||||||
error!("unexpected RPC request from host: {:?}", host_request);
|
error!("unexpected RPC request from host: {:?}", host_request);
|
||||||
return Err(Error::UnrecognizedPacket);
|
return Err(Error::UnrecognizedPacket)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
kernel::Message::KernelFinished(async_errors) => {
|
kernel::Message::KernelFinished(async_errors) => {
|
||||||
if let Some(stream) = stream {
|
if let Some(stream) = stream {
|
||||||
write_header(stream, Reply::KernelFinished).await?;
|
write_header(stream, Reply::KernelFinished).await?;
|
||||||
write_i8(stream, async_errors as i8).await?;
|
write_i8(stream, async_errors as i8).await?;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
},
|
||||||
kernel::Message::KernelException(exceptions, stack_pointers, backtrace, async_errors) => {
|
kernel::Message::KernelException(exceptions, stack_pointers, backtrace, async_errors) => {
|
||||||
match stream {
|
match stream {
|
||||||
Some(stream) => {
|
Some(stream) => {
|
||||||
|
@ -262,26 +244,7 @@ async fn handle_run_kernel(
|
||||||
for exception in exceptions.iter() {
|
for exception in exceptions.iter() {
|
||||||
let exception = exception.as_ref().unwrap();
|
let exception = exception.as_ref().unwrap();
|
||||||
write_i32(stream, exception.id as i32).await?;
|
write_i32(stream, exception.id as i32).await?;
|
||||||
|
write_exception_string(stream, exception.message).await?;
|
||||||
if exception.message.len() == usize::MAX {
|
|
||||||
// exception with host string
|
|
||||||
write_exception_string(stream, exception.message).await?;
|
|
||||||
} else {
|
|
||||||
let msg = str::from_utf8(unsafe {
|
|
||||||
slice::from_raw_parts(exception.message.as_ptr(), exception.message.len())
|
|
||||||
})
|
|
||||||
.unwrap()
|
|
||||||
.replace(
|
|
||||||
"{rtio_channel_info:0}",
|
|
||||||
&format!(
|
|
||||||
"0x{:04x}:{}",
|
|
||||||
exception.param[0],
|
|
||||||
resolve_channel_name(exception.param[0] as u32)
|
|
||||||
),
|
|
||||||
);
|
|
||||||
write_exception_string(stream, unsafe { CSlice::new(msg.as_ptr(), msg.len()) }).await?;
|
|
||||||
}
|
|
||||||
|
|
||||||
write_i64(stream, exception.param[0] as i64).await?;
|
write_i64(stream, exception.param[0] as i64).await?;
|
||||||
write_i64(stream, exception.param[1] as i64).await?;
|
write_i64(stream, exception.param[1] as i64).await?;
|
||||||
write_i64(stream, exception.param[2] as i64).await?;
|
write_i64(stream, exception.param[2] as i64).await?;
|
||||||
|
@ -301,7 +264,7 @@ async fn handle_run_kernel(
|
||||||
write_i32(stream, sp as i32).await?;
|
write_i32(stream, sp as i32).await?;
|
||||||
}
|
}
|
||||||
write_i8(stream, async_errors as i8).await?;
|
write_i8(stream, async_errors as i8).await?;
|
||||||
}
|
},
|
||||||
None => {
|
None => {
|
||||||
error!("Uncaught kernel exceptions: {:?}", exceptions);
|
error!("Uncaught kernel exceptions: {:?}", exceptions);
|
||||||
}
|
}
|
||||||
|
@ -310,68 +273,27 @@ async fn handle_run_kernel(
|
||||||
}
|
}
|
||||||
kernel::Message::CachePutRequest(key, value) => {
|
kernel::Message::CachePutRequest(key, value) => {
|
||||||
CACHE_STORE.lock().insert(key, value);
|
CACHE_STORE.lock().insert(key, value);
|
||||||
}
|
},
|
||||||
kernel::Message::CacheGetRequest(key) => {
|
kernel::Message::CacheGetRequest(key) => {
|
||||||
const DEFAULT: Vec<i32> = Vec::new();
|
const DEFAULT: Vec<i32> = Vec::new();
|
||||||
let value = CACHE_STORE.lock().get(&key).unwrap_or(&DEFAULT).clone();
|
let value = CACHE_STORE.lock().get(&key).unwrap_or(&DEFAULT).clone();
|
||||||
control
|
control.borrow_mut().tx.async_send(kernel::Message::CacheGetReply(value)).await;
|
||||||
.borrow_mut()
|
},
|
||||||
.tx
|
|
||||||
.async_send(kernel::Message::CacheGetReply(value))
|
|
||||||
.await;
|
|
||||||
}
|
|
||||||
kernel::Message::DmaPutRequest(recorder) => {
|
kernel::Message::DmaPutRequest(recorder) => {
|
||||||
let _id = rtio_dma::put_record(aux_mutex, routing_table, timer, recorder).await;
|
DMA_RECORD_STORE.lock().insert(recorder.name, (recorder.buffer, recorder.duration));
|
||||||
#[cfg(has_drtio)]
|
},
|
||||||
rtio_dma::remote_dma::upload_traces(aux_mutex, routing_table, timer, _id).await;
|
|
||||||
}
|
|
||||||
kernel::Message::DmaEraseRequest(name) => {
|
kernel::Message::DmaEraseRequest(name) => {
|
||||||
// prevent possible OOM when we have large DMA record replacement.
|
// prevent possible OOM when we have large DMA record replacement.
|
||||||
rtio_dma::erase(name, aux_mutex, routing_table, timer).await;
|
DMA_RECORD_STORE.lock().remove(&name);
|
||||||
}
|
},
|
||||||
kernel::Message::DmaGetRequest(name) => {
|
kernel::Message::DmaGetRequest(name) => {
|
||||||
let result = rtio_dma::retrieve(name);
|
let result = DMA_RECORD_STORE.lock().get(&name).map(|v| v.clone());
|
||||||
control
|
control.borrow_mut().tx.async_send(kernel::Message::DmaGetReply(result)).await;
|
||||||
.borrow_mut()
|
},
|
||||||
.tx
|
|
||||||
.async_send(kernel::Message::DmaGetReply(result))
|
|
||||||
.await;
|
|
||||||
}
|
|
||||||
#[cfg(has_drtio)]
|
|
||||||
kernel::Message::DmaStartRemoteRequest { id, timestamp } => {
|
|
||||||
rtio_dma::remote_dma::playback(aux_mutex, routing_table, timer, id as u32, timestamp as u64).await;
|
|
||||||
}
|
|
||||||
#[cfg(has_drtio)]
|
|
||||||
kernel::Message::DmaAwaitRemoteRequest(id) => {
|
|
||||||
let result = rtio_dma::remote_dma::await_done(id as u32, Some(10_000), timer).await;
|
|
||||||
let reply = match result {
|
|
||||||
Ok(rtio_dma::remote_dma::RemoteState::PlaybackEnded {
|
|
||||||
error,
|
|
||||||
channel,
|
|
||||||
timestamp,
|
|
||||||
}) => kernel::Message::DmaAwaitRemoteReply {
|
|
||||||
timeout: false,
|
|
||||||
error: error,
|
|
||||||
channel: channel,
|
|
||||||
timestamp: timestamp,
|
|
||||||
},
|
|
||||||
_ => kernel::Message::DmaAwaitRemoteReply {
|
|
||||||
timeout: true,
|
|
||||||
error: 0,
|
|
||||||
channel: 0,
|
|
||||||
timestamp: 0,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
control.borrow_mut().tx.async_send(reply).await;
|
|
||||||
}
|
|
||||||
#[cfg(has_drtio)]
|
#[cfg(has_drtio)]
|
||||||
kernel::Message::UpDestinationsRequest(destination) => {
|
kernel::Message::UpDestinationsRequest(destination) => {
|
||||||
let result = _up_destinations.borrow()[destination as usize];
|
let result = _up_destinations.borrow()[destination as usize];
|
||||||
control
|
control.borrow_mut().tx.async_send(kernel::Message::UpDestinationsReply(result)).await;
|
||||||
.borrow_mut()
|
|
||||||
.tx
|
|
||||||
.async_send(kernel::Message::UpDestinationsReply(result))
|
|
||||||
.await;
|
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
panic!("unexpected message from core1 while kernel was running: {:?}", reply);
|
panic!("unexpected message from core1 while kernel was running: {:?}", reply);
|
||||||
|
@ -381,17 +303,11 @@ async fn handle_run_kernel(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn load_kernel(
|
|
||||||
buffer: &Vec<u8>,
|
async fn load_kernel(buffer: &Vec<u8>, control: &Rc<RefCell<kernel::Control>>, stream: Option<&TcpStream>) -> Result<()> {
|
||||||
control: &Rc<RefCell<kernel::Control>>,
|
|
||||||
stream: Option<&TcpStream>,
|
|
||||||
) -> Result<()> {
|
|
||||||
let mut control = control.borrow_mut();
|
let mut control = control.borrow_mut();
|
||||||
control.restart();
|
control.restart();
|
||||||
control
|
control.tx.async_send(kernel::Message::LoadRequest(buffer.to_vec())).await;
|
||||||
.tx
|
|
||||||
.async_send(kernel::Message::LoadRequest(buffer.to_vec()))
|
|
||||||
.await;
|
|
||||||
let reply = control.rx.async_recv().await;
|
let reply = control.rx.async_recv().await;
|
||||||
match reply {
|
match reply {
|
||||||
kernel::Message::LoadCompleted => {
|
kernel::Message::LoadCompleted => {
|
||||||
|
@ -399,7 +315,7 @@ async fn load_kernel(
|
||||||
write_header(stream, Reply::LoadCompleted).await?;
|
write_header(stream, Reply::LoadCompleted).await?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
},
|
||||||
kernel::Message::LoadFailed => {
|
kernel::Message::LoadFailed => {
|
||||||
if let Some(stream) = stream {
|
if let Some(stream) = stream {
|
||||||
write_header(stream, Reply::LoadFailed).await?;
|
write_header(stream, Reply::LoadFailed).await?;
|
||||||
|
@ -408,7 +324,7 @@ async fn load_kernel(
|
||||||
error!("Kernel load failed");
|
error!("Kernel load failed");
|
||||||
}
|
}
|
||||||
Err(Error::UnexpectedPattern)
|
Err(Error::UnexpectedPattern)
|
||||||
}
|
},
|
||||||
_ => {
|
_ => {
|
||||||
error!("unexpected message from core1: {:?}", reply);
|
error!("unexpected message from core1: {:?}", reply);
|
||||||
if let Some(stream) = stream {
|
if let Some(stream) = stream {
|
||||||
|
@ -420,14 +336,7 @@ async fn load_kernel(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_connection(
|
async fn handle_connection(stream: &mut TcpStream, control: Rc<RefCell<kernel::Control>>, up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>) -> Result<()> {
|
||||||
stream: &mut TcpStream,
|
|
||||||
control: Rc<RefCell<kernel::Control>>,
|
|
||||||
up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>,
|
|
||||||
aux_mutex: &Rc<Mutex<bool>>,
|
|
||||||
routing_table: &drtio_routing::RoutingTable,
|
|
||||||
timer: GlobalTimer,
|
|
||||||
) -> Result<()> {
|
|
||||||
stream.set_ack_delay(None);
|
stream.set_ack_delay(None);
|
||||||
|
|
||||||
if !expect(stream, b"ARTIQ coredev\n").await? {
|
if !expect(stream, b"ARTIQ coredev\n").await? {
|
||||||
|
@ -444,25 +353,17 @@ async fn handle_connection(
|
||||||
Request::SystemInfo => {
|
Request::SystemInfo => {
|
||||||
write_header(stream, Reply::SystemInfo).await?;
|
write_header(stream, Reply::SystemInfo).await?;
|
||||||
stream.send_slice("ARZQ".as_bytes()).await?;
|
stream.send_slice("ARZQ".as_bytes()).await?;
|
||||||
}
|
},
|
||||||
Request::LoadKernel => {
|
Request::LoadKernel => {
|
||||||
let buffer = read_bytes(stream, 1024 * 1024).await?;
|
let buffer = read_bytes(stream, 1024*1024).await?;
|
||||||
load_kernel(&buffer, &control, Some(stream)).await?;
|
load_kernel(&buffer, &control, Some(stream)).await?;
|
||||||
}
|
},
|
||||||
Request::RunKernel => {
|
Request::RunKernel => {
|
||||||
handle_run_kernel(
|
handle_run_kernel(Some(stream), &control, &up_destinations).await?;
|
||||||
Some(stream),
|
},
|
||||||
&control,
|
|
||||||
&up_destinations,
|
|
||||||
aux_mutex,
|
|
||||||
routing_table,
|
|
||||||
timer,
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
}
|
|
||||||
_ => {
|
_ => {
|
||||||
error!("unexpected request from host: {:?}", request);
|
error!("unexpected request from host: {:?}", request);
|
||||||
return Err(Error::UnrecognizedPacket);
|
return Err(Error::UnrecognizedPacket)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -486,24 +387,24 @@ pub fn main(timer: GlobalTimer, cfg: Config) {
|
||||||
let ip_addrs = [
|
let ip_addrs = [
|
||||||
IpCidr::new(net_addresses.ipv4_addr, 0),
|
IpCidr::new(net_addresses.ipv4_addr, 0),
|
||||||
IpCidr::new(net_addresses.ipv6_ll_addr, 0),
|
IpCidr::new(net_addresses.ipv6_ll_addr, 0),
|
||||||
IpCidr::new(addr, 0),
|
IpCidr::new(addr, 0)
|
||||||
];
|
];
|
||||||
EthernetInterfaceBuilder::new(&mut eth)
|
EthernetInterfaceBuilder::new(&mut eth)
|
||||||
.ethernet_addr(net_addresses.hardware_addr)
|
.ethernet_addr(net_addresses.hardware_addr)
|
||||||
.ip_addrs(ip_addrs)
|
.ip_addrs(ip_addrs)
|
||||||
.neighbor_cache(neighbor_cache)
|
.neighbor_cache(neighbor_cache)
|
||||||
.finalize()
|
.finalize()
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
let ip_addrs = [
|
let ip_addrs = [
|
||||||
IpCidr::new(net_addresses.ipv4_addr, 0),
|
IpCidr::new(net_addresses.ipv4_addr, 0),
|
||||||
IpCidr::new(net_addresses.ipv6_ll_addr, 0),
|
IpCidr::new(net_addresses.ipv6_ll_addr, 0)
|
||||||
];
|
];
|
||||||
EthernetInterfaceBuilder::new(&mut eth)
|
EthernetInterfaceBuilder::new(&mut eth)
|
||||||
.ethernet_addr(net_addresses.hardware_addr)
|
.ethernet_addr(net_addresses.hardware_addr)
|
||||||
.ip_addrs(ip_addrs)
|
.ip_addrs(ip_addrs)
|
||||||
.neighbor_cache(neighbor_cache)
|
.neighbor_cache(neighbor_cache)
|
||||||
.finalize()
|
.finalize()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -512,20 +413,18 @@ pub fn main(timer: GlobalTimer, cfg: Config) {
|
||||||
// before, mutex was on io, but now that io isn't used...?
|
// before, mutex was on io, but now that io isn't used...?
|
||||||
let aux_mutex: Rc<Mutex<bool>> = Rc::new(Mutex::new(false));
|
let aux_mutex: Rc<Mutex<bool>> = Rc::new(Mutex::new(false));
|
||||||
#[cfg(has_drtio)]
|
#[cfg(has_drtio)]
|
||||||
let drtio_routing_table = Rc::new(RefCell::new(drtio_routing::config_routing_table(
|
let drtio_routing_table = Rc::new(RefCell::new(
|
||||||
pl::csr::DRTIO.len(),
|
drtio_routing::config_routing_table(pl::csr::DRTIO.len(), &cfg)));
|
||||||
&cfg,
|
|
||||||
)));
|
|
||||||
#[cfg(not(has_drtio))]
|
#[cfg(not(has_drtio))]
|
||||||
let drtio_routing_table = Rc::new(RefCell::new(drtio_routing::RoutingTable::default_empty()));
|
let drtio_routing_table = Rc::new(RefCell::new(drtio_routing::RoutingTable::default_empty()));
|
||||||
let up_destinations = Rc::new(RefCell::new([false; drtio_routing::DEST_COUNT]));
|
let up_destinations = Rc::new(RefCell::new([false; drtio_routing::DEST_COUNT]));
|
||||||
#[cfg(has_drtio_routing)]
|
#[cfg(has_drtio_routing)]
|
||||||
drtio_routing::interconnect_disable_all();
|
drtio_routing::interconnect_disable_all();
|
||||||
|
|
||||||
rtio_mgt::startup(&aux_mutex, &drtio_routing_table, &up_destinations, timer, &cfg);
|
rtio_mgt::startup(&aux_mutex, &drtio_routing_table, &up_destinations, timer);
|
||||||
|
|
||||||
analyzer::start();
|
analyzer::start();
|
||||||
moninj::start(timer, &aux_mutex, &drtio_routing_table);
|
moninj::start(timer, aux_mutex, drtio_routing_table);
|
||||||
|
|
||||||
let control: Rc<RefCell<kernel::Control>> = Rc::new(RefCell::new(kernel::Control::start()));
|
let control: Rc<RefCell<kernel::Control>> = Rc::new(RefCell::new(kernel::Control::start()));
|
||||||
let idle_kernel = Rc::new(cfg.read("idle_kernel").ok());
|
let idle_kernel = Rc::new(cfg.read("idle_kernel").ok());
|
||||||
|
@ -533,15 +432,7 @@ pub fn main(timer: GlobalTimer, cfg: Config) {
|
||||||
info!("Loading startup kernel...");
|
info!("Loading startup kernel...");
|
||||||
if let Ok(()) = task::block_on(load_kernel(&buffer, &control, None)) {
|
if let Ok(()) = task::block_on(load_kernel(&buffer, &control, None)) {
|
||||||
info!("Starting startup kernel...");
|
info!("Starting startup kernel...");
|
||||||
let routing_table = drtio_routing_table.borrow();
|
let _ = task::block_on(handle_run_kernel(None, &control, &up_destinations));
|
||||||
let _ = task::block_on(handle_run_kernel(
|
|
||||||
None,
|
|
||||||
&control,
|
|
||||||
&up_destinations,
|
|
||||||
&aux_mutex,
|
|
||||||
&routing_table,
|
|
||||||
timer,
|
|
||||||
));
|
|
||||||
info!("Startup kernel finished!");
|
info!("Startup kernel finished!");
|
||||||
} else {
|
} else {
|
||||||
error!("Error loading startup kernel!");
|
error!("Error loading startup kernel!");
|
||||||
|
@ -567,16 +458,13 @@ pub fn main(timer: GlobalTimer, cfg: Config) {
|
||||||
let connection = connection.clone();
|
let connection = connection.clone();
|
||||||
let terminate = terminate.clone();
|
let terminate = terminate.clone();
|
||||||
let up_destinations = up_destinations.clone();
|
let up_destinations = up_destinations.clone();
|
||||||
let aux_mutex = aux_mutex.clone();
|
|
||||||
let routing_table = drtio_routing_table.clone();
|
|
||||||
|
|
||||||
// we make sure the value of terminate is 0 before we start
|
// we make sure the value of terminate is 0 before we start
|
||||||
let _ = terminate.try_wait();
|
let _ = terminate.try_wait();
|
||||||
task::spawn(async move {
|
task::spawn(async move {
|
||||||
let routing_table = routing_table.borrow();
|
|
||||||
select_biased! {
|
select_biased! {
|
||||||
_ = (async {
|
_ = (async {
|
||||||
let _ = handle_connection(&mut stream, control.clone(), &up_destinations, &aux_mutex, &routing_table, timer)
|
let _ = handle_connection(&mut stream, control.clone(), &up_destinations)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| warn!("connection terminated: {}", e));
|
.map_err(|e| warn!("connection terminated: {}", e));
|
||||||
if let Some(buffer) = &*idle_kernel {
|
if let Some(buffer) = &*idle_kernel {
|
||||||
|
@ -584,7 +472,7 @@ pub fn main(timer: GlobalTimer, cfg: Config) {
|
||||||
let _ = load_kernel(&buffer, &control, None)
|
let _ = load_kernel(&buffer, &control, None)
|
||||||
.await.map_err(|_| warn!("error loading idle kernel"));
|
.await.map_err(|_| warn!("error loading idle kernel"));
|
||||||
info!("Running idle kernel");
|
info!("Running idle kernel");
|
||||||
let _ = handle_run_kernel(None, &control, &up_destinations, &aux_mutex, &routing_table, timer)
|
let _ = handle_run_kernel(None, &control, &up_destinations)
|
||||||
.await.map_err(|_| warn!("error running idle kernel"));
|
.await.map_err(|_| warn!("error running idle kernel"));
|
||||||
info!("Idle kernel terminated");
|
info!("Idle kernel terminated");
|
||||||
}
|
}
|
||||||
|
@ -598,59 +486,7 @@ pub fn main(timer: GlobalTimer, cfg: Config) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Sockets::run(&mut iface, || Instant::from_millis(timer.get_time().0 as i32));
|
Sockets::run(&mut iface, || {
|
||||||
}
|
Instant::from_millis(timer.get_time().0 as i32)
|
||||||
|
});
|
||||||
pub fn soft_panic_main(timer: GlobalTimer, cfg: Config) -> ! {
|
|
||||||
let net_addresses = net_settings::get_addresses(&cfg);
|
|
||||||
info!("network addresses: {}", net_addresses);
|
|
||||||
|
|
||||||
let eth = zynq::eth::Eth::eth0(net_addresses.hardware_addr.0.clone());
|
|
||||||
const RX_LEN: usize = 64;
|
|
||||||
// Number of transmission buffers (minimum is two because with
|
|
||||||
// one, duplicate packet transmission occurs)
|
|
||||||
const TX_LEN: usize = 64;
|
|
||||||
let eth = eth.start_rx(RX_LEN);
|
|
||||||
let mut eth = eth.start_tx(TX_LEN);
|
|
||||||
|
|
||||||
let neighbor_cache = NeighborCache::new(alloc::collections::BTreeMap::new());
|
|
||||||
let mut iface = match net_addresses.ipv6_addr {
|
|
||||||
Some(addr) => {
|
|
||||||
let ip_addrs = [
|
|
||||||
IpCidr::new(net_addresses.ipv4_addr, 0),
|
|
||||||
IpCidr::new(net_addresses.ipv6_ll_addr, 0),
|
|
||||||
IpCidr::new(addr, 0),
|
|
||||||
];
|
|
||||||
EthernetInterfaceBuilder::new(&mut eth)
|
|
||||||
.ethernet_addr(net_addresses.hardware_addr)
|
|
||||||
.ip_addrs(ip_addrs)
|
|
||||||
.neighbor_cache(neighbor_cache)
|
|
||||||
.finalize()
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
let ip_addrs = [
|
|
||||||
IpCidr::new(net_addresses.ipv4_addr, 0),
|
|
||||||
IpCidr::new(net_addresses.ipv6_ll_addr, 0),
|
|
||||||
];
|
|
||||||
EthernetInterfaceBuilder::new(&mut eth)
|
|
||||||
.ethernet_addr(net_addresses.hardware_addr)
|
|
||||||
.ip_addrs(ip_addrs)
|
|
||||||
.neighbor_cache(neighbor_cache)
|
|
||||||
.finalize()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Sockets::init(32);
|
|
||||||
|
|
||||||
mgmt::start(cfg);
|
|
||||||
|
|
||||||
// getting eth settings disables the LED as it resets GPIO
|
|
||||||
// need to re-enable it here
|
|
||||||
#[cfg(feature = "target_kasli_soc")]
|
|
||||||
{
|
|
||||||
let mut err_led = ErrorLED::error_led();
|
|
||||||
err_led.toggle(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
Sockets::run(&mut iface, || Instant::from_millis(timer.get_time().0 as i32));
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,15 +13,15 @@
|
||||||
#![allow(non_camel_case_types)]
|
#![allow(non_camel_case_types)]
|
||||||
|
|
||||||
use core::mem;
|
use core::mem;
|
||||||
|
|
||||||
use cslice::CSlice;
|
use cslice::CSlice;
|
||||||
use dwarf::eh::{self, EHAction, EHContext};
|
|
||||||
use libc::{c_int, c_void, uintptr_t};
|
|
||||||
use log::{error, trace};
|
|
||||||
use unwind as uw;
|
use unwind as uw;
|
||||||
|
use libc::{c_int, c_void, uintptr_t};
|
||||||
|
use log::{trace, error};
|
||||||
use crate::kernel::KERNEL_IMAGE;
|
use crate::kernel::KERNEL_IMAGE;
|
||||||
|
|
||||||
|
use dwarf::eh::{self, EHAction, EHContext};
|
||||||
|
|
||||||
|
|
||||||
const EXCEPTION_CLASS: uw::_Unwind_Exception_Class = 0x4d_4c_42_53_41_52_54_51; /* 'MLBSARTQ' */
|
const EXCEPTION_CLASS: uw::_Unwind_Exception_Class = 0x4d_4c_42_53_41_52_54_51; /* 'MLBSARTQ' */
|
||||||
|
|
||||||
#[cfg(target_arch = "arm")]
|
#[cfg(target_arch = "arm")]
|
||||||
|
@ -32,13 +32,13 @@ const UNWIND_DATA_REG: (i32, i32) = (0, 1); // R0, R1
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct Exception<'a> {
|
pub struct Exception<'a> {
|
||||||
pub id: u32,
|
pub id: u32,
|
||||||
pub file: CSlice<'a, u8>,
|
pub file: CSlice<'a, u8>,
|
||||||
pub line: u32,
|
pub line: u32,
|
||||||
pub column: u32,
|
pub column: u32,
|
||||||
pub function: CSlice<'a, u8>,
|
pub function: CSlice<'a, u8>,
|
||||||
pub message: CSlice<'a, u8>,
|
pub message: CSlice<'a, u8>,
|
||||||
pub param: [i64; 3],
|
pub param: [i64; 3]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn str_err(_: core::str::Utf8Error) -> core::fmt::Error {
|
fn str_err(_: core::str::Utf8Error) -> core::fmt::Error {
|
||||||
|
@ -55,16 +55,12 @@ fn exception_str<'a>(s: &'a CSlice<'a, u8>) -> Result<&'a str, core::str::Utf8Er
|
||||||
|
|
||||||
impl<'a> core::fmt::Debug for Exception<'a> {
|
impl<'a> core::fmt::Debug for Exception<'a> {
|
||||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||||
write!(
|
write!(f, "Exception {} from {} in {}:{}:{}, message: {}",
|
||||||
f,
|
|
||||||
"Exception {} from {} in {}:{}:{}, message: {}",
|
|
||||||
self.id,
|
self.id,
|
||||||
exception_str(&self.function).map_err(str_err)?,
|
exception_str(&self.function).map_err(str_err)?,
|
||||||
exception_str(&self.file).map_err(str_err)?,
|
exception_str(&self.file).map_err(str_err)?,
|
||||||
self.line,
|
self.line, self.column,
|
||||||
self.column,
|
exception_str(&self.message).map_err(str_err)?)
|
||||||
exception_str(&self.message).map_err(str_err)?
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,9 +91,9 @@ struct ExceptionBuffer {
|
||||||
|
|
||||||
static mut EXCEPTION_BUFFER: ExceptionBuffer = ExceptionBuffer {
|
static mut EXCEPTION_BUFFER: ExceptionBuffer = ExceptionBuffer {
|
||||||
uw_exceptions: [uw::_Unwind_Exception {
|
uw_exceptions: [uw::_Unwind_Exception {
|
||||||
exception_class: EXCEPTION_CLASS,
|
exception_class: EXCEPTION_CLASS,
|
||||||
exception_cleanup: cleanup,
|
exception_cleanup: cleanup,
|
||||||
private: [0; uw::unwinder_private_data_size],
|
private: [0; uw::unwinder_private_data_size],
|
||||||
}; MAX_INFLIGHT_EXCEPTIONS],
|
}; MAX_INFLIGHT_EXCEPTIONS],
|
||||||
exceptions: [None; MAX_INFLIGHT_EXCEPTIONS + 1],
|
exceptions: [None; MAX_INFLIGHT_EXCEPTIONS + 1],
|
||||||
exception_stack: [-1; MAX_INFLIGHT_EXCEPTIONS + 1],
|
exception_stack: [-1; MAX_INFLIGHT_EXCEPTIONS + 1],
|
||||||
|
@ -106,17 +102,17 @@ static mut EXCEPTION_BUFFER: ExceptionBuffer = ExceptionBuffer {
|
||||||
stack_pointers: [StackPointerBacktrace {
|
stack_pointers: [StackPointerBacktrace {
|
||||||
stack_pointer: 0,
|
stack_pointer: 0,
|
||||||
initial_backtrace_size: 0,
|
initial_backtrace_size: 0,
|
||||||
current_backtrace_size: 0,
|
current_backtrace_size: 0
|
||||||
}; MAX_INFLIGHT_EXCEPTIONS + 1],
|
}; MAX_INFLIGHT_EXCEPTIONS + 1],
|
||||||
exception_count: 0,
|
exception_count: 0
|
||||||
};
|
};
|
||||||
|
|
||||||
pub unsafe extern "C" fn reset_exception_buffer() {
|
pub unsafe extern fn reset_exception_buffer() {
|
||||||
trace!("reset exception buffer");
|
trace!("reset exception buffer");
|
||||||
EXCEPTION_BUFFER.uw_exceptions = [uw::_Unwind_Exception {
|
EXCEPTION_BUFFER.uw_exceptions = [uw::_Unwind_Exception {
|
||||||
exception_class: EXCEPTION_CLASS,
|
exception_class: EXCEPTION_CLASS,
|
||||||
exception_cleanup: cleanup,
|
exception_cleanup: cleanup,
|
||||||
private: [0; uw::unwinder_private_data_size],
|
private: [0; uw::unwinder_private_data_size],
|
||||||
}; MAX_INFLIGHT_EXCEPTIONS];
|
}; MAX_INFLIGHT_EXCEPTIONS];
|
||||||
EXCEPTION_BUFFER.exceptions = [None; MAX_INFLIGHT_EXCEPTIONS + 1];
|
EXCEPTION_BUFFER.exceptions = [None; MAX_INFLIGHT_EXCEPTIONS + 1];
|
||||||
EXCEPTION_BUFFER.exception_stack = [-1; MAX_INFLIGHT_EXCEPTIONS + 1];
|
EXCEPTION_BUFFER.exception_stack = [-1; MAX_INFLIGHT_EXCEPTIONS + 1];
|
||||||
|
@ -124,25 +120,26 @@ pub unsafe extern "C" fn reset_exception_buffer() {
|
||||||
EXCEPTION_BUFFER.exception_count = 0;
|
EXCEPTION_BUFFER.exception_count = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
type _Unwind_Stop_Fn = extern "C" fn(
|
type _Unwind_Stop_Fn = extern "C" fn(version: c_int,
|
||||||
version: c_int,
|
actions: i32,
|
||||||
actions: i32,
|
exception_class: uw::_Unwind_Exception_Class,
|
||||||
exception_class: uw::_Unwind_Exception_Class,
|
exception_object: *mut uw::_Unwind_Exception,
|
||||||
exception_object: *mut uw::_Unwind_Exception,
|
context: *mut uw::_Unwind_Context,
|
||||||
context: *mut uw::_Unwind_Context,
|
stop_parameter: *mut c_void)
|
||||||
stop_parameter: *mut c_void,
|
-> uw::_Unwind_Reason_Code;
|
||||||
) -> uw::_Unwind_Reason_Code;
|
|
||||||
|
|
||||||
extern "C" {
|
extern {
|
||||||
// not defined in EHABI, but LLVM added it and is useful to us
|
// not defined in EHABI, but LLVM added it and is useful to us
|
||||||
fn _Unwind_ForcedUnwind(
|
fn _Unwind_ForcedUnwind(exception: *mut uw::_Unwind_Exception,
|
||||||
exception: *mut uw::_Unwind_Exception,
|
stop_fn: _Unwind_Stop_Fn,
|
||||||
stop_fn: _Unwind_Stop_Fn,
|
stop_parameter: *mut c_void) -> uw::_Unwind_Reason_Code;
|
||||||
stop_parameter: *mut c_void,
|
|
||||||
) -> uw::_Unwind_Reason_Code;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn find_eh_action(context: *mut uw::_Unwind_Context, foreign_exception: bool, id: u32) -> Result<EHAction, ()> {
|
unsafe fn find_eh_action(
|
||||||
|
context: *mut uw::_Unwind_Context,
|
||||||
|
foreign_exception: bool,
|
||||||
|
id: u32,
|
||||||
|
) -> Result<EHAction, ()> {
|
||||||
let lsda = uw::_Unwind_GetLanguageSpecificData(context) as *const u8;
|
let lsda = uw::_Unwind_GetLanguageSpecificData(context) as *const u8;
|
||||||
let mut ip_before_instr: c_int = 0;
|
let mut ip_before_instr: c_int = 0;
|
||||||
let ip = uw::_Unwind_GetIPInfo(context, &mut ip_before_instr);
|
let ip = uw::_Unwind_GetIPInfo(context, &mut ip_before_instr);
|
||||||
|
@ -157,11 +154,10 @@ unsafe fn find_eh_action(context: *mut uw::_Unwind_Context, foreign_exception: b
|
||||||
eh::find_eh_action(lsda, &eh_context, foreign_exception, id)
|
eh::find_eh_action(lsda, &eh_context, foreign_exception, id)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn artiq_personality(
|
pub unsafe fn artiq_personality(_state: uw::_Unwind_State,
|
||||||
_state: uw::_Unwind_State,
|
exception_object: *mut uw::_Unwind_Exception,
|
||||||
exception_object: *mut uw::_Unwind_Exception,
|
context: *mut uw::_Unwind_Context)
|
||||||
context: *mut uw::_Unwind_Context,
|
-> uw::_Unwind_Reason_Code {
|
||||||
) -> uw::_Unwind_Reason_Code {
|
|
||||||
// we will only do phase 2 forced unwinding now
|
// we will only do phase 2 forced unwinding now
|
||||||
// The DWARF unwinder assumes that _Unwind_Context holds things like the function
|
// The DWARF unwinder assumes that _Unwind_Context holds things like the function
|
||||||
// and LSDA pointers, however ARM EHABI places them into the exception object.
|
// and LSDA pointers, however ARM EHABI places them into the exception object.
|
||||||
|
@ -169,7 +165,9 @@ pub unsafe fn artiq_personality(
|
||||||
// take only the context pointer, GCC personality routines stash a pointer to
|
// take only the context pointer, GCC personality routines stash a pointer to
|
||||||
// exception_object in the context, using location reserved for ARM's
|
// exception_object in the context, using location reserved for ARM's
|
||||||
// "scratch register" (r12).
|
// "scratch register" (r12).
|
||||||
uw::_Unwind_SetGR(context, uw::UNWIND_POINTER_REG, exception_object as uw::_Unwind_Ptr);
|
uw::_Unwind_SetGR(context,
|
||||||
|
uw::UNWIND_POINTER_REG,
|
||||||
|
exception_object as uw::_Unwind_Ptr);
|
||||||
// ...A more principled approach would be to provide the full definition of ARM's
|
// ...A more principled approach would be to provide the full definition of ARM's
|
||||||
// _Unwind_Context in our libunwind bindings and fetch the required data from there
|
// _Unwind_Context in our libunwind bindings and fetch the required data from there
|
||||||
// directly, bypassing DWARF compatibility functions.
|
// directly, bypassing DWARF compatibility functions.
|
||||||
|
@ -188,8 +186,10 @@ pub unsafe fn artiq_personality(
|
||||||
};
|
};
|
||||||
match eh_action {
|
match eh_action {
|
||||||
EHAction::None => return continue_unwind(exception_object, context),
|
EHAction::None => return continue_unwind(exception_object, context),
|
||||||
EHAction::Cleanup(lpad) | EHAction::Catch(lpad) => {
|
EHAction::Cleanup(lpad) |
|
||||||
uw::_Unwind_SetGR(context, UNWIND_DATA_REG.0, exception_object as uintptr_t);
|
EHAction::Catch(lpad) => {
|
||||||
|
uw::_Unwind_SetGR(context, UNWIND_DATA_REG.0,
|
||||||
|
exception_object as uintptr_t);
|
||||||
uw::_Unwind_SetGR(context, UNWIND_DATA_REG.1, exception as *const _ as uw::_Unwind_Word);
|
uw::_Unwind_SetGR(context, UNWIND_DATA_REG.1, exception as *const _ as uw::_Unwind_Word);
|
||||||
uw::_Unwind_SetIP(context, lpad);
|
uw::_Unwind_SetIP(context, lpad);
|
||||||
return uw::_URC_INSTALL_CONTEXT;
|
return uw::_URC_INSTALL_CONTEXT;
|
||||||
|
@ -199,10 +199,9 @@ pub unsafe fn artiq_personality(
|
||||||
|
|
||||||
// On ARM EHABI the personality routine is responsible for actually
|
// On ARM EHABI the personality routine is responsible for actually
|
||||||
// unwinding a single stack frame before returning (ARM EHABI Sec. 6.1).
|
// unwinding a single stack frame before returning (ARM EHABI Sec. 6.1).
|
||||||
unsafe fn continue_unwind(
|
unsafe fn continue_unwind(exception_object: *mut uw::_Unwind_Exception,
|
||||||
exception_object: *mut uw::_Unwind_Exception,
|
context: *mut uw::_Unwind_Context)
|
||||||
context: *mut uw::_Unwind_Context,
|
-> uw::_Unwind_Reason_Code {
|
||||||
) -> uw::_Unwind_Reason_Code {
|
|
||||||
let reason = __gnu_unwind_frame(exception_object, context);
|
let reason = __gnu_unwind_frame(exception_object, context);
|
||||||
if reason == uw::_URC_NO_REASON {
|
if reason == uw::_URC_NO_REASON {
|
||||||
uw::_URC_CONTINUE_UNWIND
|
uw::_URC_CONTINUE_UNWIND
|
||||||
|
@ -212,14 +211,13 @@ pub unsafe fn artiq_personality(
|
||||||
}
|
}
|
||||||
// defined in libgcc
|
// defined in libgcc
|
||||||
extern "C" {
|
extern "C" {
|
||||||
fn __gnu_unwind_frame(
|
fn __gnu_unwind_frame(exception_object: *mut uw::_Unwind_Exception,
|
||||||
exception_object: *mut uw::_Unwind_Exception,
|
context: *mut uw::_Unwind_Context)
|
||||||
context: *mut uw::_Unwind_Context,
|
-> uw::_Unwind_Reason_Code;
|
||||||
) -> uw::_Unwind_Reason_Code;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe extern "C" fn raise(exception: *const Exception) -> ! {
|
pub unsafe extern fn raise(exception: *const Exception) -> ! {
|
||||||
use cslice::AsCSlice;
|
use cslice::AsCSlice;
|
||||||
|
|
||||||
let count = EXCEPTION_BUFFER.exception_count;
|
let count = EXCEPTION_BUFFER.exception_count;
|
||||||
|
@ -246,11 +244,8 @@ pub unsafe extern "C" fn raise(exception: *const Exception) -> ! {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert!(found);
|
assert!(found);
|
||||||
let _result = _Unwind_ForcedUnwind(
|
let _result = _Unwind_ForcedUnwind(&mut EXCEPTION_BUFFER.uw_exceptions[stack[count - 1] as usize],
|
||||||
&mut EXCEPTION_BUFFER.uw_exceptions[stack[count - 1] as usize],
|
stop_fn, core::ptr::null_mut());
|
||||||
stop_fn,
|
|
||||||
core::ptr::null_mut(),
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
if count < MAX_INFLIGHT_EXCEPTIONS {
|
if count < MAX_INFLIGHT_EXCEPTIONS {
|
||||||
trace!("raising exception at level {}", count);
|
trace!("raising exception at level {}", count);
|
||||||
|
@ -258,33 +253,34 @@ pub unsafe extern "C" fn raise(exception: *const Exception) -> ! {
|
||||||
for (i, slot) in EXCEPTION_BUFFER.exceptions.iter_mut().enumerate() {
|
for (i, slot) in EXCEPTION_BUFFER.exceptions.iter_mut().enumerate() {
|
||||||
// we should always be able to find a slot
|
// we should always be able to find a slot
|
||||||
if slot.is_none() {
|
if slot.is_none() {
|
||||||
*slot = Some(*mem::transmute::<*const Exception, *const Exception<'static>>(
|
*slot = Some(
|
||||||
exception,
|
*mem::transmute::<*const Exception, *const Exception<'static>>
|
||||||
));
|
(exception));
|
||||||
EXCEPTION_BUFFER.exception_stack[count] = i as isize;
|
EXCEPTION_BUFFER.exception_stack[count] = i as isize;
|
||||||
EXCEPTION_BUFFER.uw_exceptions[i].private = [0; uw::unwinder_private_data_size];
|
EXCEPTION_BUFFER.uw_exceptions[i].private =
|
||||||
|
[0; uw::unwinder_private_data_size];
|
||||||
EXCEPTION_BUFFER.stack_pointers[i] = StackPointerBacktrace {
|
EXCEPTION_BUFFER.stack_pointers[i] = StackPointerBacktrace {
|
||||||
stack_pointer: 0,
|
stack_pointer: 0,
|
||||||
initial_backtrace_size: EXCEPTION_BUFFER.backtrace_size,
|
initial_backtrace_size: EXCEPTION_BUFFER.backtrace_size,
|
||||||
current_backtrace_size: 0,
|
current_backtrace_size: 0,
|
||||||
};
|
};
|
||||||
EXCEPTION_BUFFER.exception_count += 1;
|
EXCEPTION_BUFFER.exception_count += 1;
|
||||||
let _result =
|
let _result = _Unwind_ForcedUnwind(&mut EXCEPTION_BUFFER.uw_exceptions[i],
|
||||||
_Unwind_ForcedUnwind(&mut EXCEPTION_BUFFER.uw_exceptions[i], stop_fn, core::ptr::null_mut());
|
stop_fn, core::ptr::null_mut());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
error!("too many nested exceptions");
|
error!("too many nested exceptions");
|
||||||
// TODO: better reporting?
|
// TODO: better reporting?
|
||||||
let exception = Exception {
|
let exception = Exception {
|
||||||
id: get_exception_id("RuntimeError"),
|
id: get_exception_id("RuntimeError"),
|
||||||
file: file!().as_c_slice(),
|
file: file!().as_c_slice(),
|
||||||
line: line!(),
|
line: line!(),
|
||||||
column: column!(),
|
column: column!(),
|
||||||
// https://github.com/rust-lang/rfcs/pull/1719
|
// https://github.com/rust-lang/rfcs/pull/1719
|
||||||
function: "__artiq_raise".as_c_slice(),
|
function: "__artiq_raise".as_c_slice(),
|
||||||
message: "too many nested exceptions".as_c_slice(),
|
message: "too many nested exceptions".as_c_slice(),
|
||||||
param: [0, 0, 0],
|
param: [0, 0, 0]
|
||||||
};
|
};
|
||||||
EXCEPTION_BUFFER.exceptions[MAX_INFLIGHT_EXCEPTIONS] = Some(mem::transmute(exception));
|
EXCEPTION_BUFFER.exceptions[MAX_INFLIGHT_EXCEPTIONS] = Some(mem::transmute(exception));
|
||||||
EXCEPTION_BUFFER.stack_pointers[MAX_INFLIGHT_EXCEPTIONS] = Default::default();
|
EXCEPTION_BUFFER.stack_pointers[MAX_INFLIGHT_EXCEPTIONS] = Default::default();
|
||||||
|
@ -295,20 +291,17 @@ pub unsafe extern "C" fn raise(exception: *const Exception) -> ! {
|
||||||
unreachable!();
|
unreachable!();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe extern "C" fn resume() -> ! {
|
pub unsafe extern fn resume() -> ! {
|
||||||
trace!("resume");
|
trace!("resume");
|
||||||
assert!(EXCEPTION_BUFFER.exception_count != 0);
|
assert!(EXCEPTION_BUFFER.exception_count != 0);
|
||||||
let i = EXCEPTION_BUFFER.exception_stack[EXCEPTION_BUFFER.exception_count - 1];
|
let i = EXCEPTION_BUFFER.exception_stack[EXCEPTION_BUFFER.exception_count - 1];
|
||||||
assert!(i != -1);
|
assert!(i != -1);
|
||||||
let _result = _Unwind_ForcedUnwind(
|
let _result = _Unwind_ForcedUnwind(&mut EXCEPTION_BUFFER.uw_exceptions[i as usize],
|
||||||
&mut EXCEPTION_BUFFER.uw_exceptions[i as usize],
|
stop_fn, core::ptr::null_mut());
|
||||||
stop_fn,
|
|
||||||
core::ptr::null_mut(),
|
|
||||||
);
|
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe extern "C" fn end_catch() {
|
pub unsafe extern fn end_catch() {
|
||||||
let mut count = EXCEPTION_BUFFER.exception_count;
|
let mut count = EXCEPTION_BUFFER.exception_count;
|
||||||
assert!(count != 0);
|
assert!(count != 0);
|
||||||
// we remove all exceptions with SP <= current exception SP
|
// we remove all exceptions with SP <= current exception SP
|
||||||
|
@ -316,7 +309,8 @@ pub unsafe extern "C" fn end_catch() {
|
||||||
let index = EXCEPTION_BUFFER.exception_stack[count - 1] as usize;
|
let index = EXCEPTION_BUFFER.exception_stack[count - 1] as usize;
|
||||||
EXCEPTION_BUFFER.exception_stack[count - 1] = -1;
|
EXCEPTION_BUFFER.exception_stack[count - 1] = -1;
|
||||||
EXCEPTION_BUFFER.exceptions[index] = None;
|
EXCEPTION_BUFFER.exceptions[index] = None;
|
||||||
let outer_sp = EXCEPTION_BUFFER.stack_pointers[index].stack_pointer;
|
let outer_sp = EXCEPTION_BUFFER.stack_pointers
|
||||||
|
[index].stack_pointer;
|
||||||
count -= 1;
|
count -= 1;
|
||||||
for i in (0..count).rev() {
|
for i in (0..count).rev() {
|
||||||
let index = EXCEPTION_BUFFER.exception_stack[i];
|
let index = EXCEPTION_BUFFER.exception_stack[i];
|
||||||
|
@ -340,7 +334,8 @@ pub unsafe extern "C" fn end_catch() {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" fn cleanup(_unwind_code: uw::_Unwind_Reason_Code, _uw_exception: *mut uw::_Unwind_Exception) {
|
extern fn cleanup(_unwind_code: uw::_Unwind_Reason_Code,
|
||||||
|
_uw_exception: *mut uw::_Unwind_Exception) {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -350,26 +345,18 @@ fn uncaught_exception() -> ! {
|
||||||
for i in 0..EXCEPTION_BUFFER.exception_count {
|
for i in 0..EXCEPTION_BUFFER.exception_count {
|
||||||
if EXCEPTION_BUFFER.exception_stack[i] != i as isize {
|
if EXCEPTION_BUFFER.exception_stack[i] != i as isize {
|
||||||
// find the correct index
|
// find the correct index
|
||||||
let index = EXCEPTION_BUFFER
|
let index = EXCEPTION_BUFFER.exception_stack
|
||||||
.exception_stack
|
|
||||||
.iter()
|
.iter()
|
||||||
.position(|v| *v == i as isize)
|
.position(|v| *v == i as isize).unwrap();
|
||||||
.unwrap();
|
|
||||||
let a = EXCEPTION_BUFFER.exception_stack[index];
|
let a = EXCEPTION_BUFFER.exception_stack[index];
|
||||||
let b = EXCEPTION_BUFFER.exception_stack[i];
|
let b = EXCEPTION_BUFFER.exception_stack[i];
|
||||||
assert!(a != -1 && b != -1);
|
assert!(a != -1 && b != -1);
|
||||||
core::mem::swap(
|
core::mem::swap(&mut EXCEPTION_BUFFER.exception_stack[index],
|
||||||
&mut EXCEPTION_BUFFER.exception_stack[index],
|
&mut EXCEPTION_BUFFER.exception_stack[i]);
|
||||||
&mut EXCEPTION_BUFFER.exception_stack[i],
|
core::mem::swap(&mut EXCEPTION_BUFFER.exceptions[a as usize],
|
||||||
);
|
&mut EXCEPTION_BUFFER.exceptions[b as usize]);
|
||||||
core::mem::swap(
|
core::mem::swap(&mut EXCEPTION_BUFFER.stack_pointers[a as usize],
|
||||||
&mut EXCEPTION_BUFFER.exceptions[a as usize],
|
&mut EXCEPTION_BUFFER.stack_pointers[b as usize]);
|
||||||
&mut EXCEPTION_BUFFER.exceptions[b as usize],
|
|
||||||
);
|
|
||||||
core::mem::swap(
|
|
||||||
&mut EXCEPTION_BUFFER.stack_pointers[a as usize],
|
|
||||||
&mut EXCEPTION_BUFFER.stack_pointers[b as usize],
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -377,20 +364,17 @@ fn uncaught_exception() -> ! {
|
||||||
crate::kernel::core1::terminate(
|
crate::kernel::core1::terminate(
|
||||||
EXCEPTION_BUFFER.exceptions[..EXCEPTION_BUFFER.exception_count].as_ref(),
|
EXCEPTION_BUFFER.exceptions[..EXCEPTION_BUFFER.exception_count].as_ref(),
|
||||||
EXCEPTION_BUFFER.stack_pointers[..EXCEPTION_BUFFER.exception_count].as_ref(),
|
EXCEPTION_BUFFER.stack_pointers[..EXCEPTION_BUFFER.exception_count].as_ref(),
|
||||||
EXCEPTION_BUFFER.backtrace[..EXCEPTION_BUFFER.backtrace_size].as_mut(),
|
EXCEPTION_BUFFER.backtrace[..EXCEPTION_BUFFER.backtrace_size].as_mut())
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// stop function which would be executed when we unwind each frame
|
// stop function which would be executed when we unwind each frame
|
||||||
extern "C" fn stop_fn(
|
extern fn stop_fn(_version: c_int,
|
||||||
_version: c_int,
|
actions: i32,
|
||||||
actions: i32,
|
_uw_exception_class: uw::_Unwind_Exception_Class,
|
||||||
_uw_exception_class: uw::_Unwind_Exception_Class,
|
_uw_exception: *mut uw::_Unwind_Exception,
|
||||||
_uw_exception: *mut uw::_Unwind_Exception,
|
context: *mut uw::_Unwind_Context,
|
||||||
context: *mut uw::_Unwind_Context,
|
_stop_parameter: *mut c_void) -> uw::_Unwind_Reason_Code {
|
||||||
_stop_parameter: *mut c_void,
|
|
||||||
) -> uw::_Unwind_Reason_Code {
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let load_addr = KERNEL_IMAGE.as_ref().unwrap().get_load_addr();
|
let load_addr = KERNEL_IMAGE.as_ref().unwrap().get_load_addr();
|
||||||
let backtrace_size = EXCEPTION_BUFFER.backtrace_size;
|
let backtrace_size = EXCEPTION_BUFFER.backtrace_size;
|
||||||
|
@ -439,7 +423,7 @@ static EXCEPTION_ID_LOOKUP: [(&str, u32); 11] = [
|
||||||
pub fn get_exception_id(name: &str) -> u32 {
|
pub fn get_exception_id(name: &str) -> u32 {
|
||||||
for (n, id) in EXCEPTION_ID_LOOKUP.iter() {
|
for (n, id) in EXCEPTION_ID_LOOKUP.iter() {
|
||||||
if *n == name {
|
if *n == name {
|
||||||
return *id;
|
return *id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
unimplemented!("unallocated internal exception id")
|
unimplemented!("unallocated internal exception id")
|
||||||
|
@ -447,24 +431,25 @@ pub fn get_exception_id(name: &str) -> u32 {
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! artiq_raise {
|
macro_rules! artiq_raise {
|
||||||
($name:expr, $message:expr, $param0:expr, $param1:expr, $param2:expr) => {{
|
($name:expr, $message:expr, $param0:expr, $param1:expr, $param2:expr) => ({
|
||||||
use cslice::AsCSlice;
|
use cslice::AsCSlice;
|
||||||
let name_id = $crate::eh_artiq::get_exception_id($name);
|
let name_id = $crate::eh_artiq::get_exception_id($name);
|
||||||
let message_cl = $message.clone();
|
|
||||||
let exn = $crate::eh_artiq::Exception {
|
let exn = $crate::eh_artiq::Exception {
|
||||||
id: name_id,
|
id: name_id,
|
||||||
file: file!().as_c_slice(),
|
file: file!().as_c_slice(),
|
||||||
line: line!(),
|
line: line!(),
|
||||||
column: column!(),
|
column: column!(),
|
||||||
// https://github.com/rust-lang/rfcs/pull/1719
|
// https://github.com/rust-lang/rfcs/pull/1719
|
||||||
function: "(Rust function)".as_c_slice(),
|
function: "(Rust function)".as_c_slice(),
|
||||||
message: message_cl.as_c_slice(),
|
message: $message.as_c_slice(),
|
||||||
param: [$param0, $param1, $param2],
|
param: [$param0, $param1, $param2]
|
||||||
};
|
};
|
||||||
#[allow(unused_unsafe)]
|
#[allow(unused_unsafe)]
|
||||||
unsafe {
|
unsafe {
|
||||||
$crate::eh_artiq::raise(&exn)
|
$crate::eh_artiq::raise(&exn)
|
||||||
}
|
}
|
||||||
}};
|
});
|
||||||
($name:expr, $message:expr) => {{ artiq_raise!($name, $message, 0, 0, 0) }};
|
($name:expr, $message:expr) => ({
|
||||||
|
artiq_raise!($name, $message, 0, 0, 0)
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
use libboard_zynq;
|
use libboard_zynq;
|
||||||
|
|
||||||
use crate::artiq_raise;
|
use crate::artiq_raise;
|
||||||
|
|
||||||
pub static mut I2C_BUS: Option<libboard_zynq::i2c::I2c> = None;
|
pub static mut I2C_BUS: Option<libboard_zynq::i2c::I2c> = None;
|
||||||
|
|
||||||
pub extern "C" fn start(busno: i32) {
|
pub extern fn start(busno: i32) {
|
||||||
if busno > 0 {
|
if busno > 0 {
|
||||||
artiq_raise!("I2CError", "I2C bus could not be accessed");
|
artiq_raise!("I2CError", "I2C bus could not be accessed");
|
||||||
}
|
}
|
||||||
|
@ -15,7 +14,7 @@ pub extern "C" fn start(busno: i32) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub extern "C" fn restart(busno: i32) {
|
pub extern fn restart(busno: i32) {
|
||||||
if busno > 0 {
|
if busno > 0 {
|
||||||
artiq_raise!("I2CError", "I2C bus could not be accessed");
|
artiq_raise!("I2CError", "I2C bus could not be accessed");
|
||||||
}
|
}
|
||||||
|
@ -26,7 +25,7 @@ pub extern "C" fn restart(busno: i32) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub extern "C" fn stop(busno: i32) {
|
pub extern fn stop(busno: i32) {
|
||||||
if busno > 0 {
|
if busno > 0 {
|
||||||
artiq_raise!("I2CError", "I2C bus could not be accessed");
|
artiq_raise!("I2CError", "I2C bus could not be accessed");
|
||||||
}
|
}
|
||||||
|
@ -37,7 +36,7 @@ pub extern "C" fn stop(busno: i32) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub extern "C" fn write(busno: i32, data: i32) -> bool {
|
pub extern fn write(busno: i32, data: i32) -> bool {
|
||||||
if busno > 0 {
|
if busno > 0 {
|
||||||
artiq_raise!("I2CError", "I2C bus could not be accessed");
|
artiq_raise!("I2CError", "I2C bus could not be accessed");
|
||||||
}
|
}
|
||||||
|
@ -49,7 +48,7 @@ pub extern "C" fn write(busno: i32, data: i32) -> bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub extern "C" fn read(busno: i32, ack: bool) -> i32 {
|
pub extern fn read(busno: i32, ack: bool) -> i32 {
|
||||||
if busno > 0 {
|
if busno > 0 {
|
||||||
artiq_raise!("I2CError", "I2C bus could not be accessed");
|
artiq_raise!("I2CError", "I2C bus could not be accessed");
|
||||||
}
|
}
|
||||||
|
@ -61,12 +60,11 @@ pub extern "C" fn read(busno: i32, ack: bool) -> i32 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub extern "C" fn switch_select(busno: i32, address: i32, mask: i32) {
|
pub extern fn switch_select(busno: i32, address: i32, mask: i32) {
|
||||||
if busno > 0 {
|
if busno > 0 {
|
||||||
artiq_raise!("I2CError", "I2C bus could not be accessed");
|
artiq_raise!("I2CError", "I2C bus could not be accessed");
|
||||||
}
|
}
|
||||||
let ch = match mask {
|
let ch = match mask { //decode from mainline, PCA9548-centric API
|
||||||
//decode from mainline, PCA9548-centric API
|
|
||||||
0x00 => None,
|
0x00 => None,
|
||||||
0x01 => Some(0),
|
0x01 => Some(0),
|
||||||
0x02 => Some(1),
|
0x02 => Some(1),
|
||||||
|
@ -76,15 +74,10 @@ pub extern "C" fn switch_select(busno: i32, address: i32, mask: i32) {
|
||||||
0x20 => Some(5),
|
0x20 => Some(5),
|
||||||
0x40 => Some(6),
|
0x40 => Some(6),
|
||||||
0x80 => Some(7),
|
0x80 => Some(7),
|
||||||
_ => artiq_raise!("I2CError", "switch select supports only one channel"),
|
_ => artiq_raise!("I2CError", "switch select supports only one channel")
|
||||||
};
|
};
|
||||||
unsafe {
|
unsafe {
|
||||||
if (&mut I2C_BUS)
|
if (&mut I2C_BUS).as_mut().unwrap().pca954x_select(address as u8, ch).is_err() {
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.pca954x_select(address as u8, ch)
|
|
||||||
.is_err()
|
|
||||||
{
|
|
||||||
artiq_raise!("I2CError", "switch select failed");
|
artiq_raise!("I2CError", "switch select failed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
use core::sync::atomic::{AtomicBool, Ordering};
|
|
||||||
|
|
||||||
use libboard_zynq::{gic, mpcore, println, stdio};
|
use libboard_zynq::{gic, mpcore, println, stdio};
|
||||||
use libcortex_a9::{asm, interrupt_handler, notify_spin_lock, regs::MPIDR, spin_lock_yield};
|
use libcortex_a9::{
|
||||||
|
asm, interrupt_handler,
|
||||||
|
regs::MPIDR,
|
||||||
|
spin_lock_yield, notify_spin_lock
|
||||||
|
};
|
||||||
use libregister::RegisterR;
|
use libregister::RegisterR;
|
||||||
|
use core::sync::atomic::{AtomicBool, Ordering};
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
static mut __stack1_start: u32;
|
static mut __stack1_start: u32;
|
||||||
|
|
|
@ -1,25 +1,29 @@
|
||||||
use alloc::vec;
|
use core::ffi::VaList;
|
||||||
use core::{ffi::VaList, ptr, str};
|
use core::ptr;
|
||||||
|
use core::str;
|
||||||
use libc::{c_char, c_int, size_t};
|
use libc::{c_char, c_int, size_t};
|
||||||
use libm;
|
use libm;
|
||||||
use log::{info, warn};
|
use log::{info, warn};
|
||||||
|
|
||||||
use super::{cache,
|
use alloc::vec;
|
||||||
core1::rtio_get_destination_status,
|
|
||||||
dma,
|
use crate::eh_artiq;
|
||||||
rpc::{rpc_recv, rpc_send, rpc_send_async}};
|
use crate::rtio;
|
||||||
use crate::{eh_artiq, i2c, rtio};
|
use crate::i2c;
|
||||||
|
use super::rpc::{rpc_send, rpc_send_async, rpc_recv};
|
||||||
|
use super::dma;
|
||||||
|
use super::cache;
|
||||||
|
use super::core1::rtio_get_destination_status;
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
fn vsnprintf_(buffer: *mut c_char, count: size_t, format: *const c_char, va: VaList) -> c_int;
|
fn vsnprintf_(buffer: *mut c_char, count: size_t, format: *const c_char, va: VaList) -> c_int;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe extern "C" fn core_log(fmt: *const c_char, mut args: ...) {
|
unsafe extern fn core_log(fmt: *const c_char, mut args: ...) {
|
||||||
let size = vsnprintf_(ptr::null_mut(), 0, fmt, args.as_va_list()) as usize;
|
let size = vsnprintf_(ptr::null_mut(), 0, fmt, args.as_va_list()) as usize;
|
||||||
let mut buf = vec![0; size + 1];
|
let mut buf = vec![0; size + 1];
|
||||||
vsnprintf_(buf.as_mut_ptr() as *mut i8, size + 1, fmt, args.as_va_list());
|
vsnprintf_(buf.as_mut_ptr() as *mut i8, size + 1, fmt, args.as_va_list());
|
||||||
let buf: &[u8] = &buf.as_slice()[..size - 1]; // strip \n and NUL
|
let buf: &[u8] = &buf.as_slice()[..size-1]; // strip \n and NUL
|
||||||
match str::from_utf8(buf) {
|
match str::from_utf8(buf) {
|
||||||
Ok(s) => info!("kernel: {}", s),
|
Ok(s) => info!("kernel: {}", s),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
@ -29,13 +33,14 @@ unsafe extern "C" fn core_log(fmt: *const c_char, mut args: ...) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe extern "C" fn rtio_log(fmt: *const c_char, mut args: ...) {
|
unsafe extern fn rtio_log(fmt: *const c_char, mut args: ...) {
|
||||||
let size = vsnprintf_(ptr::null_mut(), 0, fmt, args.as_va_list()) as usize;
|
let size = vsnprintf_(ptr::null_mut(), 0, fmt, args.as_va_list()) as usize;
|
||||||
let mut buf = vec![0; size + 1];
|
let mut buf = vec![0; size + 1];
|
||||||
vsnprintf_(buf.as_mut_ptr(), size + 1, fmt, args.as_va_list());
|
vsnprintf_(buf.as_mut_ptr(), size + 1, fmt, args.as_va_list());
|
||||||
rtio::write_log(buf.as_slice());
|
rtio::write_log(buf.as_slice());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
macro_rules! api {
|
macro_rules! api {
|
||||||
($i:ident) => ({
|
($i:ident) => ({
|
||||||
extern { static $i: u8; }
|
extern { static $i: u8; }
|
||||||
|
@ -51,25 +56,24 @@ macro_rules! api {
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! api_libm_f64f64 {
|
macro_rules! api_libm_f64f64 {
|
||||||
($i:ident) => {{
|
($i:ident) => ({
|
||||||
extern "C" fn $i(x: f64) -> f64 {
|
extern fn $i(x: f64) -> f64 {
|
||||||
libm::$i(x)
|
libm::$i(x)
|
||||||
}
|
}
|
||||||
api!($i = $i)
|
api!($i = $i)
|
||||||
}};
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! api_libm_f64f64f64 {
|
macro_rules! api_libm_f64f64f64 {
|
||||||
($i:ident) => {{
|
($i:ident) => ({
|
||||||
extern "C" fn $i(x: f64, y: f64) -> f64 {
|
extern fn $i(x: f64, y: f64) -> f64 {
|
||||||
libm::$i(x, y)
|
libm::$i(x, y)
|
||||||
}
|
}
|
||||||
api!($i = $i)
|
api!($i = $i)
|
||||||
}};
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn resolve(required: &[u8]) -> Option<u32> {
|
pub fn resolve(required: &[u8]) -> Option<u32> {
|
||||||
#[rustfmt::skip]
|
|
||||||
let api = &[
|
let api = &[
|
||||||
// timing
|
// timing
|
||||||
api!(now_mu = rtio::now_mu),
|
api!(now_mu = rtio::now_mu),
|
||||||
|
@ -120,7 +124,6 @@ pub fn resolve(required: &[u8]) -> Option<u32> {
|
||||||
api!(__aeabi_ddiv),
|
api!(__aeabi_ddiv),
|
||||||
api!(__aeabi_dmul),
|
api!(__aeabi_dmul),
|
||||||
api!(__aeabi_dsub),
|
api!(__aeabi_dsub),
|
||||||
|
|
||||||
// Double-precision floating-point comparison helper functions
|
// Double-precision floating-point comparison helper functions
|
||||||
// RTABI chapter 4.1.2, Table 3
|
// RTABI chapter 4.1.2, Table 3
|
||||||
api!(__aeabi_dcmpeq),
|
api!(__aeabi_dcmpeq),
|
||||||
|
@ -130,14 +133,12 @@ pub fn resolve(required: &[u8]) -> Option<u32> {
|
||||||
api!(__aeabi_dcmpge),
|
api!(__aeabi_dcmpge),
|
||||||
api!(__aeabi_dcmpgt),
|
api!(__aeabi_dcmpgt),
|
||||||
api!(__aeabi_dcmpun),
|
api!(__aeabi_dcmpun),
|
||||||
|
|
||||||
// Single-precision floating-point arithmetic helper functions
|
// Single-precision floating-point arithmetic helper functions
|
||||||
// RTABI chapter 4.1.2, Table 4
|
// RTABI chapter 4.1.2, Table 4
|
||||||
api!(__aeabi_fadd),
|
api!(__aeabi_fadd),
|
||||||
api!(__aeabi_fdiv),
|
api!(__aeabi_fdiv),
|
||||||
api!(__aeabi_fmul),
|
api!(__aeabi_fmul),
|
||||||
api!(__aeabi_fsub),
|
api!(__aeabi_fsub),
|
||||||
|
|
||||||
// Single-precision floating-point comparison helper functions
|
// Single-precision floating-point comparison helper functions
|
||||||
// RTABI chapter 4.1.2, Table 5
|
// RTABI chapter 4.1.2, Table 5
|
||||||
api!(__aeabi_fcmpeq),
|
api!(__aeabi_fcmpeq),
|
||||||
|
@ -147,7 +148,6 @@ pub fn resolve(required: &[u8]) -> Option<u32> {
|
||||||
api!(__aeabi_fcmpge),
|
api!(__aeabi_fcmpge),
|
||||||
api!(__aeabi_fcmpgt),
|
api!(__aeabi_fcmpgt),
|
||||||
api!(__aeabi_fcmpun),
|
api!(__aeabi_fcmpun),
|
||||||
|
|
||||||
// Floating-point to integer conversions.
|
// Floating-point to integer conversions.
|
||||||
// RTABI chapter 4.1.2, Table 6
|
// RTABI chapter 4.1.2, Table 6
|
||||||
api!(__aeabi_d2iz),
|
api!(__aeabi_d2iz),
|
||||||
|
@ -158,11 +158,9 @@ pub fn resolve(required: &[u8]) -> Option<u32> {
|
||||||
api!(__aeabi_f2uiz),
|
api!(__aeabi_f2uiz),
|
||||||
api!(__aeabi_f2lz),
|
api!(__aeabi_f2lz),
|
||||||
api!(__aeabi_f2ulz),
|
api!(__aeabi_f2ulz),
|
||||||
|
|
||||||
// Conversions between floating types.
|
// Conversions between floating types.
|
||||||
// RTABI chapter 4.1.2, Table 7
|
// RTABI chapter 4.1.2, Table 7
|
||||||
api!(__aeabi_f2d),
|
api!(__aeabi_f2d),
|
||||||
|
|
||||||
// Integer to floating-point conversions.
|
// Integer to floating-point conversions.
|
||||||
// RTABI chapter 4.1.2, Table 8
|
// RTABI chapter 4.1.2, Table 8
|
||||||
api!(__aeabi_i2d),
|
api!(__aeabi_i2d),
|
||||||
|
@ -173,14 +171,12 @@ pub fn resolve(required: &[u8]) -> Option<u32> {
|
||||||
api!(__aeabi_ui2f),
|
api!(__aeabi_ui2f),
|
||||||
api!(__aeabi_l2f),
|
api!(__aeabi_l2f),
|
||||||
api!(__aeabi_ul2f),
|
api!(__aeabi_ul2f),
|
||||||
|
|
||||||
// Long long helper functions
|
// Long long helper functions
|
||||||
// RTABI chapter 4.2, Table 9
|
// RTABI chapter 4.2, Table 9
|
||||||
api!(__aeabi_lmul),
|
api!(__aeabi_lmul),
|
||||||
api!(__aeabi_llsl),
|
api!(__aeabi_llsl),
|
||||||
api!(__aeabi_llsr),
|
api!(__aeabi_llsr),
|
||||||
api!(__aeabi_lasr),
|
api!(__aeabi_lasr),
|
||||||
|
|
||||||
// Integer division functions
|
// Integer division functions
|
||||||
// RTABI chapter 4.3.1
|
// RTABI chapter 4.3.1
|
||||||
api!(__aeabi_idiv),
|
api!(__aeabi_idiv),
|
||||||
|
@ -188,7 +184,6 @@ pub fn resolve(required: &[u8]) -> Option<u32> {
|
||||||
api!(__aeabi_idivmod),
|
api!(__aeabi_idivmod),
|
||||||
api!(__aeabi_uidiv),
|
api!(__aeabi_uidiv),
|
||||||
api!(__aeabi_uldivmod),
|
api!(__aeabi_uldivmod),
|
||||||
|
|
||||||
// 4.3.4 Memory copying, clearing, and setting
|
// 4.3.4 Memory copying, clearing, and setting
|
||||||
api!(__aeabi_memcpy8),
|
api!(__aeabi_memcpy8),
|
||||||
api!(__aeabi_memcpy4),
|
api!(__aeabi_memcpy4),
|
||||||
|
@ -204,30 +199,10 @@ pub fn resolve(required: &[u8]) -> Option<u32> {
|
||||||
api!(__aeabi_memclr),
|
api!(__aeabi_memclr),
|
||||||
|
|
||||||
// libc
|
// libc
|
||||||
api!(
|
api!(memcpy, extern { fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8; }),
|
||||||
memcpy,
|
api!(memmove, extern { fn memmove(dest: *mut u8, src: *const u8, n: usize) -> *mut u8; }),
|
||||||
extern "C" {
|
api!(memset, extern { fn memset(s: *mut u8, c: i32, n: usize) -> *mut u8; }),
|
||||||
fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8;
|
api!(memcmp, extern { fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32; }),
|
||||||
}
|
|
||||||
),
|
|
||||||
api!(
|
|
||||||
memmove,
|
|
||||||
extern "C" {
|
|
||||||
fn memmove(dest: *mut u8, src: *const u8, n: usize) -> *mut u8;
|
|
||||||
}
|
|
||||||
),
|
|
||||||
api!(
|
|
||||||
memset,
|
|
||||||
extern "C" {
|
|
||||||
fn memset(s: *mut u8, c: i32, n: usize) -> *mut u8;
|
|
||||||
}
|
|
||||||
),
|
|
||||||
api!(
|
|
||||||
memcmp,
|
|
||||||
extern "C" {
|
|
||||||
fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32;
|
|
||||||
}
|
|
||||||
),
|
|
||||||
|
|
||||||
// exceptions
|
// exceptions
|
||||||
api!(_Unwind_Resume = unwind::_Unwind_Resume),
|
api!(_Unwind_Resume = unwind::_Unwind_Resume),
|
||||||
|
@ -235,7 +210,6 @@ pub fn resolve(required: &[u8]) -> Option<u32> {
|
||||||
api!(__nac3_raise = eh_artiq::raise),
|
api!(__nac3_raise = eh_artiq::raise),
|
||||||
api!(__nac3_resume = eh_artiq::resume),
|
api!(__nac3_resume = eh_artiq::resume),
|
||||||
api!(__nac3_end_catch = eh_artiq::end_catch),
|
api!(__nac3_end_catch = eh_artiq::end_catch),
|
||||||
|
|
||||||
// legacy exception symbols
|
// legacy exception symbols
|
||||||
api!(__artiq_personality = eh_artiq::artiq_personality),
|
api!(__artiq_personality = eh_artiq::artiq_personality),
|
||||||
api!(__artiq_raise = eh_artiq::raise),
|
api!(__artiq_raise = eh_artiq::raise),
|
||||||
|
@ -267,7 +241,7 @@ pub fn resolve(required: &[u8]) -> Option<u32> {
|
||||||
api_libm_f64f64!(fabs),
|
api_libm_f64f64!(fabs),
|
||||||
api_libm_f64f64!(floor),
|
api_libm_f64f64!(floor),
|
||||||
{
|
{
|
||||||
extern "C" fn fma(x: f64, y: f64, z: f64) -> f64 {
|
extern fn fma(x: f64, y: f64, z: f64) -> f64 {
|
||||||
libm::fma(x, y, z)
|
libm::fma(x, y, z)
|
||||||
}
|
}
|
||||||
api!(fma = fma)
|
api!(fma = fma)
|
||||||
|
@ -279,7 +253,7 @@ pub fn resolve(required: &[u8]) -> Option<u32> {
|
||||||
api_libm_f64f64!(j0),
|
api_libm_f64f64!(j0),
|
||||||
api_libm_f64f64!(j1),
|
api_libm_f64f64!(j1),
|
||||||
{
|
{
|
||||||
extern "C" fn jn(n: i32, x: f64) -> f64 {
|
extern fn jn(n: i32, x: f64) -> f64 {
|
||||||
libm::jn(n, x)
|
libm::jn(n, x)
|
||||||
}
|
}
|
||||||
api!(jn = jn)
|
api!(jn = jn)
|
||||||
|
@ -301,13 +275,13 @@ pub fn resolve(required: &[u8]) -> Option<u32> {
|
||||||
api_libm_f64f64!(y0),
|
api_libm_f64f64!(y0),
|
||||||
api_libm_f64f64!(y1),
|
api_libm_f64f64!(y1),
|
||||||
{
|
{
|
||||||
extern "C" fn yn(n: i32, x: f64) -> f64 {
|
extern fn yn(n: i32, x: f64) -> f64 {
|
||||||
libm::yn(n, x)
|
libm::yn(n, x)
|
||||||
}
|
}
|
||||||
api!(yn = yn)
|
api!(yn = yn)
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
api.iter()
|
api.iter()
|
||||||
.find(|&&(exported, _)| exported.as_bytes() == required)
|
.find(|&&(exported, _)| exported.as_bytes() == required)
|
||||||
.map(|&(_, ptr)| ptr as u32)
|
.map(|&(_, ptr)| ptr as u32)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,17 +1,12 @@
|
||||||
use alloc::{boxed::Box, string::String};
|
use alloc::{string::String, boxed::Box};
|
||||||
use core::mem::{forget, transmute};
|
use cslice::{CSlice, AsCSlice};
|
||||||
|
use core::mem::{transmute, forget};
|
||||||
|
use super::{KERNEL_CHANNEL_0TO1, KERNEL_CHANNEL_1TO0, Message};
|
||||||
|
|
||||||
use cslice::{AsCSlice, CSlice};
|
pub extern fn get(key: CSlice<u8>) -> &CSlice<'static, i32> {
|
||||||
|
|
||||||
use super::{Message, KERNEL_CHANNEL_0TO1, KERNEL_CHANNEL_1TO0};
|
|
||||||
|
|
||||||
pub extern "C" fn get(key: CSlice<u8>) -> &CSlice<'static, i32> {
|
|
||||||
let key = String::from_utf8(key.as_ref().to_vec()).unwrap();
|
let key = String::from_utf8(key.as_ref().to_vec()).unwrap();
|
||||||
unsafe {
|
unsafe {
|
||||||
KERNEL_CHANNEL_1TO0
|
KERNEL_CHANNEL_1TO0.as_mut().unwrap().send(Message::CacheGetRequest(key));
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.send(Message::CacheGetRequest(key));
|
|
||||||
let msg = KERNEL_CHANNEL_0TO1.as_mut().unwrap().recv();
|
let msg = KERNEL_CHANNEL_0TO1.as_mut().unwrap().recv();
|
||||||
if let Message::CacheGetReply(v) = msg {
|
if let Message::CacheGetReply(v) = msg {
|
||||||
let leaked = Box::new(v.as_c_slice());
|
let leaked = Box::new(v.as_c_slice());
|
||||||
|
@ -25,13 +20,11 @@ pub extern "C" fn get(key: CSlice<u8>) -> &CSlice<'static, i32> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub extern "C" fn put(key: CSlice<u8>, list: &CSlice<i32>) {
|
pub extern fn put(key: CSlice<u8>, list: &CSlice<i32>) {
|
||||||
let key = String::from_utf8(key.as_ref().to_vec()).unwrap();
|
let key = String::from_utf8(key.as_ref().to_vec()).unwrap();
|
||||||
let value = list.as_ref().to_vec();
|
let value = list.as_ref().to_vec();
|
||||||
unsafe {
|
unsafe {
|
||||||
KERNEL_CHANNEL_1TO0
|
KERNEL_CHANNEL_1TO0.as_mut().unwrap().send(Message::CachePutRequest(key, value));
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.send(Message::CachePutRequest(key, value));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
use core::mem::{forget, replace};
|
use libcortex_a9::sync_channel::{Sender, Receiver};
|
||||||
|
|
||||||
use libcortex_a9::sync_channel::{Receiver, Sender};
|
|
||||||
use libsupport_zynq::boot::Core1;
|
use libsupport_zynq::boot::Core1;
|
||||||
|
|
||||||
use super::{Message, CHANNEL_0TO1, CHANNEL_1TO0, CHANNEL_SEM, INIT_LOCK};
|
use super::{CHANNEL_0TO1, CHANNEL_1TO0, CHANNEL_SEM, INIT_LOCK, Message};
|
||||||
use crate::irq::restart_core1;
|
use crate::irq::restart_core1;
|
||||||
|
|
||||||
|
use core::mem::{forget, replace};
|
||||||
|
|
||||||
pub struct Control {
|
pub struct Control {
|
||||||
pub tx: Sender<'static, Message>,
|
pub tx: Sender<'static, Message>,
|
||||||
pub rx: Receiver<'static, Message>,
|
pub rx: Receiver<'static, Message>,
|
||||||
|
@ -53,3 +53,4 @@ impl Control {
|
||||||
forget(replace(&mut self.rx, core0_rx));
|
forget(replace(&mut self.rx, core0_rx));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,20 +1,31 @@
|
||||||
//! Kernel prologue/epilogue that runs on the 2nd CPU core
|
//! Kernel prologue/epilogue that runs on the 2nd CPU core
|
||||||
|
|
||||||
|
use core::{mem, ptr, cell::UnsafeCell};
|
||||||
use alloc::borrow::ToOwned;
|
use alloc::borrow::ToOwned;
|
||||||
use core::{cell::UnsafeCell, mem, ptr};
|
use log::{debug, info, error};
|
||||||
|
|
||||||
use cslice::CSlice;
|
use cslice::CSlice;
|
||||||
use dyld::{self, elf::EXIDX_Entry, Library};
|
|
||||||
use libboard_zynq::{gic, mpcore};
|
|
||||||
use libcortex_a9::{asm::{dsb, isb},
|
|
||||||
cache::{bpiall, dcci_slice, iciallu},
|
|
||||||
enable_fpu, sync_channel};
|
|
||||||
use libsupport_zynq::ram;
|
|
||||||
use log::{debug, error, info};
|
|
||||||
|
|
||||||
use super::{api::resolve, dma, rpc::rpc_send_async, Message, CHANNEL_0TO1, CHANNEL_1TO0, CHANNEL_SEM, INIT_LOCK,
|
use libcortex_a9::{
|
||||||
KERNEL_CHANNEL_0TO1, KERNEL_CHANNEL_1TO0, KERNEL_IMAGE};
|
enable_fpu,
|
||||||
|
cache::{dcci_slice, iciallu, bpiall},
|
||||||
|
asm::{dsb, isb},
|
||||||
|
sync_channel,
|
||||||
|
};
|
||||||
|
use libboard_zynq::{mpcore, gic};
|
||||||
|
use libsupport_zynq::ram;
|
||||||
|
use dyld::{self, Library, elf::EXIDX_Entry};
|
||||||
use crate::{eh_artiq, get_async_errors, rtio};
|
use crate::{eh_artiq, get_async_errors, rtio};
|
||||||
|
use super::{
|
||||||
|
api::resolve,
|
||||||
|
rpc::rpc_send_async,
|
||||||
|
INIT_LOCK,
|
||||||
|
CHANNEL_0TO1, CHANNEL_1TO0,
|
||||||
|
CHANNEL_SEM,
|
||||||
|
KERNEL_CHANNEL_0TO1, KERNEL_CHANNEL_1TO0,
|
||||||
|
KERNEL_IMAGE,
|
||||||
|
Message,
|
||||||
|
dma,
|
||||||
|
};
|
||||||
|
|
||||||
// linker symbols
|
// linker symbols
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
@ -27,13 +38,13 @@ extern "C" {
|
||||||
unsafe fn attribute_writeback(typeinfo: *const ()) {
|
unsafe fn attribute_writeback(typeinfo: *const ()) {
|
||||||
struct Attr {
|
struct Attr {
|
||||||
offset: usize,
|
offset: usize,
|
||||||
tag: CSlice<'static, u8>,
|
tag: CSlice<'static, u8>,
|
||||||
name: CSlice<'static, u8>,
|
name: CSlice<'static, u8>
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Type {
|
struct Type {
|
||||||
attributes: *const *const Attr,
|
attributes: *const *const Attr,
|
||||||
objects: *const *const (),
|
objects: *const *const ()
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut tys = typeinfo as *const *const Type;
|
let mut tys = typeinfo as *const *const Type;
|
||||||
|
@ -52,16 +63,11 @@ unsafe fn attribute_writeback(typeinfo: *const ()) {
|
||||||
attributes = attributes.offset(1);
|
attributes = attributes.offset(1);
|
||||||
|
|
||||||
if (*attribute).tag.len() > 0 {
|
if (*attribute).tag.len() > 0 {
|
||||||
rpc_send_async(
|
rpc_send_async(0, &(*attribute).tag, [
|
||||||
0,
|
&object as *const _ as *const (),
|
||||||
&(*attribute).tag,
|
&(*attribute).name as *const _ as *const (),
|
||||||
[
|
(object as usize + (*attribute).offset) as *const ()
|
||||||
&object as *const _ as *const (),
|
].as_ptr());
|
||||||
&(*attribute).name as *const _ as *const (),
|
|
||||||
(object as usize + (*attribute).offset) as *const (),
|
|
||||||
]
|
|
||||||
.as_ptr(),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -76,8 +82,7 @@ pub struct KernelImage {
|
||||||
|
|
||||||
impl KernelImage {
|
impl KernelImage {
|
||||||
pub fn new(library: Library) -> Result<Self, dyld::Error> {
|
pub fn new(library: Library) -> Result<Self, dyld::Error> {
|
||||||
let __modinit__ = library
|
let __modinit__ = library.lookup(b"__modinit__")
|
||||||
.lookup(b"__modinit__")
|
|
||||||
.ok_or(dyld::Error::Lookup("__modinit__".to_owned()))?;
|
.ok_or(dyld::Error::Lookup("__modinit__".to_owned()))?;
|
||||||
let typeinfo = library.lookup(b"typeinfo");
|
let typeinfo = library.lookup(b"typeinfo");
|
||||||
|
|
||||||
|
@ -85,7 +90,8 @@ impl KernelImage {
|
||||||
let bss_start = library.lookup(b"__bss_start");
|
let bss_start = library.lookup(b"__bss_start");
|
||||||
let end = library.lookup(b"_end");
|
let end = library.lookup(b"_end");
|
||||||
if let Some(bss_start) = bss_start {
|
if let Some(bss_start) = bss_start {
|
||||||
let end = end.ok_or(dyld::Error::Lookup("_end".to_owned()))?;
|
let end = end
|
||||||
|
.ok_or(dyld::Error::Lookup("_end".to_owned()))?;
|
||||||
unsafe {
|
unsafe {
|
||||||
ptr::write_bytes(bss_start as *mut u8, 0, (end - bss_start) as usize);
|
ptr::write_bytes(bss_start as *mut u8, 0, (end - bss_start) as usize);
|
||||||
}
|
}
|
||||||
|
@ -120,7 +126,9 @@ impl KernelImage {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_load_addr(&self) -> usize {
|
pub fn get_load_addr(&self) -> usize {
|
||||||
unsafe { self.library.get().as_ref().unwrap().image.as_ptr() as usize }
|
unsafe {
|
||||||
|
self.library.get().as_ref().unwrap().image.as_ptr() as usize
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,19 +164,20 @@ pub extern "C" fn main_core1() {
|
||||||
let message = core1_rx.recv();
|
let message = core1_rx.recv();
|
||||||
match message {
|
match message {
|
||||||
Message::LoadRequest(data) => {
|
Message::LoadRequest(data) => {
|
||||||
let result = dyld::load(&data, &resolve).and_then(KernelImage::new);
|
let result = dyld::load(&data, &resolve)
|
||||||
|
.and_then(KernelImage::new);
|
||||||
match result {
|
match result {
|
||||||
Ok(kernel) => {
|
Ok(kernel) => {
|
||||||
loaded_kernel = Some(kernel);
|
loaded_kernel = Some(kernel);
|
||||||
debug!("kernel loaded");
|
debug!("kernel loaded");
|
||||||
core1_tx.send(Message::LoadCompleted);
|
core1_tx.send(Message::LoadCompleted);
|
||||||
}
|
},
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
error!("failed to load shared library: {}", error);
|
error!("failed to load shared library: {}", error);
|
||||||
core1_tx.send(Message::LoadFailed);
|
core1_tx.send(Message::LoadFailed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
Message::StartRequest => {
|
Message::StartRequest => {
|
||||||
info!("kernel starting");
|
info!("kernel starting");
|
||||||
if let Some(kernel) = loaded_kernel.take() {
|
if let Some(kernel) = loaded_kernel.take() {
|
||||||
|
@ -193,11 +202,9 @@ pub extern "C" fn main_core1() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Called by eh_artiq
|
/// Called by eh_artiq
|
||||||
pub fn terminate(
|
pub fn terminate(exceptions: &'static [Option<eh_artiq::Exception<'static>>],
|
||||||
exceptions: &'static [Option<eh_artiq::Exception<'static>>],
|
stack_pointers: &'static [eh_artiq::StackPointerBacktrace],
|
||||||
stack_pointers: &'static [eh_artiq::StackPointerBacktrace],
|
backtrace: &'static mut [(usize, usize)]) -> ! {
|
||||||
backtrace: &'static mut [(usize, usize)],
|
|
||||||
) -> ! {
|
|
||||||
{
|
{
|
||||||
let core1_tx = unsafe { KERNEL_CHANNEL_1TO0.as_mut().unwrap() };
|
let core1_tx = unsafe { KERNEL_CHANNEL_1TO0.as_mut().unwrap() };
|
||||||
let errors = unsafe { get_async_errors() };
|
let errors = unsafe { get_async_errors() };
|
||||||
|
@ -208,34 +215,26 @@ pub fn terminate(
|
||||||
|
|
||||||
/// Called by llvm_libunwind
|
/// Called by llvm_libunwind
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
extern "C" fn dl_unwind_find_exidx(pc: *const u32, len_ptr: *mut u32) -> *const u32 {
|
extern fn dl_unwind_find_exidx(pc: *const u32, len_ptr: *mut u32) -> *const u32 {
|
||||||
let length;
|
let length;
|
||||||
let start: *const EXIDX_Entry;
|
let start: *const EXIDX_Entry;
|
||||||
unsafe {
|
unsafe {
|
||||||
if &__text_start as *const u32 <= pc && pc < &__text_end as *const u32 {
|
if &__text_start as *const u32 <= pc && pc < &__text_end as *const u32 {
|
||||||
length = (&__exidx_end as *const EXIDX_Entry).offset_from(&__exidx_start) as u32;
|
length = (&__exidx_end as *const EXIDX_Entry).offset_from(&__exidx_start) as u32;
|
||||||
start = &__exidx_start;
|
start = &__exidx_start;
|
||||||
} else if KERNEL_IMAGE != ptr::null() {
|
} else {
|
||||||
let exidx = KERNEL_IMAGE
|
let exidx = KERNEL_IMAGE.as_ref()
|
||||||
.as_ref()
|
|
||||||
.expect("dl_unwind_find_exidx kernel image")
|
.expect("dl_unwind_find_exidx kernel image")
|
||||||
.library
|
.library.get().as_ref().unwrap().exidx();
|
||||||
.get()
|
|
||||||
.as_ref()
|
|
||||||
.unwrap()
|
|
||||||
.exidx();
|
|
||||||
length = exidx.len() as u32;
|
length = exidx.len() as u32;
|
||||||
start = exidx.as_ptr();
|
start = exidx.as_ptr();
|
||||||
} else {
|
|
||||||
length = 0;
|
|
||||||
start = ptr::null();
|
|
||||||
}
|
}
|
||||||
*len_ptr = length;
|
*len_ptr = length;
|
||||||
}
|
}
|
||||||
start as *const u32
|
start as *const u32
|
||||||
}
|
}
|
||||||
|
|
||||||
pub extern "C" fn rtio_get_destination_status(destination: i32) -> bool {
|
pub extern fn rtio_get_destination_status(destination: i32) -> bool {
|
||||||
#[cfg(has_drtio)]
|
#[cfg(has_drtio)]
|
||||||
if destination > 0 && destination < 255 {
|
if destination > 0 && destination < 255 {
|
||||||
let reply = unsafe {
|
let reply = unsafe {
|
||||||
|
@ -246,9 +245,9 @@ pub extern "C" fn rtio_get_destination_status(destination: i32) -> bool {
|
||||||
};
|
};
|
||||||
return match reply {
|
return match reply {
|
||||||
Message::UpDestinationsReply(x) => x,
|
Message::UpDestinationsReply(x) => x,
|
||||||
_ => panic!("received unexpected reply to UpDestinationsRequest: {:?}", reply),
|
_ => panic!("received unexpected reply to UpDestinationsRequest: {:?}", reply)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
destination == 0
|
destination == 0
|
||||||
}
|
}
|
|
@ -1,15 +1,21 @@
|
||||||
use alloc::{string::String, vec::Vec};
|
use crate::{
|
||||||
|
pl::csr,
|
||||||
|
artiq_raise,
|
||||||
|
rtio,
|
||||||
|
};
|
||||||
|
use alloc::{vec::Vec, string::String, boxed::Box};
|
||||||
|
use cslice::CSlice;
|
||||||
|
use super::{KERNEL_IMAGE, KERNEL_CHANNEL_0TO1, KERNEL_CHANNEL_1TO0, Message};
|
||||||
use core::mem;
|
use core::mem;
|
||||||
|
|
||||||
use cslice::CSlice;
|
use libcortex_a9::cache::dcci_slice;
|
||||||
|
|
||||||
use super::{Message, KERNEL_CHANNEL_0TO1, KERNEL_CHANNEL_1TO0, KERNEL_IMAGE};
|
const ALIGNMENT: usize = 16 * 8;
|
||||||
use crate::{artiq_raise, pl::csr, rtio};
|
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct DmaTrace {
|
pub struct DmaTrace {
|
||||||
duration: i64,
|
duration: i64,
|
||||||
address: i32,
|
address: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
@ -17,7 +23,6 @@ pub struct DmaRecorder {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub buffer: Vec<u8>,
|
pub buffer: Vec<u8>,
|
||||||
pub duration: i64,
|
pub duration: i64,
|
||||||
pub enable_ddma: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static mut RECORDER: Option<DmaRecorder> = None;
|
static mut RECORDER: Option<DmaRecorder> = None;
|
||||||
|
@ -28,13 +33,10 @@ pub unsafe fn init_dma_recorder() {
|
||||||
mem::forget(mem::replace(&mut RECORDER, None));
|
mem::forget(mem::replace(&mut RECORDER, None));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub extern "C" fn dma_record_start(name: CSlice<u8>) {
|
pub extern fn dma_record_start(name: CSlice<u8>) {
|
||||||
let name = String::from_utf8(name.as_ref().to_vec()).unwrap();
|
let name = String::from_utf8(name.as_ref().to_vec()).unwrap();
|
||||||
unsafe {
|
unsafe {
|
||||||
KERNEL_CHANNEL_1TO0
|
KERNEL_CHANNEL_1TO0.as_mut().unwrap().send(Message::DmaEraseRequest(name.clone()));
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.send(Message::DmaEraseRequest(name.clone()));
|
|
||||||
}
|
}
|
||||||
unsafe {
|
unsafe {
|
||||||
if RECORDER.is_some() {
|
if RECORDER.is_some() {
|
||||||
|
@ -42,44 +44,42 @@ pub extern "C" fn dma_record_start(name: CSlice<u8>) {
|
||||||
}
|
}
|
||||||
|
|
||||||
let library = KERNEL_IMAGE.as_ref().unwrap();
|
let library = KERNEL_IMAGE.as_ref().unwrap();
|
||||||
library.rebind(b"rtio_output", dma_record_output as *const ()).unwrap();
|
library.rebind(b"rtio_output",
|
||||||
library
|
dma_record_output as *const ()).unwrap();
|
||||||
.rebind(b"rtio_output_wide", dma_record_output_wide as *const ())
|
library.rebind(b"rtio_output_wide",
|
||||||
.unwrap();
|
dma_record_output_wide as *const ()).unwrap();
|
||||||
|
|
||||||
RECORDER = Some(DmaRecorder {
|
RECORDER = Some(DmaRecorder {
|
||||||
name,
|
name,
|
||||||
buffer: Vec::new(),
|
buffer: Vec::new(),
|
||||||
duration: 0,
|
duration: 0,
|
||||||
enable_ddma: false,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub extern "C" fn dma_record_stop(duration: i64, enable_ddma: bool) {
|
pub extern fn dma_record_stop(duration: i64) {
|
||||||
unsafe {
|
unsafe {
|
||||||
if RECORDER.is_none() {
|
if RECORDER.is_none() {
|
||||||
artiq_raise!("DMAError", "DMA is not recording")
|
artiq_raise!("DMAError", "DMA is not recording")
|
||||||
}
|
}
|
||||||
|
|
||||||
let library = KERNEL_IMAGE.as_ref().unwrap();
|
let library = KERNEL_IMAGE.as_ref().unwrap();
|
||||||
library.rebind(b"rtio_output", rtio::output as *const ()).unwrap();
|
library.rebind(b"rtio_output",
|
||||||
library
|
rtio::output as *const ()).unwrap();
|
||||||
.rebind(b"rtio_output_wide", rtio::output_wide as *const ())
|
library.rebind(b"rtio_output_wide",
|
||||||
.unwrap();
|
rtio::output_wide as *const ()).unwrap();
|
||||||
|
|
||||||
let mut recorder = RECORDER.take().unwrap();
|
let mut recorder = RECORDER.take().unwrap();
|
||||||
recorder.duration = duration;
|
recorder.duration = duration;
|
||||||
recorder.enable_ddma = enable_ddma;
|
KERNEL_CHANNEL_1TO0.as_mut().unwrap().send(
|
||||||
KERNEL_CHANNEL_1TO0
|
Message::DmaPutRequest(recorder)
|
||||||
.as_mut()
|
);
|
||||||
.unwrap()
|
|
||||||
.send(Message::DmaPutRequest(recorder));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
unsafe fn dma_record_output_prepare(timestamp: i64, target: i32, words: usize) {
|
unsafe fn dma_record_output_prepare(timestamp: i64, target: i32,
|
||||||
|
words: usize) {
|
||||||
// See gateware/rtio/dma.py.
|
// See gateware/rtio/dma.py.
|
||||||
const HEADER_LENGTH: usize = /*length*/1 + /*channel*/3 + /*timestamp*/8 + /*address*/1;
|
const HEADER_LENGTH: usize = /*length*/1 + /*channel*/3 + /*timestamp*/8 + /*address*/1;
|
||||||
let length = HEADER_LENGTH + /*data*/words * 4;
|
let length = HEADER_LENGTH + /*data*/words * 4;
|
||||||
|
@ -87,36 +87,36 @@ unsafe fn dma_record_output_prepare(timestamp: i64, target: i32, words: usize) {
|
||||||
let buffer = &mut RECORDER.as_mut().unwrap().buffer;
|
let buffer = &mut RECORDER.as_mut().unwrap().buffer;
|
||||||
buffer.reserve(length);
|
buffer.reserve(length);
|
||||||
buffer.extend_from_slice(&[
|
buffer.extend_from_slice(&[
|
||||||
(length >> 0) as u8,
|
(length >> 0) as u8,
|
||||||
(target >> 8) as u8,
|
(target >> 8) as u8,
|
||||||
(target >> 16) as u8,
|
(target >> 16) as u8,
|
||||||
(target >> 24) as u8,
|
(target >> 24) as u8,
|
||||||
(timestamp >> 0) as u8,
|
(timestamp >> 0) as u8,
|
||||||
(timestamp >> 8) as u8,
|
(timestamp >> 8) as u8,
|
||||||
(timestamp >> 16) as u8,
|
(timestamp >> 16) as u8,
|
||||||
(timestamp >> 24) as u8,
|
(timestamp >> 24) as u8,
|
||||||
(timestamp >> 32) as u8,
|
(timestamp >> 32) as u8,
|
||||||
(timestamp >> 40) as u8,
|
(timestamp >> 40) as u8,
|
||||||
(timestamp >> 48) as u8,
|
(timestamp >> 48) as u8,
|
||||||
(timestamp >> 56) as u8,
|
(timestamp >> 56) as u8,
|
||||||
(target >> 0) as u8,
|
(target >> 0) as u8,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub extern "C" fn dma_record_output(target: i32, word: i32) {
|
pub extern fn dma_record_output(target: i32, word: i32) {
|
||||||
unsafe {
|
unsafe {
|
||||||
let timestamp = rtio::now_mu();
|
let timestamp = rtio::now_mu();
|
||||||
dma_record_output_prepare(timestamp, target, 1);
|
dma_record_output_prepare(timestamp, target, 1);
|
||||||
RECORDER.as_mut().unwrap().buffer.extend_from_slice(&[
|
RECORDER.as_mut().unwrap().buffer.extend_from_slice(&[
|
||||||
(word >> 0) as u8,
|
(word >> 0) as u8,
|
||||||
(word >> 8) as u8,
|
(word >> 8) as u8,
|
||||||
(word >> 16) as u8,
|
(word >> 16) as u8,
|
||||||
(word >> 24) as u8,
|
(word >> 24) as u8,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub extern "C" fn dma_record_output_wide(target: i32, words: CSlice<i32>) {
|
pub extern fn dma_record_output_wide(target: i32, words: CSlice<i32>) {
|
||||||
assert!(words.len() <= 16); // enforce the hardware limit
|
assert!(words.len() <= 16); // enforce the hardware limit
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -125,8 +125,8 @@ pub extern "C" fn dma_record_output_wide(target: i32, words: CSlice<i32>) {
|
||||||
let buffer = &mut RECORDER.as_mut().unwrap().buffer;
|
let buffer = &mut RECORDER.as_mut().unwrap().buffer;
|
||||||
for word in words.as_ref().iter() {
|
for word in words.as_ref().iter() {
|
||||||
buffer.extend_from_slice(&[
|
buffer.extend_from_slice(&[
|
||||||
(word >> 0) as u8,
|
(word >> 0) as u8,
|
||||||
(word >> 8) as u8,
|
(word >> 8) as u8,
|
||||||
(word >> 16) as u8,
|
(word >> 16) as u8,
|
||||||
(word >> 24) as u8,
|
(word >> 24) as u8,
|
||||||
]);
|
]);
|
||||||
|
@ -134,114 +134,79 @@ pub extern "C" fn dma_record_output_wide(target: i32, words: CSlice<i32>) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub extern "C" fn dma_erase(name: CSlice<u8>) {
|
pub extern fn dma_erase(name: CSlice<u8>) {
|
||||||
let name = String::from_utf8(name.as_ref().to_vec()).unwrap();
|
let name = String::from_utf8(name.as_ref().to_vec()).unwrap();
|
||||||
unsafe {
|
unsafe {
|
||||||
KERNEL_CHANNEL_1TO0
|
KERNEL_CHANNEL_1TO0.as_mut().unwrap().send(Message::DmaEraseRequest(name));
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.send(Message::DmaEraseRequest(name));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub extern "C" fn dma_retrieve(name: CSlice<u8>) -> DmaTrace {
|
pub extern fn dma_retrieve(name: CSlice<u8>) -> DmaTrace {
|
||||||
let name = String::from_utf8(name.as_ref().to_vec()).unwrap();
|
let name = String::from_utf8(name.as_ref().to_vec()).unwrap();
|
||||||
unsafe {
|
unsafe {
|
||||||
KERNEL_CHANNEL_1TO0.as_mut().unwrap().send(Message::DmaGetRequest(name));
|
KERNEL_CHANNEL_1TO0.as_mut().unwrap().send(Message::DmaGetRequest(name));
|
||||||
}
|
}
|
||||||
match unsafe { KERNEL_CHANNEL_0TO1.as_mut().unwrap() }.recv() {
|
match unsafe {KERNEL_CHANNEL_0TO1.as_mut().unwrap()}.recv() {
|
||||||
Message::DmaGetReply(None) => (),
|
Message::DmaGetReply(None) => (),
|
||||||
Message::DmaGetReply(Some((address, duration))) => {
|
Message::DmaGetReply(Some((mut v, duration))) => {
|
||||||
return DmaTrace { address, duration };
|
v.reserve(ALIGNMENT - 1);
|
||||||
}
|
let original_length = v.len();
|
||||||
|
let padding = ALIGNMENT - v.as_ptr() as usize % ALIGNMENT;
|
||||||
|
let padding = if padding == ALIGNMENT { 0 } else { padding };
|
||||||
|
for _ in 0..padding {
|
||||||
|
v.push(0);
|
||||||
|
}
|
||||||
|
// trailing zero to indicate end of buffer
|
||||||
|
v.push(0);
|
||||||
|
v.copy_within(0..original_length, padding);
|
||||||
|
dcci_slice(&v);
|
||||||
|
let v = Box::new(v);
|
||||||
|
let address = Box::into_raw(v) as *mut Vec<u8> as i32;
|
||||||
|
return DmaTrace {
|
||||||
|
address,
|
||||||
|
duration,
|
||||||
|
};
|
||||||
|
},
|
||||||
_ => panic!("Expected DmaGetReply after DmaGetRequest!"),
|
_ => panic!("Expected DmaGetReply after DmaGetRequest!"),
|
||||||
}
|
}
|
||||||
// we have to defer raising error as we have to drop the message first...
|
// we have to defer raising error as we have to drop the message first...
|
||||||
artiq_raise!("DMAError", "DMA trace not found");
|
artiq_raise!("DMAError", "DMA trace not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
pub extern "C" fn dma_playback(timestamp: i64, ptr: i32) {
|
pub extern fn dma_playback(timestamp: i64, ptr: i32) {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
let v = Box::from_raw(ptr as *mut Vec<u8>);
|
||||||
|
let padding = ALIGNMENT - v.as_ptr() as usize % ALIGNMENT;
|
||||||
|
let padding = if padding == ALIGNMENT { 0 } else { padding };
|
||||||
|
let ptr = v.as_ptr().add(padding) as i32;
|
||||||
|
|
||||||
csr::rtio_dma::base_address_write(ptr as u32);
|
csr::rtio_dma::base_address_write(ptr as u32);
|
||||||
csr::rtio_dma::time_offset_write(timestamp as u64);
|
csr::rtio_dma::time_offset_write(timestamp as u64);
|
||||||
|
|
||||||
csr::cri_con::selected_write(1);
|
csr::cri_con::selected_write(1);
|
||||||
csr::rtio_dma::enable_write(1);
|
csr::rtio_dma::enable_write(1);
|
||||||
#[cfg(has_drtio)]
|
|
||||||
KERNEL_CHANNEL_1TO0
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.send(Message::DmaStartRemoteRequest {
|
|
||||||
id: ptr,
|
|
||||||
timestamp: timestamp,
|
|
||||||
});
|
|
||||||
while csr::rtio_dma::enable_read() != 0 {}
|
while csr::rtio_dma::enable_read() != 0 {}
|
||||||
csr::cri_con::selected_write(0);
|
csr::cri_con::selected_write(0);
|
||||||
|
|
||||||
|
// leave the handle as we may try to do playback for another time.
|
||||||
|
mem::forget(v);
|
||||||
|
|
||||||
let error = csr::rtio_dma::error_read();
|
let error = csr::rtio_dma::error_read();
|
||||||
if error != 0 {
|
if error != 0 {
|
||||||
let timestamp = csr::rtio_dma::error_timestamp_read();
|
let timestamp = csr::rtio_dma::error_timestamp_read();
|
||||||
let channel = csr::rtio_dma::error_channel_read();
|
let channel = csr::rtio_dma::error_channel_read();
|
||||||
csr::rtio_dma::error_write(1);
|
csr::rtio_dma::error_write(1);
|
||||||
if error & 1 != 0 {
|
if error & 1 != 0 {
|
||||||
artiq_raise!(
|
artiq_raise!("RTIOUnderflow",
|
||||||
"RTIOUnderflow",
|
"RTIO underflow at {0} mu, channel {1}",
|
||||||
"RTIO underflow at {1} mu, channel {rtio_channel_info:0}",
|
timestamp as i64, channel as i64, 0);
|
||||||
channel as i64,
|
|
||||||
timestamp as i64,
|
|
||||||
0
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
if error & 2 != 0 {
|
if error & 2 != 0 {
|
||||||
artiq_raise!(
|
artiq_raise!("RTIODestinationUnreachable",
|
||||||
"RTIODestinationUnreachable",
|
"RTIO destination unreachable, output, at {0} mu, channel {1}",
|
||||||
"RTIO destination unreachable, output, at {1} mu, channel {rtio_channel_info:0}",
|
timestamp as i64, channel as i64, 0);
|
||||||
channel as i64,
|
|
||||||
timestamp as i64,
|
|
||||||
0
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[cfg(has_drtio)]
|
|
||||||
{
|
|
||||||
KERNEL_CHANNEL_1TO0
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.send(Message::DmaAwaitRemoteRequest(ptr));
|
|
||||||
match KERNEL_CHANNEL_0TO1.as_mut().unwrap().recv() {
|
|
||||||
Message::DmaAwaitRemoteReply {
|
|
||||||
timeout,
|
|
||||||
error,
|
|
||||||
channel,
|
|
||||||
timestamp,
|
|
||||||
} => {
|
|
||||||
if timeout {
|
|
||||||
artiq_raise!(
|
|
||||||
"DMAError",
|
|
||||||
"Error running DMA on satellite device, timed out waiting for results"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if error & 1 != 0 {
|
|
||||||
artiq_raise!(
|
|
||||||
"RTIOUnderflow",
|
|
||||||
"RTIO underflow at {1} mu, channel {rtio_channel_info:0}",
|
|
||||||
channel as i64,
|
|
||||||
timestamp as i64,
|
|
||||||
0
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if error & 2 != 0 {
|
|
||||||
artiq_raise!(
|
|
||||||
"RTIODestinationUnreachable",
|
|
||||||
"RTIO destination unreachable, output, at {1} mu, channel {rtio_channel_info:0}",
|
|
||||||
channel as i64,
|
|
||||||
timestamp as i64,
|
|
||||||
0
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => panic!("Expected DmaAwaitRemoteReply after DmaAwaitRemoteRequest!"),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,16 +1,15 @@
|
||||||
use alloc::{string::String, vec::Vec};
|
|
||||||
use core::ptr;
|
use core::ptr;
|
||||||
|
use alloc::{vec::Vec, string::String};
|
||||||
|
|
||||||
use libcortex_a9::{mutex::Mutex, semaphore::Semaphore, sync_channel};
|
use libcortex_a9::{mutex::Mutex, sync_channel, semaphore::Semaphore};
|
||||||
|
|
||||||
use crate::eh_artiq;
|
use crate::eh_artiq;
|
||||||
|
|
||||||
mod control;
|
mod control;
|
||||||
pub use control::Control;
|
pub use control::Control;
|
||||||
mod api;
|
|
||||||
pub mod core1;
|
pub mod core1;
|
||||||
mod dma;
|
mod api;
|
||||||
mod rpc;
|
mod rpc;
|
||||||
|
mod dma;
|
||||||
pub use dma::DmaRecorder;
|
pub use dma::DmaRecorder;
|
||||||
mod cache;
|
mod cache;
|
||||||
|
|
||||||
|
@ -22,7 +21,7 @@ pub struct RPCException {
|
||||||
pub file: u32,
|
pub file: u32,
|
||||||
pub line: i32,
|
pub line: i32,
|
||||||
pub column: i32,
|
pub column: i32,
|
||||||
pub function: u32,
|
pub function: u32
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
@ -32,16 +31,11 @@ pub enum Message {
|
||||||
LoadFailed,
|
LoadFailed,
|
||||||
StartRequest,
|
StartRequest,
|
||||||
KernelFinished(u8),
|
KernelFinished(u8),
|
||||||
KernelException(
|
KernelException(&'static [Option<eh_artiq::Exception<'static>>],
|
||||||
&'static [Option<eh_artiq::Exception<'static>>],
|
&'static [eh_artiq::StackPointerBacktrace],
|
||||||
&'static [eh_artiq::StackPointerBacktrace],
|
&'static [(usize, usize)],
|
||||||
&'static [(usize, usize)],
|
u8),
|
||||||
u8,
|
RpcSend { is_async: bool, data: Vec<u8> },
|
||||||
),
|
|
||||||
RpcSend {
|
|
||||||
is_async: bool,
|
|
||||||
data: Vec<u8>,
|
|
||||||
},
|
|
||||||
RpcRecvRequest(*mut ()),
|
RpcRecvRequest(*mut ()),
|
||||||
RpcRecvReply(Result<usize, RPCException>),
|
RpcRecvReply(Result<usize, RPCException>),
|
||||||
|
|
||||||
|
@ -52,21 +46,7 @@ pub enum Message {
|
||||||
DmaPutRequest(DmaRecorder),
|
DmaPutRequest(DmaRecorder),
|
||||||
DmaEraseRequest(String),
|
DmaEraseRequest(String),
|
||||||
DmaGetRequest(String),
|
DmaGetRequest(String),
|
||||||
DmaGetReply(Option<(i32, i64)>),
|
DmaGetReply(Option<(Vec<u8>, i64)>),
|
||||||
#[cfg(has_drtio)]
|
|
||||||
DmaStartRemoteRequest {
|
|
||||||
id: i32,
|
|
||||||
timestamp: i64,
|
|
||||||
},
|
|
||||||
#[cfg(has_drtio)]
|
|
||||||
DmaAwaitRemoteRequest(i32),
|
|
||||||
#[cfg(has_drtio)]
|
|
||||||
DmaAwaitRemoteReply {
|
|
||||||
timeout: bool,
|
|
||||||
error: u8,
|
|
||||||
channel: u32,
|
|
||||||
timestamp: u64,
|
|
||||||
},
|
|
||||||
|
|
||||||
#[cfg(has_drtio)]
|
#[cfg(has_drtio)]
|
||||||
UpDestinationsRequest(i32),
|
UpDestinationsRequest(i32),
|
||||||
|
@ -84,3 +64,4 @@ static mut KERNEL_CHANNEL_1TO0: Option<sync_channel::Sender<'static, Message>> =
|
||||||
pub static mut KERNEL_IMAGE: *const core1::KernelImage = ptr::null();
|
pub static mut KERNEL_IMAGE: *const core1::KernelImage = ptr::null();
|
||||||
|
|
||||||
static INIT_LOCK: Mutex<()> = Mutex::new(());
|
static INIT_LOCK: Mutex<()> = Mutex::new(());
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
//! Kernel-side RPC API
|
//! Kernel-side RPC API
|
||||||
|
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
|
|
||||||
use cslice::CSlice;
|
use cslice::CSlice;
|
||||||
|
|
||||||
use super::{Message, KERNEL_CHANNEL_0TO1, KERNEL_CHANNEL_1TO0};
|
use crate::eh_artiq;
|
||||||
use crate::{eh_artiq, rpc::send_args};
|
use crate::rpc::send_args;
|
||||||
|
use super::{
|
||||||
|
KERNEL_CHANNEL_0TO1, KERNEL_CHANNEL_1TO0,
|
||||||
|
Message,
|
||||||
|
};
|
||||||
|
|
||||||
fn rpc_send_common(is_async: bool, service: u32, tag: &CSlice<u8>, data: *const *const ()) {
|
fn rpc_send_common(is_async: bool, service: u32, tag: &CSlice<u8>, data: *const *const ()) {
|
||||||
let core1_tx = unsafe { KERNEL_CHANNEL_1TO0.as_mut().unwrap() };
|
let core1_tx = unsafe { KERNEL_CHANNEL_1TO0.as_mut().unwrap() };
|
||||||
|
@ -14,15 +17,15 @@ fn rpc_send_common(is_async: bool, service: u32, tag: &CSlice<u8>, data: *const
|
||||||
core1_tx.send(Message::RpcSend { is_async, data: buffer });
|
core1_tx.send(Message::RpcSend { is_async, data: buffer });
|
||||||
}
|
}
|
||||||
|
|
||||||
pub extern "C" fn rpc_send(service: u32, tag: &CSlice<u8>, data: *const *const ()) {
|
pub extern fn rpc_send(service: u32, tag: &CSlice<u8>, data: *const *const ()) {
|
||||||
rpc_send_common(false, service, tag, data);
|
rpc_send_common(false, service, tag, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub extern "C" fn rpc_send_async(service: u32, tag: &CSlice<u8>, data: *const *const ()) {
|
pub extern fn rpc_send_async(service: u32, tag: &CSlice<u8>, data: *const *const ()) {
|
||||||
rpc_send_common(true, service, tag, data);
|
rpc_send_common(true, service, tag, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub extern "C" fn rpc_recv(slot: *mut ()) -> usize {
|
pub extern fn rpc_recv(slot: *mut ()) -> usize {
|
||||||
let reply = unsafe {
|
let reply = unsafe {
|
||||||
let core1_rx = KERNEL_CHANNEL_0TO1.as_mut().unwrap();
|
let core1_rx = KERNEL_CHANNEL_0TO1.as_mut().unwrap();
|
||||||
let core1_tx = KERNEL_CHANNEL_1TO0.as_mut().unwrap();
|
let core1_tx = KERNEL_CHANNEL_1TO0.as_mut().unwrap();
|
||||||
|
@ -33,15 +36,15 @@ pub extern "C" fn rpc_recv(slot: *mut ()) -> usize {
|
||||||
Message::RpcRecvReply(Ok(alloc_size)) => alloc_size,
|
Message::RpcRecvReply(Ok(alloc_size)) => alloc_size,
|
||||||
Message::RpcRecvReply(Err(exception)) => unsafe {
|
Message::RpcRecvReply(Err(exception)) => unsafe {
|
||||||
eh_artiq::raise(&eh_artiq::Exception {
|
eh_artiq::raise(&eh_artiq::Exception {
|
||||||
id: exception.id,
|
id: exception.id,
|
||||||
file: CSlice::new(exception.file as *const u8, usize::MAX),
|
file: CSlice::new(exception.file as *const u8, usize::MAX),
|
||||||
line: exception.line as u32,
|
line: exception.line as u32,
|
||||||
column: exception.column as u32,
|
column: exception.column as u32,
|
||||||
function: CSlice::new(exception.function as *const u8, usize::MAX),
|
function: CSlice::new(exception.function as *const u8, usize::MAX),
|
||||||
message: CSlice::new(exception.message as *const u8, usize::MAX),
|
message: CSlice::new(exception.message as *const u8, usize::MAX),
|
||||||
param: exception.param,
|
param: exception.param
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
_ => panic!("received unexpected reply to RpcRecvRequest: {:?}", reply),
|
_ => panic!("received unexpected reply to RpcRecvRequest: {:?}", reply)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![recursion_limit = "1024"] // for futures_util::select!
|
#![recursion_limit="1024"] // for futures_util::select!
|
||||||
#![feature(alloc_error_handler)]
|
#![feature(alloc_error_handler)]
|
||||||
#![feature(panic_info_message)]
|
#![feature(panic_info_message)]
|
||||||
#![feature(c_variadic)]
|
#![feature(c_variadic)]
|
||||||
|
@ -9,35 +9,27 @@
|
||||||
#![feature(naked_functions)]
|
#![feature(naked_functions)]
|
||||||
#![feature(asm)]
|
#![feature(asm)]
|
||||||
|
|
||||||
#[macro_use]
|
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
use libasync::{block_async, task};
|
use log::{info, warn, error};
|
||||||
#[cfg(feature = "target_kasli_soc")]
|
|
||||||
use libboard_artiq::io_expander;
|
use libboard_zynq::{timer::GlobalTimer, mpcore, gic};
|
||||||
use libboard_artiq::{identifier_read, logger, pl};
|
use libasync::{task, block_async};
|
||||||
use libboard_zynq::{gic, mpcore, timer::GlobalTimer};
|
|
||||||
use libconfig::Config;
|
|
||||||
use libcortex_a9::l2c::enable_l2_cache;
|
|
||||||
use libsupport_zynq::ram;
|
use libsupport_zynq::ram;
|
||||||
use log::{error, info, warn};
|
|
||||||
use nb;
|
use nb;
|
||||||
use void::Void;
|
use void::Void;
|
||||||
|
use libconfig::Config;
|
||||||
|
use libcortex_a9::l2c::enable_l2_cache;
|
||||||
|
use libboard_artiq::{logger, identifier_read, init_gateware, pl};
|
||||||
|
#[cfg(feature = "target_kasli_soc")]
|
||||||
|
use libboard_artiq::io_expander;
|
||||||
|
|
||||||
const ASYNC_ERROR_COLLISION: u8 = 1 << 0;
|
const ASYNC_ERROR_COLLISION: u8 = 1 << 0;
|
||||||
const ASYNC_ERROR_BUSY: u8 = 1 << 1;
|
const ASYNC_ERROR_BUSY: u8 = 1 << 1;
|
||||||
const ASYNC_ERROR_SEQUENCE_ERROR: u8 = 1 << 2;
|
const ASYNC_ERROR_SEQUENCE_ERROR: u8 = 1 << 2;
|
||||||
|
|
||||||
mod analyzer;
|
|
||||||
mod comms;
|
|
||||||
mod eh_artiq;
|
|
||||||
mod i2c;
|
|
||||||
mod irq;
|
|
||||||
mod kernel;
|
|
||||||
mod mgmt;
|
|
||||||
mod moninj;
|
|
||||||
mod panic;
|
|
||||||
mod proto_async;
|
mod proto_async;
|
||||||
|
mod comms;
|
||||||
mod rpc;
|
mod rpc;
|
||||||
#[cfg(ki_impl = "csr")]
|
#[cfg(ki_impl = "csr")]
|
||||||
#[path = "rtio_csr.rs"]
|
#[path = "rtio_csr.rs"]
|
||||||
|
@ -45,9 +37,16 @@ mod rtio;
|
||||||
#[cfg(ki_impl = "acp")]
|
#[cfg(ki_impl = "acp")]
|
||||||
#[path = "rtio_acp.rs"]
|
#[path = "rtio_acp.rs"]
|
||||||
mod rtio;
|
mod rtio;
|
||||||
mod rtio_clocking;
|
|
||||||
mod rtio_dma;
|
|
||||||
mod rtio_mgt;
|
mod rtio_mgt;
|
||||||
|
mod rtio_clocking;
|
||||||
|
mod kernel;
|
||||||
|
mod moninj;
|
||||||
|
mod eh_artiq;
|
||||||
|
mod panic;
|
||||||
|
mod mgmt;
|
||||||
|
mod analyzer;
|
||||||
|
mod irq;
|
||||||
|
mod i2c;
|
||||||
|
|
||||||
static mut SEEN_ASYNC_ERRORS: u8 = 0;
|
static mut SEEN_ASYNC_ERRORS: u8 = 0;
|
||||||
|
|
||||||
|
@ -73,28 +72,16 @@ async fn report_async_rtio_errors() {
|
||||||
unsafe {
|
unsafe {
|
||||||
let errors = pl::csr::rtio_core::async_error_read();
|
let errors = pl::csr::rtio_core::async_error_read();
|
||||||
if errors & ASYNC_ERROR_COLLISION != 0 {
|
if errors & ASYNC_ERROR_COLLISION != 0 {
|
||||||
let channel = pl::csr::rtio_core::collision_channel_read();
|
error!("RTIO collision involving channel {}",
|
||||||
error!(
|
pl::csr::rtio_core::collision_channel_read());
|
||||||
"RTIO collision involving channel 0x{:04x}:{}",
|
|
||||||
channel,
|
|
||||||
rtio_mgt::resolve_channel_name(channel as u32)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
if errors & ASYNC_ERROR_BUSY != 0 {
|
if errors & ASYNC_ERROR_BUSY != 0 {
|
||||||
let channel = pl::csr::rtio_core::busy_channel_read();
|
error!("RTIO busy error involving channel {}",
|
||||||
error!(
|
pl::csr::rtio_core::busy_channel_read());
|
||||||
"RTIO busy error involving channel 0x{:04x}:{}",
|
|
||||||
channel,
|
|
||||||
rtio_mgt::resolve_channel_name(channel as u32)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
if errors & ASYNC_ERROR_SEQUENCE_ERROR != 0 {
|
if errors & ASYNC_ERROR_SEQUENCE_ERROR != 0 {
|
||||||
let channel = pl::csr::rtio_core::sequence_error_channel_read();
|
error!("RTIO sequence error involving channel {}",
|
||||||
error!(
|
pl::csr::rtio_core::sequence_error_channel_read());
|
||||||
"RTIO sequence error involving channel 0x{:04x}:{}",
|
|
||||||
channel,
|
|
||||||
rtio_mgt::resolve_channel_name(channel as u32)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
SEEN_ASYNC_ERRORS = errors;
|
SEEN_ASYNC_ERRORS = errors;
|
||||||
pl::csr::rtio_core::async_error_write(errors);
|
pl::csr::rtio_core::async_error_write(errors);
|
||||||
|
@ -102,14 +89,18 @@ async fn report_async_rtio_errors() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static mut LOG_BUFFER: [u8; 1 << 17] = [0; 1 << 17];
|
|
||||||
|
|
||||||
|
static mut LOG_BUFFER: [u8; 1<<17] = [0; 1<<17];
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub fn main_core0() {
|
pub fn main_core0() {
|
||||||
enable_l2_cache(0x8);
|
enable_l2_cache(0x8);
|
||||||
let mut timer = GlobalTimer::start();
|
let mut timer = GlobalTimer::start();
|
||||||
|
|
||||||
let buffer_logger = unsafe { logger::BufferLogger::new(&mut LOG_BUFFER[..]) };
|
let buffer_logger = unsafe {
|
||||||
|
logger::BufferLogger::new(&mut LOG_BUFFER[..])
|
||||||
|
};
|
||||||
buffer_logger.set_uart_log_level(log::LevelFilter::Info);
|
buffer_logger.set_uart_log_level(log::LevelFilter::Info);
|
||||||
buffer_logger.register();
|
buffer_logger.register();
|
||||||
log::set_max_level(log::LevelFilter::Info);
|
log::set_max_level(log::LevelFilter::Info);
|
||||||
|
@ -119,6 +110,7 @@ pub fn main_core0() {
|
||||||
ram::init_alloc_core0();
|
ram::init_alloc_core0();
|
||||||
gic::InterruptController::gic(mpcore::RegisterBlock::mpcore()).enable_interrupts();
|
gic::InterruptController::gic(mpcore::RegisterBlock::mpcore()).enable_interrupts();
|
||||||
|
|
||||||
|
init_gateware();
|
||||||
info!("gateware ident: {}", identifier_read(&mut [0; 64]));
|
info!("gateware ident: {}", identifier_read(&mut [0; 64]));
|
||||||
|
|
||||||
i2c::init();
|
i2c::init();
|
||||||
|
|
|
@ -1,17 +1,16 @@
|
||||||
use alloc::{rc::Rc, string::String, vec::Vec};
|
|
||||||
use core::cell::RefCell;
|
|
||||||
|
|
||||||
use futures::{future::poll_fn, task::Poll};
|
use futures::{future::poll_fn, task::Poll};
|
||||||
use libasync::{smoltcp::TcpStream, task};
|
use libasync::{smoltcp::TcpStream, task};
|
||||||
use libboard_artiq::logger::{BufferLogger, LogBufferRef};
|
use libboard_zynq::smoltcp;
|
||||||
use libboard_zynq::{slcr, smoltcp};
|
|
||||||
use libconfig::Config;
|
use libconfig::Config;
|
||||||
use log::{self, debug, error, info, warn, LevelFilter};
|
use core::cell::RefCell;
|
||||||
|
use alloc::{rc::Rc, vec::Vec, string::String};
|
||||||
|
use log::{self, info, debug, warn, error, LevelFilter};
|
||||||
|
|
||||||
|
use libboard_artiq::logger::{BufferLogger, LogBufferRef};
|
||||||
|
use crate::proto_async::*;
|
||||||
use num_derive::FromPrimitive;
|
use num_derive::FromPrimitive;
|
||||||
use num_traits::FromPrimitive;
|
use num_traits::FromPrimitive;
|
||||||
|
|
||||||
use crate::proto_async::*;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
NetworkError(smoltcp::Error),
|
NetworkError(smoltcp::Error),
|
||||||
|
@ -25,10 +24,10 @@ type Result<T> = core::result::Result<T, Error>;
|
||||||
impl core::fmt::Display for Error {
|
impl core::fmt::Display for Error {
|
||||||
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
|
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
&Error::NetworkError(error) => write!(f, "network error: {}", error),
|
&Error::NetworkError(error) => write!(f, "network error: {}", error),
|
||||||
&Error::UnknownLogLevel(lvl) => write!(f, "unknown log level {}", lvl),
|
&Error::UnknownLogLevel(lvl) => write!(f, "unknown log level {}", lvl),
|
||||||
&Error::UnexpectedPattern => write!(f, "unexpected pattern"),
|
&Error::UnexpectedPattern => write!(f, "unexpected pattern"),
|
||||||
&Error::UnrecognizedPacket => write!(f, "unrecognized packet"),
|
&Error::UnrecognizedPacket => write!(f, "unrecognized packet"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -45,7 +44,6 @@ pub enum Request {
|
||||||
ClearLog = 2,
|
ClearLog = 2,
|
||||||
PullLog = 7,
|
PullLog = 7,
|
||||||
SetLogFilter = 3,
|
SetLogFilter = 3,
|
||||||
Reboot = 5,
|
|
||||||
SetUartLogFilter = 6,
|
SetUartLogFilter = 6,
|
||||||
|
|
||||||
ConfigRead = 12,
|
ConfigRead = 12,
|
||||||
|
@ -57,7 +55,6 @@ pub enum Request {
|
||||||
pub enum Reply {
|
pub enum Reply {
|
||||||
Success = 1,
|
Success = 1,
|
||||||
LogContent = 2,
|
LogContent = 2,
|
||||||
RebootImminent = 3,
|
|
||||||
Error = 6,
|
Error = 6,
|
||||||
ConfigData = 7,
|
ConfigData = 7,
|
||||||
}
|
}
|
||||||
|
@ -75,7 +72,9 @@ async fn read_log_level_filter(stream: &mut TcpStream) -> Result<log::LevelFilte
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_logger_buffer_pred<F>(f: F) -> LogBufferRef<'static>
|
async fn get_logger_buffer_pred<F>(f: F) -> LogBufferRef<'static>
|
||||||
where F: Fn(&LogBufferRef) -> bool {
|
where
|
||||||
|
F: Fn(&LogBufferRef) -> bool,
|
||||||
|
{
|
||||||
poll_fn(|ctx| {
|
poll_fn(|ctx| {
|
||||||
let logger = unsafe { BufferLogger::get_logger().as_mut().unwrap() };
|
let logger = unsafe { BufferLogger::get_logger().as_mut().unwrap() };
|
||||||
match logger.buffer() {
|
match logger.buffer() {
|
||||||
|
@ -111,7 +110,10 @@ async fn read_key(stream: &mut TcpStream) -> Result<String> {
|
||||||
Ok(String::from_utf8(buffer).unwrap())
|
Ok(String::from_utf8(buffer).unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_connection(stream: &mut TcpStream, pull_id: Rc<RefCell<u32>>, cfg: Rc<Config>) -> Result<()> {
|
async fn handle_connection(
|
||||||
|
stream: &mut TcpStream,
|
||||||
|
pull_id: Rc<RefCell<u32>>,
|
||||||
|
cfg: Rc<Config>) -> Result<()> {
|
||||||
if !expect(&stream, b"ARTIQ management\n").await? {
|
if !expect(&stream, b"ARTIQ management\n").await? {
|
||||||
return Err(Error::UnexpectedPattern);
|
return Err(Error::UnexpectedPattern);
|
||||||
}
|
}
|
||||||
|
@ -159,7 +161,7 @@ async fn handle_connection(stream: &mut TcpStream, pull_id: Rc<RefCell<u32>>, cf
|
||||||
logger.set_buffer_log_level(LevelFilter::Trace);
|
logger.set_buffer_log_level(LevelFilter::Trace);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
Request::SetLogFilter => {
|
Request::SetLogFilter => {
|
||||||
let lvl = read_log_level_filter(stream).await?;
|
let lvl = read_log_level_filter(stream).await?;
|
||||||
info!("Changing log level to {}", lvl);
|
info!("Changing log level to {}", lvl);
|
||||||
|
@ -170,7 +172,10 @@ async fn handle_connection(stream: &mut TcpStream, pull_id: Rc<RefCell<u32>>, cf
|
||||||
let lvl = read_log_level_filter(stream).await?;
|
let lvl = read_log_level_filter(stream).await?;
|
||||||
info!("Changing UART log level to {}", lvl);
|
info!("Changing UART log level to {}", lvl);
|
||||||
unsafe {
|
unsafe {
|
||||||
BufferLogger::get_logger().as_ref().unwrap().set_uart_log_level(lvl);
|
BufferLogger::get_logger()
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.set_uart_log_level(lvl);
|
||||||
}
|
}
|
||||||
write_i8(stream, Reply::Success as i8).await?;
|
write_i8(stream, Reply::Success as i8).await?;
|
||||||
}
|
}
|
||||||
|
@ -186,12 +191,16 @@ async fn handle_connection(stream: &mut TcpStream, pull_id: Rc<RefCell<u32>>, cf
|
||||||
warn!("read error: no such key");
|
warn!("read error: no such key");
|
||||||
write_i8(stream, Reply::Error as i8).await?;
|
write_i8(stream, Reply::Error as i8).await?;
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
Request::ConfigWrite => {
|
Request::ConfigWrite => {
|
||||||
let key = read_key(stream).await?;
|
let key = read_key(stream).await?;
|
||||||
debug!("write key: {}", key);
|
debug!("write key: {}", key);
|
||||||
let len = read_i32(stream).await?;
|
let len = read_i32(stream).await?;
|
||||||
let len = if len <= 0 { 0 } else { len as usize };
|
let len = if len <= 0 {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
len as usize
|
||||||
|
};
|
||||||
let mut buffer = Vec::with_capacity(len);
|
let mut buffer = Vec::with_capacity(len);
|
||||||
unsafe {
|
unsafe {
|
||||||
buffer.set_len(len);
|
buffer.set_len(len);
|
||||||
|
@ -206,7 +215,7 @@ async fn handle_connection(stream: &mut TcpStream, pull_id: Rc<RefCell<u32>>, cf
|
||||||
error!("failed to write: {:?}", value);
|
error!("failed to write: {:?}", value);
|
||||||
write_i8(stream, Reply::Error as i8).await?;
|
write_i8(stream, Reply::Error as i8).await?;
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
Request::ConfigRemove => {
|
Request::ConfigRemove => {
|
||||||
let key = read_key(stream).await?;
|
let key = read_key(stream).await?;
|
||||||
debug!("erase key: {}", key);
|
debug!("erase key: {}", key);
|
||||||
|
@ -219,12 +228,6 @@ async fn handle_connection(stream: &mut TcpStream, pull_id: Rc<RefCell<u32>>, cf
|
||||||
write_i8(stream, Reply::Error as i8).await?;
|
write_i8(stream, Reply::Error as i8).await?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Request::Reboot => {
|
|
||||||
info!("rebooting");
|
|
||||||
write_i8(stream, Reply::RebootImminent as i8).await?;
|
|
||||||
stream.flush().await?;
|
|
||||||
slcr::reboot();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,23 +1,26 @@
|
||||||
|
use core::{fmt, cell::RefCell};
|
||||||
use alloc::{collections::BTreeMap, rc::Rc};
|
use alloc::{collections::BTreeMap, rc::Rc};
|
||||||
use core::{cell::RefCell, fmt};
|
|
||||||
|
|
||||||
use futures::{pin_mut, select_biased, FutureExt};
|
|
||||||
use libasync::{block_async, nb, smoltcp::TcpStream, task};
|
|
||||||
use libboard_artiq::drtio_routing;
|
|
||||||
use libboard_zynq::{smoltcp, time::Milliseconds, timer::GlobalTimer};
|
|
||||||
use libcortex_a9::mutex::Mutex;
|
|
||||||
use log::{debug, info, warn};
|
use log::{debug, info, warn};
|
||||||
use num_derive::{FromPrimitive, ToPrimitive};
|
|
||||||
use num_traits::{FromPrimitive, ToPrimitive};
|
|
||||||
use void::Void;
|
use void::Void;
|
||||||
|
|
||||||
|
use libboard_artiq::drtio_routing;
|
||||||
|
|
||||||
|
use libboard_zynq::{smoltcp, timer::GlobalTimer, time::Milliseconds};
|
||||||
|
use libasync::{task, smoltcp::TcpStream, block_async, nb};
|
||||||
|
use libcortex_a9::mutex::Mutex;
|
||||||
|
|
||||||
|
use num_derive::{FromPrimitive, ToPrimitive};
|
||||||
|
use num_traits::{FromPrimitive, ToPrimitive};
|
||||||
|
use futures::{pin_mut, select_biased, FutureExt};
|
||||||
|
|
||||||
use crate::proto_async::*;
|
use crate::proto_async::*;
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
NetworkError(smoltcp::Error),
|
NetworkError(smoltcp::Error),
|
||||||
UnexpectedPattern,
|
UnexpectedPattern,
|
||||||
UnrecognizedPacket,
|
UnrecognizedPacket
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type Result<T> = core::result::Result<T, Error>;
|
pub type Result<T> = core::result::Result<T, Error>;
|
||||||
|
@ -26,8 +29,8 @@ impl fmt::Display for Error {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
&Error::NetworkError(error) => write!(f, "network error: {}", error),
|
&Error::NetworkError(error) => write!(f, "network error: {}", error),
|
||||||
&Error::UnexpectedPattern => write!(f, "unexpected pattern"),
|
&Error::UnexpectedPattern => write!(f, "unexpected pattern"),
|
||||||
&Error::UnrecognizedPacket => write!(f, "unrecognized packet"),
|
&Error::UnrecognizedPacket => write!(f, "unrecognized packet"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,102 +46,60 @@ enum HostMessage {
|
||||||
MonitorProbe = 0,
|
MonitorProbe = 0,
|
||||||
MonitorInjection = 3,
|
MonitorInjection = 3,
|
||||||
Inject = 1,
|
Inject = 1,
|
||||||
GetInjectionStatus = 2,
|
GetInjectionStatus = 2
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, FromPrimitive, ToPrimitive)]
|
#[derive(Debug, FromPrimitive, ToPrimitive)]
|
||||||
enum DeviceMessage {
|
enum DeviceMessage {
|
||||||
MonitorStatus = 0,
|
MonitorStatus = 0,
|
||||||
InjectionStatus = 1,
|
InjectionStatus = 1
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(has_drtio)]
|
#[cfg(has_drtio)]
|
||||||
mod remote_moninj {
|
mod remote_moninj {
|
||||||
|
use super::*;
|
||||||
use libboard_artiq::drtioaux_async;
|
use libboard_artiq::drtioaux_async;
|
||||||
|
use crate::rtio_mgt::drtio;
|
||||||
use log::error;
|
use log::error;
|
||||||
|
|
||||||
use super::*;
|
pub async fn read_probe(aux_mutex: &Rc<Mutex<bool>>, timer: GlobalTimer, linkno: u8, destination: u8, channel: i32, probe: i8) -> i64 {
|
||||||
use crate::rtio_mgt::drtio;
|
let reply = drtio::aux_transact(aux_mutex, linkno, &drtioaux_async::Packet::MonitorRequest {
|
||||||
|
destination: destination,
|
||||||
pub async fn read_probe(
|
channel: channel as _,
|
||||||
aux_mutex: &Rc<Mutex<bool>>,
|
probe: probe as _},
|
||||||
timer: GlobalTimer,
|
timer).await;
|
||||||
linkno: u8,
|
|
||||||
destination: u8,
|
|
||||||
channel: i32,
|
|
||||||
probe: i8,
|
|
||||||
) -> i64 {
|
|
||||||
let reply = drtio::aux_transact(
|
|
||||||
aux_mutex,
|
|
||||||
linkno,
|
|
||||||
&drtioaux_async::Packet::MonitorRequest {
|
|
||||||
destination: destination,
|
|
||||||
channel: channel as _,
|
|
||||||
probe: probe as _,
|
|
||||||
},
|
|
||||||
timer,
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
match reply {
|
match reply {
|
||||||
Ok(drtioaux_async::Packet::MonitorReply { value }) => return value as i64,
|
Ok(drtioaux_async::Packet::MonitorReply { value }) => return value as i64,
|
||||||
Ok(packet) => error!("received unexpected aux packet: {:?}", packet),
|
Ok(packet) => error!("received unexpected aux packet: {:?}", packet),
|
||||||
Err("link went down") => {
|
Err("link went down") => { debug!("link is down"); },
|
||||||
debug!("link is down");
|
Err(e) => error!("aux packet error ({})", e)
|
||||||
}
|
|
||||||
Err(e) => error!("aux packet error ({})", e),
|
|
||||||
}
|
}
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn inject(
|
pub async fn inject(aux_mutex: &Rc<Mutex<bool>>, _timer: GlobalTimer, linkno: u8, destination: u8, channel: i32, overrd: i8, value: i8) {
|
||||||
aux_mutex: &Rc<Mutex<bool>>,
|
|
||||||
_timer: GlobalTimer,
|
|
||||||
linkno: u8,
|
|
||||||
destination: u8,
|
|
||||||
channel: i32,
|
|
||||||
overrd: i8,
|
|
||||||
value: i8,
|
|
||||||
) {
|
|
||||||
let _lock = aux_mutex.lock();
|
let _lock = aux_mutex.lock();
|
||||||
drtioaux_async::send(
|
drtioaux_async::send(linkno, &drtioaux_async::Packet::InjectionRequest {
|
||||||
linkno,
|
destination: destination,
|
||||||
&drtioaux_async::Packet::InjectionRequest {
|
channel: channel as _,
|
||||||
destination: destination,
|
overrd: overrd as _,
|
||||||
channel: channel as _,
|
value: value as _
|
||||||
overrd: overrd as _,
|
}).await.unwrap();
|
||||||
value: value as _,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn read_injection_status(
|
pub async fn read_injection_status(aux_mutex: &Rc<Mutex<bool>>, timer: GlobalTimer, linkno: u8, destination: u8, channel: i32, overrd: i8) -> i8 {
|
||||||
aux_mutex: &Rc<Mutex<bool>>,
|
let reply = drtio::aux_transact(aux_mutex,
|
||||||
timer: GlobalTimer,
|
linkno,
|
||||||
linkno: u8,
|
|
||||||
destination: u8,
|
|
||||||
channel: i32,
|
|
||||||
overrd: i8,
|
|
||||||
) -> i8 {
|
|
||||||
let reply = drtio::aux_transact(
|
|
||||||
aux_mutex,
|
|
||||||
linkno,
|
|
||||||
&drtioaux_async::Packet::InjectionStatusRequest {
|
&drtioaux_async::Packet::InjectionStatusRequest {
|
||||||
destination: destination,
|
destination: destination,
|
||||||
channel: channel as _,
|
channel: channel as _,
|
||||||
overrd: overrd as _,
|
overrd: overrd as _},
|
||||||
},
|
timer).await;
|
||||||
timer,
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
match reply {
|
match reply {
|
||||||
Ok(drtioaux_async::Packet::InjectionStatusReply { value }) => return value as i8,
|
Ok(drtioaux_async::Packet::InjectionStatusReply { value }) => return value as i8,
|
||||||
Ok(packet) => error!("received unexpected aux packet: {:?}", packet),
|
Ok(packet) => error!("received unexpected aux packet: {:?}", packet),
|
||||||
Err("link went down") => {
|
Err("link went down") => { debug!("link is down"); },
|
||||||
debug!("link is down");
|
Err(e) => error!("aux packet error ({})", e)
|
||||||
}
|
|
||||||
Err(e) => error!("aux packet error ({})", e),
|
|
||||||
}
|
}
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
@ -196,12 +157,8 @@ macro_rules! dispatch {
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_connection(
|
async fn handle_connection(stream: &TcpStream, timer: GlobalTimer,
|
||||||
stream: &TcpStream,
|
_aux_mutex: &Rc<Mutex<bool>>, _routing_table: &drtio_routing::RoutingTable) -> Result<()> {
|
||||||
timer: GlobalTimer,
|
|
||||||
_aux_mutex: &Rc<Mutex<bool>>,
|
|
||||||
_routing_table: &drtio_routing::RoutingTable,
|
|
||||||
) -> Result<()> {
|
|
||||||
if !expect(&stream, b"ARTIQ moninj\n").await? {
|
if !expect(&stream, b"ARTIQ moninj\n").await? {
|
||||||
return Err(Error::UnexpectedPattern);
|
return Err(Error::UnexpectedPattern);
|
||||||
}
|
}
|
||||||
|
@ -298,13 +255,7 @@ async fn handle_connection(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn start(
|
pub fn start(timer: GlobalTimer, aux_mutex: Rc<Mutex<bool>>, routing_table: Rc<RefCell<drtio_routing::RoutingTable>>) {
|
||||||
timer: GlobalTimer,
|
|
||||||
aux_mutex: &Rc<Mutex<bool>>,
|
|
||||||
routing_table: &Rc<RefCell<drtio_routing::RoutingTable>>,
|
|
||||||
) {
|
|
||||||
let aux_mutex = aux_mutex.clone();
|
|
||||||
let routing_table = routing_table.clone();
|
|
||||||
task::spawn(async move {
|
task::spawn(async move {
|
||||||
loop {
|
loop {
|
||||||
let aux_mutex = aux_mutex.clone();
|
let aux_mutex = aux_mutex.clone();
|
||||||
|
|
|
@ -1,22 +1,22 @@
|
||||||
#[cfg(feature = "target_kasli_soc")]
|
use libboard_zynq::{print, println};
|
||||||
use libboard_zynq::error_led::ErrorLED;
|
|
||||||
use libboard_zynq::{print, println, timer::GlobalTimer};
|
|
||||||
use libconfig::Config;
|
|
||||||
use libcortex_a9::regs::MPIDR;
|
|
||||||
use libregister::RegisterR;
|
use libregister::RegisterR;
|
||||||
use log::error;
|
use libcortex_a9::regs::MPIDR;
|
||||||
use unwind::backtrace;
|
use unwind::backtrace;
|
||||||
|
|
||||||
use crate::comms::soft_panic_main;
|
|
||||||
|
|
||||||
static mut PANICKED: [bool; 2] = [false; 2];
|
static mut PANICKED: [bool; 2] = [false; 2];
|
||||||
static mut SOFT_PANICKED: bool = false;
|
|
||||||
|
|
||||||
#[panic_handler]
|
#[panic_handler]
|
||||||
fn panic(info: &core::panic::PanicInfo) -> ! {
|
fn panic(info: &core::panic::PanicInfo) -> ! {
|
||||||
let id = MPIDR.read().cpu_id() as usize;
|
let id = MPIDR.read().cpu_id() as usize;
|
||||||
let soft_panicked = unsafe { SOFT_PANICKED };
|
print!("Core {} ", id);
|
||||||
print!("Core {} panic at ", id);
|
unsafe {
|
||||||
|
if PANICKED[id] {
|
||||||
|
println!("nested panic!");
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
PANICKED[id] = true;
|
||||||
|
}
|
||||||
|
print!("panic at ");
|
||||||
if let Some(location) = info.location() {
|
if let Some(location) = info.location() {
|
||||||
print!("{}:{}:{}", location.file(), location.line(), location.column());
|
print!("{}:{}:{}", location.file(), location.line(), location.column());
|
||||||
} else {
|
} else {
|
||||||
|
@ -27,20 +27,6 @@ fn panic(info: &core::panic::PanicInfo) -> ! {
|
||||||
} else {
|
} else {
|
||||||
println!("");
|
println!("");
|
||||||
}
|
}
|
||||||
unsafe {
|
|
||||||
// soft panics only allowed for core 0
|
|
||||||
if PANICKED[id] && (SOFT_PANICKED || id == 1) {
|
|
||||||
println!("nested panic!");
|
|
||||||
loop {}
|
|
||||||
}
|
|
||||||
SOFT_PANICKED = true;
|
|
||||||
PANICKED[id] = true;
|
|
||||||
}
|
|
||||||
#[cfg(feature = "target_kasli_soc")]
|
|
||||||
{
|
|
||||||
let mut err_led = ErrorLED::error_led();
|
|
||||||
err_led.toggle(true);
|
|
||||||
}
|
|
||||||
println!("Backtrace: ");
|
println!("Backtrace: ");
|
||||||
let _ = backtrace(|ip| {
|
let _ = backtrace(|ip| {
|
||||||
// Backtrace gives us the return address, i.e. the address after the delay slot,
|
// Backtrace gives us the return address, i.e. the address after the delay slot,
|
||||||
|
@ -48,26 +34,6 @@ fn panic(info: &core::panic::PanicInfo) -> ! {
|
||||||
print!("{:#08x} ", ip - 2 * 4);
|
print!("{:#08x} ", ip - 2 * 4);
|
||||||
});
|
});
|
||||||
println!("\nEnd backtrace");
|
println!("\nEnd backtrace");
|
||||||
if !soft_panicked && id == 0 {
|
|
||||||
soft_panic(info);
|
|
||||||
}
|
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn soft_panic(info: &core::panic::PanicInfo) -> ! {
|
|
||||||
// write panic info to log, so coremgmt can also read it
|
|
||||||
if let Some(location) = info.location() {
|
|
||||||
error!("panic at {}:{}:{}", location.file(), location.line(), location.column());
|
|
||||||
} else {
|
|
||||||
error!("panic at unknown location");
|
|
||||||
}
|
|
||||||
if let Some(message) = info.message() {
|
|
||||||
error!("panic message: {}", message);
|
|
||||||
}
|
|
||||||
let timer = GlobalTimer::start();
|
|
||||||
let cfg = match Config::new() {
|
|
||||||
Ok(cfg) => cfg,
|
|
||||||
Err(_) => Config::new_dummy(),
|
|
||||||
};
|
|
||||||
soft_panic_main(timer, cfg);
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
use core::{cell::RefCell, cmp::min};
|
use core::cmp::min;
|
||||||
|
use core::cell::RefCell;
|
||||||
|
|
||||||
use libasync::smoltcp::TcpStream;
|
|
||||||
use libboard_zynq::smoltcp;
|
use libboard_zynq::smoltcp;
|
||||||
|
use libasync::smoltcp::TcpStream;
|
||||||
|
|
||||||
type Result<T> = core::result::Result<T, smoltcp::Error>;
|
type Result<T> = core::result::Result<T, smoltcp::Error>;
|
||||||
|
|
||||||
|
@ -13,27 +14,25 @@ enum RecvState<T> {
|
||||||
pub async fn expect(stream: &TcpStream, pattern: &[u8]) -> Result<bool> {
|
pub async fn expect(stream: &TcpStream, pattern: &[u8]) -> Result<bool> {
|
||||||
let mut state = RecvState::NeedsMore(0, true);
|
let mut state = RecvState::NeedsMore(0, true);
|
||||||
loop {
|
loop {
|
||||||
state = stream
|
state = stream.recv(|buf| {
|
||||||
.recv(|buf| {
|
let mut consumed = 0;
|
||||||
let mut consumed = 0;
|
if let RecvState::NeedsMore(mut cur_index, _) = state {
|
||||||
if let RecvState::NeedsMore(mut cur_index, _) = state {
|
for b in buf.iter() {
|
||||||
for b in buf.iter() {
|
consumed += 1;
|
||||||
consumed += 1;
|
if *b == pattern[cur_index] {
|
||||||
if *b == pattern[cur_index] {
|
if cur_index + 1 == pattern.len() {
|
||||||
if cur_index + 1 == pattern.len() {
|
return (consumed, RecvState::Completed(true));
|
||||||
return (consumed, RecvState::Completed(true));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return (consumed, RecvState::Completed(false));
|
|
||||||
}
|
}
|
||||||
cur_index += 1;
|
} else {
|
||||||
|
return (consumed, RecvState::Completed(false));
|
||||||
}
|
}
|
||||||
(consumed, RecvState::NeedsMore(cur_index, true))
|
cur_index += 1;
|
||||||
} else {
|
|
||||||
unreachable!();
|
|
||||||
}
|
}
|
||||||
})
|
(consumed, RecvState::NeedsMore(cur_index, true))
|
||||||
.await?;
|
} else {
|
||||||
|
unreachable!();
|
||||||
|
}
|
||||||
|
}).await?;
|
||||||
if let RecvState::Completed(result) = state {
|
if let RecvState::Completed(result) = state {
|
||||||
return Ok(result);
|
return Ok(result);
|
||||||
}
|
}
|
||||||
|
@ -41,11 +40,15 @@ pub async fn expect(stream: &TcpStream, pattern: &[u8]) -> Result<bool> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn read_bool(stream: &TcpStream) -> Result<bool> {
|
pub async fn read_bool(stream: &TcpStream) -> Result<bool> {
|
||||||
Ok(stream.recv(|buf| (1, buf[0] != 0)).await?)
|
Ok(stream.recv(|buf| {
|
||||||
|
(1, buf[0] != 0)
|
||||||
|
}).await?)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn read_i8(stream: &TcpStream) -> Result<i8> {
|
pub async fn read_i8(stream: &TcpStream) -> Result<i8> {
|
||||||
Ok(stream.recv(|buf| (1, buf[0] as i8)).await?)
|
Ok(stream.recv(|buf| {
|
||||||
|
(1, buf[0] as i8)
|
||||||
|
}).await?)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn read_i32(stream: &TcpStream) -> Result<i32> {
|
pub async fn read_i32(stream: &TcpStream) -> Result<i32> {
|
||||||
|
@ -65,14 +68,12 @@ pub async fn read_chunk(stream: &TcpStream, destination: &mut [u8]) -> Result<()
|
||||||
let destination = RefCell::new(destination);
|
let destination = RefCell::new(destination);
|
||||||
let mut done = 0;
|
let mut done = 0;
|
||||||
while done < total {
|
while done < total {
|
||||||
let count = stream
|
let count = stream.recv(|buf| {
|
||||||
.recv(|buf| {
|
let mut destination = destination.borrow_mut();
|
||||||
let mut destination = destination.borrow_mut();
|
let count = min(total - done, buf.len());
|
||||||
let count = min(total - done, buf.len());
|
destination[done..done + count].copy_from_slice(&buf[..count]);
|
||||||
destination[done..done + count].copy_from_slice(&buf[..count]);
|
(count, count)
|
||||||
(count, count)
|
}).await?;
|
||||||
})
|
|
||||||
.await?;
|
|
||||||
done += count;
|
done += count;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -1,17 +1,18 @@
|
||||||
use alloc::boxed::Box;
|
use core::str;
|
||||||
use core::{future::Future, str};
|
use core::future::Future;
|
||||||
|
use cslice::{CSlice, CMutSlice};
|
||||||
use async_recursion::async_recursion;
|
|
||||||
use byteorder::{ByteOrder, NativeEndian};
|
|
||||||
use core_io::{Error, Write};
|
|
||||||
use cslice::{CMutSlice, CSlice};
|
|
||||||
use io::proto::ProtoWrite;
|
|
||||||
use libasync::smoltcp::TcpStream;
|
|
||||||
use libboard_zynq::smoltcp;
|
|
||||||
use log::trace;
|
use log::trace;
|
||||||
|
use byteorder::{NativeEndian, ByteOrder};
|
||||||
|
|
||||||
use self::tag::{split_tag, Tag, TagIterator};
|
use core_io::{Write, Error};
|
||||||
|
use libboard_zynq::smoltcp;
|
||||||
|
use libasync::smoltcp::TcpStream;
|
||||||
|
use alloc::boxed::Box;
|
||||||
|
use async_recursion::async_recursion;
|
||||||
|
|
||||||
|
use io::proto::ProtoWrite;
|
||||||
use crate::proto_async;
|
use crate::proto_async;
|
||||||
|
use self::tag::{Tag, TagIterator, split_tag};
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn round_up(val: usize, power_of_two: usize) -> usize {
|
fn round_up(val: usize, power_of_two: usize) -> usize {
|
||||||
|
@ -51,17 +52,17 @@ async unsafe fn recv_elements<F>(
|
||||||
elt_tag: Tag<'async_recursion>,
|
elt_tag: Tag<'async_recursion>,
|
||||||
length: usize,
|
length: usize,
|
||||||
storage: *mut (),
|
storage: *mut (),
|
||||||
alloc: &(impl Fn(usize) -> F + 'async_recursion),
|
alloc: &(impl Fn(usize) -> F + 'async_recursion)
|
||||||
) -> Result<(), smoltcp::Error>
|
) -> Result<(), smoltcp::Error>
|
||||||
where
|
where
|
||||||
F: Future<Output = *mut ()>,
|
F: Future<Output=*mut ()>,
|
||||||
{
|
{
|
||||||
// List of simple types are special-cased in the protocol for performance.
|
// List of simple types are special-cased in the protocol for performance.
|
||||||
match elt_tag {
|
match elt_tag {
|
||||||
Tag::Bool => {
|
Tag::Bool => {
|
||||||
let dest = core::slice::from_raw_parts_mut(storage as *mut u8, length);
|
let dest = core::slice::from_raw_parts_mut(storage as *mut u8, length);
|
||||||
proto_async::read_chunk(stream, dest).await?;
|
proto_async::read_chunk(stream, dest).await?;
|
||||||
}
|
},
|
||||||
Tag::Int32 => {
|
Tag::Int32 => {
|
||||||
let ptr = storage as *mut u32;
|
let ptr = storage as *mut u32;
|
||||||
let dest = core::slice::from_raw_parts_mut(ptr as *mut u8, length * 4);
|
let dest = core::slice::from_raw_parts_mut(ptr as *mut u8, length * 4);
|
||||||
|
@ -69,7 +70,7 @@ where
|
||||||
drop(dest);
|
drop(dest);
|
||||||
let dest = core::slice::from_raw_parts_mut(ptr, length);
|
let dest = core::slice::from_raw_parts_mut(ptr, length);
|
||||||
NativeEndian::from_slice_u32(dest);
|
NativeEndian::from_slice_u32(dest);
|
||||||
}
|
},
|
||||||
Tag::Int64 | Tag::Float64 => {
|
Tag::Int64 | Tag::Float64 => {
|
||||||
let ptr = storage as *mut u64;
|
let ptr = storage as *mut u64;
|
||||||
let dest = core::slice::from_raw_parts_mut(ptr as *mut u8, length * 8);
|
let dest = core::slice::from_raw_parts_mut(ptr as *mut u8, length * 8);
|
||||||
|
@ -77,7 +78,7 @@ where
|
||||||
drop(dest);
|
drop(dest);
|
||||||
let dest = core::slice::from_raw_parts_mut(ptr, length);
|
let dest = core::slice::from_raw_parts_mut(ptr, length);
|
||||||
NativeEndian::from_slice_u64(dest);
|
NativeEndian::from_slice_u64(dest);
|
||||||
}
|
},
|
||||||
_ => {
|
_ => {
|
||||||
let mut data = storage;
|
let mut data = storage;
|
||||||
for _ in 0..length {
|
for _ in 0..length {
|
||||||
|
@ -94,37 +95,36 @@ where
|
||||||
/// invoked any number of times with the size of the required allocation as a parameter
|
/// invoked any number of times with the size of the required allocation as a parameter
|
||||||
/// (which is assumed to be correctly aligned for all payload types).
|
/// (which is assumed to be correctly aligned for all payload types).
|
||||||
#[async_recursion(?Send)]
|
#[async_recursion(?Send)]
|
||||||
async unsafe fn recv_value<F>(
|
async unsafe fn recv_value<F>(stream: &TcpStream, tag: Tag<'async_recursion>, data: &mut *mut (),
|
||||||
stream: &TcpStream,
|
alloc: &(impl Fn(usize) -> F + 'async_recursion))
|
||||||
tag: Tag<'async_recursion>,
|
-> Result<(), smoltcp::Error>
|
||||||
data: &mut *mut (),
|
where F: Future<Output=*mut ()>
|
||||||
alloc: &(impl Fn(usize) -> F + 'async_recursion),
|
|
||||||
) -> Result<(), smoltcp::Error>
|
|
||||||
where
|
|
||||||
F: Future<Output = *mut ()>,
|
|
||||||
{
|
{
|
||||||
macro_rules! consume_value {
|
macro_rules! consume_value {
|
||||||
($ty:ty, | $ptr:ident | $map:expr) => {{
|
($ty:ty, |$ptr:ident| $map:expr) => ({
|
||||||
let $ptr = align_ptr_mut::<$ty>(*data);
|
let $ptr = align_ptr_mut::<$ty>(*data);
|
||||||
*data = $ptr.offset(1) as *mut ();
|
*data = $ptr.offset(1) as *mut ();
|
||||||
$map
|
$map
|
||||||
}};
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
match tag {
|
match tag {
|
||||||
Tag::None => Ok(()),
|
Tag::None => Ok(()),
|
||||||
Tag::Bool => consume_value!(i8, |ptr| {
|
Tag::Bool =>
|
||||||
*ptr = proto_async::read_i8(stream).await?;
|
consume_value!(i8, |ptr| {
|
||||||
Ok(())
|
*ptr = proto_async::read_i8(stream).await?;
|
||||||
}),
|
Ok(())
|
||||||
Tag::Int32 => consume_value!(i32, |ptr| {
|
}),
|
||||||
*ptr = proto_async::read_i32(stream).await?;
|
Tag::Int32 =>
|
||||||
Ok(())
|
consume_value!(i32, |ptr| {
|
||||||
}),
|
*ptr = proto_async::read_i32(stream).await?;
|
||||||
Tag::Int64 | Tag::Float64 => consume_value!(i64, |ptr| {
|
Ok(())
|
||||||
*ptr = proto_async::read_i64(stream).await?;
|
}),
|
||||||
Ok(())
|
Tag::Int64 | Tag::Float64 =>
|
||||||
}),
|
consume_value!(i64, |ptr| {
|
||||||
|
*ptr = proto_async::read_i64(stream).await?;
|
||||||
|
Ok(())
|
||||||
|
}),
|
||||||
Tag::String | Tag::Bytes | Tag::ByteArray => {
|
Tag::String | Tag::Bytes | Tag::ByteArray => {
|
||||||
consume_value!(CMutSlice<u8>, |ptr| {
|
consume_value!(CMutSlice<u8>, |ptr| {
|
||||||
let length = proto_async::read_i32(stream).await? as usize;
|
let length = proto_async::read_i32(stream).await? as usize;
|
||||||
|
@ -148,10 +148,7 @@ where
|
||||||
}
|
}
|
||||||
Tag::List(it) => {
|
Tag::List(it) => {
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
struct List {
|
struct List { elements: *mut (), length: usize }
|
||||||
elements: *mut (),
|
|
||||||
length: usize,
|
|
||||||
}
|
|
||||||
consume_value!(*mut List, |ptr_to_list| {
|
consume_value!(*mut List, |ptr_to_list| {
|
||||||
let tag = it.clone().next().expect("truncated tag");
|
let tag = it.clone().next().expect("truncated tag");
|
||||||
let length = proto_async::read_i32(stream).await? as usize;
|
let length = proto_async::read_i32(stream).await? as usize;
|
||||||
|
@ -183,7 +180,7 @@ where
|
||||||
for _ in 0..num_dims {
|
for _ in 0..num_dims {
|
||||||
let len = proto_async::read_i32(stream).await? as usize;
|
let len = proto_async::read_i32(stream).await? as usize;
|
||||||
total_len *= len;
|
total_len *= len;
|
||||||
consume_value!(usize, |ptr| *ptr = len)
|
consume_value!(usize, |ptr| *ptr = len )
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allocate backing storage for elements; deserialize them.
|
// Allocate backing storage for elements; deserialize them.
|
||||||
|
@ -201,18 +198,14 @@ where
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
Tag::Keyword(_) => unreachable!(),
|
Tag::Keyword(_) => unreachable!(),
|
||||||
Tag::Object => unreachable!(),
|
Tag::Object => unreachable!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn recv_return<F>(
|
pub async fn recv_return<F>(stream: &TcpStream, tag_bytes: &[u8], data: *mut (),
|
||||||
stream: &TcpStream,
|
alloc: &impl Fn(usize) -> F)
|
||||||
tag_bytes: &[u8],
|
-> Result<(), smoltcp::Error>
|
||||||
data: *mut (),
|
where F: Future<Output=*mut ()>
|
||||||
alloc: &impl Fn(usize) -> F,
|
|
||||||
) -> Result<(), smoltcp::Error>
|
|
||||||
where
|
|
||||||
F: Future<Output = *mut ()>,
|
|
||||||
{
|
{
|
||||||
let mut it = TagIterator::new(tag_bytes);
|
let mut it = TagIterator::new(tag_bytes);
|
||||||
trace!("recv ...->{}", it);
|
trace!("recv ...->{}", it);
|
||||||
|
@ -224,8 +217,10 @@ where
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn send_elements<W>(writer: &mut W, elt_tag: Tag, length: usize, data: *const ()) -> Result<(), Error>
|
unsafe fn send_elements<W>(writer: &mut W, elt_tag: Tag, length: usize, data: *const ())
|
||||||
where W: Write + ?Sized {
|
-> Result<(), Error>
|
||||||
|
where W: Write + ?Sized
|
||||||
|
{
|
||||||
writer.write_u8(elt_tag.as_u8())?;
|
writer.write_u8(elt_tag.as_u8())?;
|
||||||
match elt_tag {
|
match elt_tag {
|
||||||
// we cannot use NativeEndian::from_slice_i32 as the data is not mutable,
|
// we cannot use NativeEndian::from_slice_i32 as the data is not mutable,
|
||||||
|
@ -233,15 +228,15 @@ where W: Write + ?Sized {
|
||||||
Tag::Bool => {
|
Tag::Bool => {
|
||||||
let slice = core::slice::from_raw_parts(data as *const u8, length);
|
let slice = core::slice::from_raw_parts(data as *const u8, length);
|
||||||
writer.write_all(slice)?;
|
writer.write_all(slice)?;
|
||||||
}
|
},
|
||||||
Tag::Int32 => {
|
Tag::Int32 => {
|
||||||
let slice = core::slice::from_raw_parts(data as *const u8, length * 4);
|
let slice = core::slice::from_raw_parts(data as *const u8, length * 4);
|
||||||
writer.write_all(slice)?;
|
writer.write_all(slice)?;
|
||||||
}
|
},
|
||||||
Tag::Int64 | Tag::Float64 => {
|
Tag::Int64 | Tag::Float64 => {
|
||||||
let slice = core::slice::from_raw_parts(data as *const u8, length * 8);
|
let slice = core::slice::from_raw_parts(data as *const u8, length * 8);
|
||||||
writer.write_all(slice)?;
|
writer.write_all(slice)?;
|
||||||
}
|
},
|
||||||
_ => {
|
_ => {
|
||||||
let mut data = data;
|
let mut data = data;
|
||||||
for _ in 0..length {
|
for _ in 0..length {
|
||||||
|
@ -252,26 +247,36 @@ where W: Write + ?Sized {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn send_value<W>(writer: &mut W, tag: Tag, data: &mut *const ()) -> Result<(), Error>
|
unsafe fn send_value<W>(writer: &mut W, tag: Tag, data: &mut *const ())
|
||||||
where W: Write + ?Sized {
|
-> Result<(), Error>
|
||||||
|
where W: Write + ?Sized
|
||||||
|
{
|
||||||
macro_rules! consume_value {
|
macro_rules! consume_value {
|
||||||
($ty:ty, | $ptr:ident | $map:expr) => {{
|
($ty:ty, |$ptr:ident| $map:expr) => ({
|
||||||
let $ptr = align_ptr::<$ty>(*data);
|
let $ptr = align_ptr::<$ty>(*data);
|
||||||
*data = $ptr.offset(1) as *const ();
|
*data = $ptr.offset(1) as *const ();
|
||||||
$map
|
$map
|
||||||
}};
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
writer.write_u8(tag.as_u8())?;
|
writer.write_u8(tag.as_u8())?;
|
||||||
match tag {
|
match tag {
|
||||||
Tag::None => Ok(()),
|
Tag::None => Ok(()),
|
||||||
Tag::Bool => consume_value!(u8, |ptr| writer.write_u8(*ptr)),
|
Tag::Bool =>
|
||||||
Tag::Int32 => consume_value!(u32, |ptr| writer.write_u32(*ptr)),
|
consume_value!(u8, |ptr|
|
||||||
Tag::Int64 | Tag::Float64 => consume_value!(u64, |ptr| writer.write_u64(*ptr)),
|
writer.write_u8(*ptr)),
|
||||||
Tag::String => consume_value!(CSlice<u8>, |ptr| {
|
Tag::Int32 =>
|
||||||
writer.write_string(str::from_utf8((*ptr).as_ref()).unwrap())
|
consume_value!(u32, |ptr|
|
||||||
}),
|
writer.write_u32(*ptr)),
|
||||||
Tag::Bytes | Tag::ByteArray => consume_value!(CSlice<u8>, |ptr| writer.write_bytes((*ptr).as_ref())),
|
Tag::Int64 | Tag::Float64 =>
|
||||||
|
consume_value!(u64, |ptr|
|
||||||
|
writer.write_u64(*ptr)),
|
||||||
|
Tag::String =>
|
||||||
|
consume_value!(CSlice<u8>, |ptr|
|
||||||
|
writer.write_string(str::from_utf8((*ptr).as_ref()).unwrap())),
|
||||||
|
Tag::Bytes | Tag::ByteArray =>
|
||||||
|
consume_value!(CSlice<u8>, |ptr|
|
||||||
|
writer.write_bytes((*ptr).as_ref())),
|
||||||
Tag::Tuple(it, arity) => {
|
Tag::Tuple(it, arity) => {
|
||||||
let mut it = it.clone();
|
let mut it = it.clone();
|
||||||
writer.write_u8(arity)?;
|
writer.write_u8(arity)?;
|
||||||
|
@ -286,10 +291,7 @@ where W: Write + ?Sized {
|
||||||
}
|
}
|
||||||
Tag::List(it) => {
|
Tag::List(it) => {
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
struct List {
|
struct List { elements: *const (), length: u32 }
|
||||||
elements: *const (),
|
|
||||||
length: u32,
|
|
||||||
}
|
|
||||||
consume_value!(&List, |ptr| {
|
consume_value!(&List, |ptr| {
|
||||||
let length = (**ptr).length as usize;
|
let length = (**ptr).length as usize;
|
||||||
writer.write_u32((*ptr).length)?;
|
writer.write_u32((*ptr).length)?;
|
||||||
|
@ -299,7 +301,7 @@ where W: Write + ?Sized {
|
||||||
}
|
}
|
||||||
Tag::Array(it, num_dims) => {
|
Tag::Array(it, num_dims) => {
|
||||||
writer.write_u8(num_dims)?;
|
writer.write_u8(num_dims)?;
|
||||||
consume_value!(*const (), |buffer| {
|
consume_value!(*const(), |buffer| {
|
||||||
let elt_tag = it.clone().next().expect("truncated tag");
|
let elt_tag = it.clone().next().expect("truncated tag");
|
||||||
|
|
||||||
let mut total_len = 1;
|
let mut total_len = 1;
|
||||||
|
@ -322,9 +324,7 @@ where W: Write + ?Sized {
|
||||||
}
|
}
|
||||||
Tag::Keyword(it) => {
|
Tag::Keyword(it) => {
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
struct Keyword<'a> {
|
struct Keyword<'a> { name: CSlice<'a, u8> }
|
||||||
name: CSlice<'a, u8>,
|
|
||||||
}
|
|
||||||
consume_value!(Keyword, |ptr| {
|
consume_value!(Keyword, |ptr| {
|
||||||
writer.write_string(str::from_utf8((*ptr).name.as_ref()).unwrap())?;
|
writer.write_string(str::from_utf8((*ptr).name.as_ref()).unwrap())?;
|
||||||
let tag = it.clone().next().expect("truncated tag");
|
let tag = it.clone().next().expect("truncated tag");
|
||||||
|
@ -336,16 +336,17 @@ where W: Write + ?Sized {
|
||||||
}
|
}
|
||||||
Tag::Object => {
|
Tag::Object => {
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
struct Object {
|
struct Object { id: u32 }
|
||||||
id: u32,
|
consume_value!(*const Object, |ptr|
|
||||||
}
|
writer.write_u32((**ptr).id))
|
||||||
consume_value!(*const Object, |ptr| writer.write_u32((**ptr).id))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_args<W>(writer: &mut W, service: u32, tag_bytes: &[u8], data: *const *const ()) -> Result<(), Error>
|
pub fn send_args<W>(writer: &mut W, service: u32, tag_bytes: &[u8], data: *const *const ())
|
||||||
where W: Write + ?Sized {
|
-> Result<(), Error>
|
||||||
|
where W: Write + ?Sized
|
||||||
|
{
|
||||||
let (arg_tags_bytes, return_tag_bytes) = split_tag(tag_bytes);
|
let (arg_tags_bytes, return_tag_bytes) = split_tag(tag_bytes);
|
||||||
|
|
||||||
let mut args_it = TagIterator::new(arg_tags_bytes);
|
let mut args_it = TagIterator::new(arg_tags_bytes);
|
||||||
|
@ -358,7 +359,7 @@ where W: Write + ?Sized {
|
||||||
let mut data = unsafe { *data.offset(index) };
|
let mut data = unsafe { *data.offset(index) };
|
||||||
unsafe { send_value(writer, arg_tag, &mut data)? };
|
unsafe { send_value(writer, arg_tag, &mut data)? };
|
||||||
} else {
|
} else {
|
||||||
break;
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
writer.write_u8(0)?;
|
writer.write_u8(0)?;
|
||||||
|
@ -371,10 +372,10 @@ mod tag {
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
|
|
||||||
pub fn split_tag(tag_bytes: &[u8]) -> (&[u8], &[u8]) {
|
pub fn split_tag(tag_bytes: &[u8]) -> (&[u8], &[u8]) {
|
||||||
let tag_separator = tag_bytes
|
let tag_separator =
|
||||||
.iter()
|
tag_bytes.iter()
|
||||||
.position(|&b| b == b':')
|
.position(|&b| b == b':')
|
||||||
.expect("tag without a return separator");
|
.expect("tag without a return separator");
|
||||||
let (arg_tags_bytes, rest) = tag_bytes.split_at(tag_separator);
|
let (arg_tags_bytes, rest) = tag_bytes.split_at(tag_separator);
|
||||||
let return_tag_bytes = &rest[1..];
|
let return_tag_bytes = &rest[1..];
|
||||||
(arg_tags_bytes, return_tag_bytes)
|
(arg_tags_bytes, return_tag_bytes)
|
||||||
|
@ -395,7 +396,7 @@ mod tag {
|
||||||
Array(TagIterator<'a>, u8),
|
Array(TagIterator<'a>, u8),
|
||||||
Range(TagIterator<'a>),
|
Range(TagIterator<'a>),
|
||||||
Keyword(TagIterator<'a>),
|
Keyword(TagIterator<'a>),
|
||||||
Object,
|
Object
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Tag<'a> {
|
impl<'a> Tag<'a> {
|
||||||
|
@ -430,15 +431,14 @@ mod tag {
|
||||||
Tag::Tuple(it, arity) => {
|
Tag::Tuple(it, arity) => {
|
||||||
let it = it.clone();
|
let it = it.clone();
|
||||||
it.take(arity.into()).map(|t| t.alignment()).max().unwrap()
|
it.take(arity.into()).map(|t| t.alignment()).max().unwrap()
|
||||||
}
|
},
|
||||||
Tag::Range(it) => {
|
Tag::Range(it) => {
|
||||||
let it = it.clone();
|
let it = it.clone();
|
||||||
it.take(3).map(|t| t.alignment()).max().unwrap()
|
it.take(3).map(|t| t.alignment()).max().unwrap()
|
||||||
}
|
}
|
||||||
// the ptr/length(s) pair is basically CSlice
|
// the ptr/length(s) pair is basically CSlice
|
||||||
Tag::Bytes | Tag::String | Tag::ByteArray | Tag::List(_) | Tag::Array(_, _) => {
|
Tag::Bytes | Tag::String | Tag::ByteArray | Tag::List(_) | Tag::Array(_, _) =>
|
||||||
core::mem::align_of::<CSlice<()>>()
|
core::mem::align_of::<CSlice<()>>(),
|
||||||
}
|
|
||||||
Tag::Keyword(_) => unreachable!("Tag::Keyword should not appear in composite types"),
|
Tag::Keyword(_) => unreachable!("Tag::Keyword should not appear in composite types"),
|
||||||
Tag::Object => core::mem::align_of::<u32>(),
|
Tag::Object => core::mem::align_of::<u32>(),
|
||||||
}
|
}
|
||||||
|
@ -484,7 +484,7 @@ mod tag {
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct TagIterator<'a> {
|
pub struct TagIterator<'a> {
|
||||||
data: &'a [u8],
|
data: &'a [u8]
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> TagIterator<'a> {
|
impl<'a> TagIterator<'a> {
|
||||||
|
@ -492,14 +492,13 @@ mod tag {
|
||||||
TagIterator { data }
|
TagIterator { data }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn sub(&mut self, count: u8) -> TagIterator<'a> {
|
fn sub(&mut self, count: u8) -> TagIterator<'a> {
|
||||||
let data = self.data;
|
let data = self.data;
|
||||||
for _ in 0..count {
|
for _ in 0..count {
|
||||||
self.next().expect("truncated tag");
|
self.next().expect("truncated tag");
|
||||||
}
|
}
|
||||||
TagIterator {
|
TagIterator { data: &data[..(data.len() - self.data.len())] }
|
||||||
data: &data[..(data.len() - self.data.len())],
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -508,7 +507,7 @@ mod tag {
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Tag<'a>> {
|
fn next(&mut self) -> Option<Tag<'a>> {
|
||||||
if self.data.len() == 0 {
|
if self.data.len() == 0 {
|
||||||
return None;
|
return None
|
||||||
}
|
}
|
||||||
|
|
||||||
let tag_byte = self.data[0];
|
let tag_byte = self.data[0];
|
||||||
|
@ -536,7 +535,7 @@ mod tag {
|
||||||
b'r' => Tag::Range(self.sub(1)),
|
b'r' => Tag::Range(self.sub(1)),
|
||||||
b'k' => Tag::Keyword(self.sub(1)),
|
b'k' => Tag::Keyword(self.sub(1)),
|
||||||
b'O' => Tag::Object,
|
b'O' => Tag::Object,
|
||||||
_ => unreachable!(),
|
_ => unreachable!()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -553,14 +552,22 @@ mod tag {
|
||||||
}
|
}
|
||||||
|
|
||||||
match tag {
|
match tag {
|
||||||
Tag::None => write!(f, "None")?,
|
Tag::None =>
|
||||||
Tag::Bool => write!(f, "Bool")?,
|
write!(f, "None")?,
|
||||||
Tag::Int32 => write!(f, "Int32")?,
|
Tag::Bool =>
|
||||||
Tag::Int64 => write!(f, "Int64")?,
|
write!(f, "Bool")?,
|
||||||
Tag::Float64 => write!(f, "Float64")?,
|
Tag::Int32 =>
|
||||||
Tag::String => write!(f, "String")?,
|
write!(f, "Int32")?,
|
||||||
Tag::Bytes => write!(f, "Bytes")?,
|
Tag::Int64 =>
|
||||||
Tag::ByteArray => write!(f, "ByteArray")?,
|
write!(f, "Int64")?,
|
||||||
|
Tag::Float64 =>
|
||||||
|
write!(f, "Float64")?,
|
||||||
|
Tag::String =>
|
||||||
|
write!(f, "String")?,
|
||||||
|
Tag::Bytes =>
|
||||||
|
write!(f, "Bytes")?,
|
||||||
|
Tag::ByteArray =>
|
||||||
|
write!(f, "ByteArray")?,
|
||||||
Tag::Tuple(it, _) => {
|
Tag::Tuple(it, _) => {
|
||||||
write!(f, "Tuple(")?;
|
write!(f, "Tuple(")?;
|
||||||
it.fmt(f)?;
|
it.fmt(f)?;
|
||||||
|
@ -586,7 +593,8 @@ mod tag {
|
||||||
it.fmt(f)?;
|
it.fmt(f)?;
|
||||||
write!(f, ")")?;
|
write!(f, ")")?;
|
||||||
}
|
}
|
||||||
Tag::Object => write!(f, "Object")?,
|
Tag::Object =>
|
||||||
|
write!(f, "Object")?,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
|
use cslice::CSlice;
|
||||||
|
use vcell::VolatileCell;
|
||||||
|
use libcortex_a9::asm;
|
||||||
|
use crate::artiq_raise;
|
||||||
use core::sync::atomic::{fence, Ordering};
|
use core::sync::atomic::{fence, Ordering};
|
||||||
|
|
||||||
use cslice::CSlice;
|
use crate::pl::csr;
|
||||||
use libcortex_a9::asm;
|
|
||||||
use vcell::VolatileCell;
|
|
||||||
|
|
||||||
use crate::{artiq_raise, pl::csr, rtio_mgt::resolve_channel_name};
|
pub const RTIO_O_STATUS_WAIT: i32 = 1;
|
||||||
|
pub const RTIO_O_STATUS_UNDERFLOW: i32 = 2;
|
||||||
pub const RTIO_O_STATUS_WAIT: i32 = 1;
|
pub const RTIO_O_STATUS_DESTINATION_UNREACHABLE: i32 = 4;
|
||||||
pub const RTIO_O_STATUS_UNDERFLOW: i32 = 2;
|
pub const RTIO_I_STATUS_WAIT_EVENT: i32 = 1;
|
||||||
pub const RTIO_O_STATUS_DESTINATION_UNREACHABLE: i32 = 4;
|
pub const RTIO_I_STATUS_OVERFLOW: i32 = 2;
|
||||||
pub const RTIO_I_STATUS_WAIT_EVENT: i32 = 1;
|
pub const RTIO_I_STATUS_WAIT_STATUS: i32 = 4; // TODO
|
||||||
pub const RTIO_I_STATUS_OVERFLOW: i32 = 2;
|
pub const RTIO_I_STATUS_DESTINATION_UNREACHABLE: i32 = 8;
|
||||||
pub const RTIO_I_STATUS_WAIT_STATUS: i32 = 4; // TODO
|
|
||||||
pub const RTIO_I_STATUS_DESTINATION_UNREACHABLE: i32 = 8;
|
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct TimestampedData {
|
pub struct TimestampedData {
|
||||||
|
@ -46,10 +46,10 @@ static mut TRANSACTION_BUFFER: Transaction = Transaction {
|
||||||
reply_timestamp: VolatileCell::new(0),
|
reply_timestamp: VolatileCell::new(0),
|
||||||
padding0: [0; 2],
|
padding0: [0; 2],
|
||||||
padding1: [0; 2],
|
padding1: [0; 2],
|
||||||
padding2: [0; 2],
|
padding2: [0; 2]
|
||||||
};
|
};
|
||||||
|
|
||||||
pub extern "C" fn init() {
|
pub extern fn init() {
|
||||||
unsafe {
|
unsafe {
|
||||||
csr::rtio_core::reset_write(1);
|
csr::rtio_core::reset_write(1);
|
||||||
csr::rtio::engine_addr_base_write(&TRANSACTION_BUFFER as *const Transaction as u32);
|
csr::rtio::engine_addr_base_write(&TRANSACTION_BUFFER as *const Transaction as u32);
|
||||||
|
@ -57,7 +57,7 @@ pub extern "C" fn init() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub extern "C" fn get_counter() -> i64 {
|
pub extern fn get_counter() -> i64 {
|
||||||
unsafe {
|
unsafe {
|
||||||
csr::rtio::counter_update_write(1);
|
csr::rtio::counter_update_write(1);
|
||||||
csr::rtio::counter_read() as i64
|
csr::rtio::counter_read() as i64
|
||||||
|
@ -66,15 +66,15 @@ pub extern "C" fn get_counter() -> i64 {
|
||||||
|
|
||||||
static mut NOW: i64 = 0;
|
static mut NOW: i64 = 0;
|
||||||
|
|
||||||
pub extern "C" fn now_mu() -> i64 {
|
pub extern fn now_mu() -> i64 {
|
||||||
unsafe { NOW }
|
unsafe { NOW }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub extern "C" fn at_mu(t: i64) {
|
pub extern fn at_mu(t: i64) {
|
||||||
unsafe { NOW = t }
|
unsafe { NOW = t }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub extern "C" fn delay_mu(dt: i64) {
|
pub extern fn delay_mu(dt: i64) {
|
||||||
unsafe { NOW += dt }
|
unsafe { NOW += dt }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,34 +86,18 @@ unsafe fn process_exceptional_status(channel: i32, status: i32) {
|
||||||
while csr::rtio::o_status_read() as i32 & RTIO_O_STATUS_WAIT != 0 {}
|
while csr::rtio::o_status_read() as i32 & RTIO_O_STATUS_WAIT != 0 {}
|
||||||
}
|
}
|
||||||
if status & RTIO_O_STATUS_UNDERFLOW != 0 {
|
if status & RTIO_O_STATUS_UNDERFLOW != 0 {
|
||||||
artiq_raise!(
|
artiq_raise!("RTIOUnderflow",
|
||||||
"RTIOUnderflow",
|
"RTIO underflow at {0} mu, channel {1}, slack {2} mu",
|
||||||
format!(
|
timestamp, channel as i64, timestamp - get_counter());
|
||||||
"RTIO underflow at {{1}} mu, channel 0x{:04x}:{}, slack {{2}} mu",
|
|
||||||
channel,
|
|
||||||
resolve_channel_name(channel as u32)
|
|
||||||
),
|
|
||||||
channel as i64,
|
|
||||||
timestamp,
|
|
||||||
timestamp - get_counter()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
if status & RTIO_O_STATUS_DESTINATION_UNREACHABLE != 0 {
|
if status & RTIO_O_STATUS_DESTINATION_UNREACHABLE != 0 {
|
||||||
artiq_raise!(
|
artiq_raise!("RTIODestinationUnreachable",
|
||||||
"RTIODestinationUnreachable",
|
"RTIO destination unreachable, output, at {0} mu, channel {1}",
|
||||||
format!(
|
timestamp, channel as i64, 0);
|
||||||
"RTIO destination unreachable, output, at {{0}} mu, channel 0x{:04x}:{}",
|
|
||||||
channel,
|
|
||||||
resolve_channel_name(channel as u32)
|
|
||||||
),
|
|
||||||
timestamp,
|
|
||||||
channel as i64,
|
|
||||||
0
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub extern "C" fn output(target: i32, data: i32) {
|
pub extern fn output(target: i32, data: i32) {
|
||||||
unsafe {
|
unsafe {
|
||||||
// Clear status so we can observe response
|
// Clear status so we can observe response
|
||||||
TRANSACTION_BUFFER.reply_status.set(0);
|
TRANSACTION_BUFFER.reply_status.set(0);
|
||||||
|
@ -141,7 +125,7 @@ pub extern "C" fn output(target: i32, data: i32) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub extern "C" fn output_wide(target: i32, data: CSlice<i32>) {
|
pub extern fn output_wide(target: i32, data: CSlice<i32>) {
|
||||||
unsafe {
|
unsafe {
|
||||||
// Clear status so we can observe response
|
// Clear status so we can observe response
|
||||||
TRANSACTION_BUFFER.reply_status.set(0);
|
TRANSACTION_BUFFER.reply_status.set(0);
|
||||||
|
@ -158,7 +142,7 @@ pub extern "C" fn output_wide(target: i32, data: CSlice<i32>) {
|
||||||
loop {
|
loop {
|
||||||
status = TRANSACTION_BUFFER.reply_status.get();
|
status = TRANSACTION_BUFFER.reply_status.get();
|
||||||
if status != 0 {
|
if status != 0 {
|
||||||
break;
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -169,8 +153,8 @@ pub extern "C" fn output_wide(target: i32, data: CSlice<i32>) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub extern "C" fn input_timestamp(timeout: i64, channel: i32) -> i64 {
|
pub extern fn input_timestamp(timeout: i64, channel: i32) -> i64 {
|
||||||
unsafe {
|
unsafe {
|
||||||
// Clear status so we can observe response
|
// Clear status so we can observe response
|
||||||
TRANSACTION_BUFFER.reply_status.set(0);
|
TRANSACTION_BUFFER.reply_status.set(0);
|
||||||
|
|
||||||
|
@ -186,45 +170,29 @@ pub extern "C" fn input_timestamp(timeout: i64, channel: i32) -> i64 {
|
||||||
loop {
|
loop {
|
||||||
status = TRANSACTION_BUFFER.reply_status.get();
|
status = TRANSACTION_BUFFER.reply_status.get();
|
||||||
if status != 0 {
|
if status != 0 {
|
||||||
break;
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if status & RTIO_I_STATUS_OVERFLOW != 0 {
|
if status & RTIO_I_STATUS_OVERFLOW != 0 {
|
||||||
artiq_raise!(
|
artiq_raise!("RTIOOverflow",
|
||||||
"RTIOOverflow",
|
"RTIO input overflow on channel {0}",
|
||||||
format!(
|
channel as i64, 0, 0);
|
||||||
"RTIO input overflow on channel 0x{:04x}:{}",
|
|
||||||
channel,
|
|
||||||
resolve_channel_name(channel as u32)
|
|
||||||
),
|
|
||||||
channel as i64,
|
|
||||||
0,
|
|
||||||
0
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
if status & RTIO_I_STATUS_WAIT_EVENT != 0 {
|
if status & RTIO_I_STATUS_WAIT_EVENT != 0 {
|
||||||
return -1;
|
return -1
|
||||||
}
|
}
|
||||||
if status & RTIO_I_STATUS_DESTINATION_UNREACHABLE != 0 {
|
if status & RTIO_I_STATUS_DESTINATION_UNREACHABLE != 0 {
|
||||||
artiq_raise!(
|
artiq_raise!("RTIODestinationUnreachable",
|
||||||
"RTIODestinationUnreachable",
|
"RTIO destination unreachable, input, on channel {0}",
|
||||||
format!(
|
channel as i64, 0, 0);
|
||||||
"RTIO destination unreachable, input, on channel 0x{:04x}:{}",
|
|
||||||
channel,
|
|
||||||
resolve_channel_name(channel as u32)
|
|
||||||
),
|
|
||||||
channel as i64,
|
|
||||||
0,
|
|
||||||
0
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TRANSACTION_BUFFER.reply_timestamp.get()
|
TRANSACTION_BUFFER.reply_timestamp.get()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub extern "C" fn input_data(channel: i32) -> i32 {
|
pub extern fn input_data(channel: i32) -> i32 {
|
||||||
unsafe {
|
unsafe {
|
||||||
TRANSACTION_BUFFER.reply_status.set(0);
|
TRANSACTION_BUFFER.reply_status.set(0);
|
||||||
|
|
||||||
|
@ -240,42 +208,26 @@ pub extern "C" fn input_data(channel: i32) -> i32 {
|
||||||
loop {
|
loop {
|
||||||
status = TRANSACTION_BUFFER.reply_status.get();
|
status = TRANSACTION_BUFFER.reply_status.get();
|
||||||
if status != 0 {
|
if status != 0 {
|
||||||
break;
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if status & RTIO_I_STATUS_OVERFLOW != 0 {
|
if status & RTIO_I_STATUS_OVERFLOW != 0 {
|
||||||
artiq_raise!(
|
artiq_raise!("RTIOOverflow",
|
||||||
"RTIOOverflow",
|
"RTIO input overflow on channel {0}",
|
||||||
format!(
|
channel as i64, 0, 0);
|
||||||
"RTIO input overflow on channel 0x{:04x}:{}",
|
|
||||||
channel,
|
|
||||||
resolve_channel_name(channel as u32)
|
|
||||||
),
|
|
||||||
channel as i64,
|
|
||||||
0,
|
|
||||||
0
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
if status & RTIO_I_STATUS_DESTINATION_UNREACHABLE != 0 {
|
if status & RTIO_I_STATUS_DESTINATION_UNREACHABLE != 0 {
|
||||||
artiq_raise!(
|
artiq_raise!("RTIODestinationUnreachable",
|
||||||
"RTIODestinationUnreachable",
|
"RTIO destination unreachable, input, on channel {0}",
|
||||||
format!(
|
channel as i64, 0, 0);
|
||||||
"RTIO destination unreachable, input, on channel 0x{:04x}:{}",
|
|
||||||
channel,
|
|
||||||
resolve_channel_name(channel as u32)
|
|
||||||
),
|
|
||||||
channel as i64,
|
|
||||||
0,
|
|
||||||
0
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TRANSACTION_BUFFER.reply_data.get()
|
TRANSACTION_BUFFER.reply_data.get()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub extern "C" fn input_timestamped_data(timeout: i64, channel: i32) -> TimestampedData {
|
pub extern fn input_timestamped_data(timeout: i64, channel: i32) -> TimestampedData {
|
||||||
unsafe {
|
unsafe {
|
||||||
TRANSACTION_BUFFER.reply_status.set(0);
|
TRANSACTION_BUFFER.reply_status.set(0);
|
||||||
|
|
||||||
|
@ -291,35 +243,19 @@ pub extern "C" fn input_timestamped_data(timeout: i64, channel: i32) -> Timestam
|
||||||
loop {
|
loop {
|
||||||
status = TRANSACTION_BUFFER.reply_status.get();
|
status = TRANSACTION_BUFFER.reply_status.get();
|
||||||
if status != 0 {
|
if status != 0 {
|
||||||
break;
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if status & RTIO_I_STATUS_OVERFLOW != 0 {
|
if status & RTIO_I_STATUS_OVERFLOW != 0 {
|
||||||
artiq_raise!(
|
artiq_raise!("RTIOOverflow",
|
||||||
"RTIOOverflow",
|
"RTIO input overflow on channel {0}",
|
||||||
format!(
|
channel as i64, 0, 0);
|
||||||
"RTIO input overflow on channel 0x{:04x}:{}",
|
|
||||||
channel,
|
|
||||||
resolve_channel_name(channel as u32)
|
|
||||||
),
|
|
||||||
channel as i64,
|
|
||||||
0,
|
|
||||||
0
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
if status & RTIO_I_STATUS_DESTINATION_UNREACHABLE != 0 {
|
if status & RTIO_I_STATUS_DESTINATION_UNREACHABLE != 0 {
|
||||||
artiq_raise!(
|
artiq_raise!("RTIODestinationUnreachable",
|
||||||
"RTIODestinationUnreachable",
|
"RTIO destination unreachable, input, on channel {0}",
|
||||||
format!(
|
channel as i64, 0, 0);
|
||||||
"RTIO destination unreachable, input, on channel 0x{:04x}:{}",
|
|
||||||
channel,
|
|
||||||
resolve_channel_name(channel as u32)
|
|
||||||
),
|
|
||||||
channel as i64,
|
|
||||||
0,
|
|
||||||
0
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TimestampedData {
|
TimestampedData {
|
||||||
|
|
|
@ -1,15 +1,14 @@
|
||||||
|
use log::{info, warn, error};
|
||||||
|
use libboard_zynq::timer::GlobalTimer;
|
||||||
use embedded_hal::blocking::delay::DelayMs;
|
use embedded_hal::blocking::delay::DelayMs;
|
||||||
|
use libconfig::Config;
|
||||||
use libboard_artiq::pl;
|
use libboard_artiq::pl;
|
||||||
#[cfg(has_si5324)]
|
#[cfg(has_si5324)]
|
||||||
use libboard_artiq::si5324;
|
|
||||||
#[cfg(has_si5324)]
|
|
||||||
use libboard_zynq::i2c::I2c;
|
use libboard_zynq::i2c::I2c;
|
||||||
use libboard_zynq::timer::GlobalTimer;
|
|
||||||
use libconfig::Config;
|
|
||||||
use log::{info, warn};
|
|
||||||
|
|
||||||
#[cfg(has_si5324)]
|
#[cfg(has_si5324)]
|
||||||
use crate::i2c;
|
use crate::i2c;
|
||||||
|
#[cfg(has_si5324)]
|
||||||
|
use libboard_artiq::si5324;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Copy, Clone)]
|
#[derive(Debug, PartialEq, Copy, Clone)]
|
||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
|
@ -38,21 +37,22 @@ fn get_rtio_clock_cfg(cfg: &Config) -> RtioClock {
|
||||||
"ext0_synth0_10to125" => RtioClock::Ext0_Synth0_10to125,
|
"ext0_synth0_10to125" => RtioClock::Ext0_Synth0_10to125,
|
||||||
"ext0_synth0_100to125" => RtioClock::Ext0_Synth0_100to125,
|
"ext0_synth0_100to125" => RtioClock::Ext0_Synth0_100to125,
|
||||||
"ext0_synth0_125to125" => RtioClock::Ext0_Synth0_125to125,
|
"ext0_synth0_125to125" => RtioClock::Ext0_Synth0_125to125,
|
||||||
_ => {
|
_ => {
|
||||||
warn!("Unrecognised rtio_clock setting. Falling back to default.");
|
warn!("Unrecognised rtio_clock setting. Falling back to default.");
|
||||||
RtioClock::Default
|
RtioClock::Default
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
warn!("error reading configuration. Falling back to default.");
|
warn!("error reading configuration. Falling back to default.");
|
||||||
}
|
}
|
||||||
if res == RtioClock::Default {
|
if res == RtioClock::Default {
|
||||||
#[cfg(rtio_frequency = "100.0")]
|
#[cfg(rtio_frequency="100.0")]
|
||||||
{
|
{
|
||||||
warn!("Using default configuration - internal 100MHz RTIO clock.");
|
warn!("Using default configuration - internal 100MHz RTIO clock.");
|
||||||
return RtioClock::Int_100;
|
return RtioClock::Int_100;
|
||||||
}
|
}
|
||||||
#[cfg(rtio_frequency = "125.0")]
|
#[cfg(rtio_frequency="125.0")]
|
||||||
{
|
{
|
||||||
warn!("Using default configuration - internal 125MHz RTIO clock.");
|
warn!("Using default configuration - internal 125MHz RTIO clock.");
|
||||||
return RtioClock::Int_125;
|
return RtioClock::Int_125;
|
||||||
|
@ -66,173 +66,168 @@ fn get_rtio_clock_cfg(cfg: &Config) -> RtioClock {
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(has_drtio))]
|
|
||||||
fn init_rtio(timer: &mut GlobalTimer) {
|
|
||||||
info!("Switching SYS clocks...");
|
|
||||||
unsafe {
|
|
||||||
pl::csr::sys_crg::clock_switch_write(1);
|
|
||||||
}
|
|
||||||
// if it's not locked, it will hang at the CSR.
|
|
||||||
|
|
||||||
timer.delay_ms(20); // wait for CPLL/QPLL/SYS PLL lock
|
fn init_rtio(timer: &mut GlobalTimer, _clk: RtioClock) {
|
||||||
let clk = unsafe { pl::csr::sys_crg::current_clock_read() };
|
#[cfg(has_rtio_crg_clock_sel)]
|
||||||
if clk == 1 {
|
let clock_sel = match _clk {
|
||||||
info!("SYS CLK switched successfully");
|
RtioClock::Ext0_Bypass => {
|
||||||
} else {
|
info!("Using bypassed external clock");
|
||||||
panic!("SYS CLK did not switch");
|
1
|
||||||
|
},
|
||||||
|
RtioClock::Int_125 => {
|
||||||
|
info!("Using internal RTIO clock");
|
||||||
|
0
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
warn!("rtio_clock setting '{:?}' is not supported. Using default internal RTIO clock instead", _clk);
|
||||||
|
0
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
pl::csr::rtio_crg::pll_reset_write(1);
|
||||||
|
#[cfg(has_rtio_crg_clock_sel)]
|
||||||
|
pl::csr::rtio_crg::clock_sel_write(clock_sel);
|
||||||
|
pl::csr::rtio_crg::pll_reset_write(0);
|
||||||
}
|
}
|
||||||
|
timer.delay_ms(1);
|
||||||
|
let locked = unsafe { pl::csr::rtio_crg::pll_locked_read() != 0 };
|
||||||
|
if locked {
|
||||||
|
info!("RTIO PLL locked");
|
||||||
|
} else {
|
||||||
|
error!("RTIO PLL failed to lock");
|
||||||
|
}
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
pl::csr::rtio_core::reset_phy_write(1);
|
pl::csr::rtio_core::reset_phy_write(1);
|
||||||
}
|
}
|
||||||
info!("SYS PLL locked");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(has_drtio)]
|
#[cfg(has_drtio)]
|
||||||
fn init_drtio(timer: &mut GlobalTimer) {
|
fn init_drtio(timer: &mut GlobalTimer)
|
||||||
|
{
|
||||||
unsafe {
|
unsafe {
|
||||||
pl::csr::drtio_transceiver::stable_clkin_write(1);
|
pl::csr::drtio_transceiver::stable_clkin_write(1);
|
||||||
}
|
}
|
||||||
|
timer.delay_ms(2); // wait for CPLL/QPLL lock
|
||||||
timer.delay_ms(20); // wait for CPLL/QPLL/SYS PLL lock
|
|
||||||
let clk = unsafe { pl::csr::sys_crg::current_clock_read() };
|
|
||||||
if clk == 1 {
|
|
||||||
info!("SYS CLK switched successfully");
|
|
||||||
} else {
|
|
||||||
panic!("SYS CLK did not switch");
|
|
||||||
}
|
|
||||||
unsafe {
|
unsafe {
|
||||||
pl::csr::rtio_core::reset_phy_write(1);
|
|
||||||
pl::csr::drtio_transceiver::txenable_write(0xffffffffu32 as _);
|
pl::csr::drtio_transceiver::txenable_write(0xffffffffu32 as _);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Si5324 input to select for locking to an external clock.
|
|
||||||
#[cfg(has_si5324)]
|
|
||||||
const SI5324_EXT_INPUT: si5324::Input = si5324::Input::Ckin1;
|
|
||||||
|
|
||||||
#[cfg(has_si5324)]
|
#[cfg(has_si5324)]
|
||||||
fn setup_si5324(i2c: &mut I2c, timer: &mut GlobalTimer, clk: RtioClock) {
|
fn setup_si5324(i2c: &mut I2c, timer: &mut GlobalTimer, clk: RtioClock) {
|
||||||
let (si5324_settings, si5324_ref_input) = match clk {
|
let (si5324_settings, si5324_ref_input) = match clk {
|
||||||
RtioClock::Ext0_Synth0_10to125 => {
|
RtioClock::Ext0_Synth0_10to125 => { // 125 MHz output from 10 MHz CLKINx reference, 504 Hz BW
|
||||||
// 125 MHz output from 10 MHz CLKINx reference, 504 Hz BW
|
|
||||||
info!("using 10MHz reference to make 125MHz RTIO clock with PLL");
|
info!("using 10MHz reference to make 125MHz RTIO clock with PLL");
|
||||||
(
|
(
|
||||||
si5324::FrequencySettings {
|
si5324::FrequencySettings {
|
||||||
n1_hs: 10,
|
n1_hs : 10,
|
||||||
nc1_ls: 4,
|
nc1_ls : 4,
|
||||||
n2_hs: 10,
|
n2_hs : 10,
|
||||||
n2_ls: 300,
|
n2_ls : 300,
|
||||||
n31: 6,
|
n31 : 6,
|
||||||
n32: 6,
|
n32 : 6,
|
||||||
bwsel: 4,
|
bwsel : 4,
|
||||||
crystal_as_ckin2: false,
|
crystal_ref: false
|
||||||
},
|
},
|
||||||
SI5324_EXT_INPUT,
|
si5324::Input::Ckin1
|
||||||
)
|
)
|
||||||
}
|
},
|
||||||
RtioClock::Ext0_Synth0_100to125 => {
|
RtioClock::Ext0_Synth0_100to125 => { // 125MHz output, from 100MHz CLKINx reference, 586 Hz loop bandwidth
|
||||||
// 125MHz output, from 100MHz CLKINx reference, 586 Hz loop bandwidth
|
|
||||||
info!("using 100MHz reference to make 125MHz RTIO clock with PLL");
|
info!("using 100MHz reference to make 125MHz RTIO clock with PLL");
|
||||||
(
|
(
|
||||||
si5324::FrequencySettings {
|
si5324::FrequencySettings {
|
||||||
n1_hs: 10,
|
n1_hs : 10,
|
||||||
nc1_ls: 4,
|
nc1_ls : 4,
|
||||||
n2_hs: 10,
|
n2_hs : 10,
|
||||||
n2_ls: 260,
|
n2_ls : 260,
|
||||||
n31: 52,
|
n31 : 52,
|
||||||
n32: 52,
|
n32 : 52,
|
||||||
bwsel: 4,
|
bwsel : 4,
|
||||||
crystal_as_ckin2: false,
|
crystal_ref: false
|
||||||
},
|
},
|
||||||
SI5324_EXT_INPUT,
|
si5324::Input::Ckin1
|
||||||
)
|
)
|
||||||
}
|
},
|
||||||
RtioClock::Ext0_Synth0_125to125 => {
|
RtioClock::Ext0_Synth0_125to125 => { // 125MHz output, from 125MHz CLKINx reference, 606 Hz loop bandwidth
|
||||||
// 125MHz output, from 125MHz CLKINx reference, 606 Hz loop bandwidth
|
|
||||||
info!("using 125MHz reference to make 125MHz RTIO clock with PLL");
|
info!("using 125MHz reference to make 125MHz RTIO clock with PLL");
|
||||||
(
|
(
|
||||||
si5324::FrequencySettings {
|
si5324::FrequencySettings {
|
||||||
n1_hs: 5,
|
n1_hs : 5,
|
||||||
nc1_ls: 8,
|
nc1_ls : 8,
|
||||||
n2_hs: 7,
|
n2_hs : 7,
|
||||||
n2_ls: 360,
|
n2_ls : 360,
|
||||||
n31: 63,
|
n31 : 63,
|
||||||
n32: 63,
|
n32 : 63,
|
||||||
bwsel: 4,
|
bwsel : 4,
|
||||||
crystal_as_ckin2: false,
|
crystal_ref: false
|
||||||
},
|
},
|
||||||
SI5324_EXT_INPUT,
|
si5324::Input::Ckin1
|
||||||
)
|
)
|
||||||
}
|
},
|
||||||
RtioClock::Int_150 => {
|
RtioClock::Int_150 => { // 150MHz output, from crystal
|
||||||
// 150MHz output, from crystal
|
|
||||||
info!("using internal 150MHz RTIO clock");
|
info!("using internal 150MHz RTIO clock");
|
||||||
(
|
(
|
||||||
si5324::FrequencySettings {
|
si5324::FrequencySettings {
|
||||||
n1_hs: 9,
|
n1_hs : 9,
|
||||||
nc1_ls: 4,
|
nc1_ls : 4,
|
||||||
n2_hs: 10,
|
n2_hs : 10,
|
||||||
n2_ls: 33732,
|
n2_ls : 33732,
|
||||||
n31: 7139,
|
n31 : 7139,
|
||||||
n32: 7139,
|
n32 : 7139,
|
||||||
bwsel: 3,
|
bwsel : 3,
|
||||||
crystal_as_ckin2: true,
|
crystal_ref: true
|
||||||
},
|
},
|
||||||
si5324::Input::Ckin2,
|
si5324::Input::Ckin2
|
||||||
)
|
)
|
||||||
}
|
},
|
||||||
RtioClock::Int_100 => {
|
RtioClock::Int_100 => { // 100MHz output, from crystal.
|
||||||
// 100MHz output, from crystal
|
|
||||||
info!("using internal 100MHz RTIO clock");
|
info!("using internal 100MHz RTIO clock");
|
||||||
(
|
(
|
||||||
si5324::FrequencySettings {
|
si5324::FrequencySettings {
|
||||||
n1_hs: 9,
|
n1_hs : 9,
|
||||||
nc1_ls: 6,
|
nc1_ls : 6,
|
||||||
n2_hs: 10,
|
n2_hs : 10,
|
||||||
n2_ls: 33732,
|
n2_ls : 33732,
|
||||||
n31: 7139,
|
n31 : 7139,
|
||||||
n32: 7139,
|
n32 : 7139,
|
||||||
bwsel: 3,
|
bwsel : 3,
|
||||||
crystal_as_ckin2: true,
|
crystal_ref: true
|
||||||
},
|
},
|
||||||
si5324::Input::Ckin2,
|
si5324::Input::Ckin2
|
||||||
)
|
)
|
||||||
}
|
},
|
||||||
RtioClock::Int_125 => {
|
RtioClock::Int_125 => { // 125MHz output, from crystal, 7 Hz
|
||||||
// 125MHz output, from crystal, 7 Hz
|
|
||||||
info!("using internal 125MHz RTIO clock");
|
info!("using internal 125MHz RTIO clock");
|
||||||
(
|
(
|
||||||
si5324::FrequencySettings {
|
si5324::FrequencySettings {
|
||||||
n1_hs: 10,
|
n1_hs : 10,
|
||||||
nc1_ls: 4,
|
nc1_ls : 4,
|
||||||
n2_hs: 10,
|
n2_hs : 10,
|
||||||
n2_ls: 19972,
|
n2_ls : 19972,
|
||||||
n31: 4565,
|
n31 : 4565,
|
||||||
n32: 4565,
|
n32 : 4565,
|
||||||
bwsel: 4,
|
bwsel : 4,
|
||||||
crystal_as_ckin2: true,
|
crystal_ref: true
|
||||||
},
|
},
|
||||||
si5324::Input::Ckin2,
|
si5324::Input::Ckin2
|
||||||
)
|
)
|
||||||
}
|
},
|
||||||
_ => {
|
_ => { // same setting as Int_125, but fallback to default
|
||||||
// same setting as Int_125, but fallback to default
|
warn!("rtio_clock setting '{:?}' is unsupported. Falling back to default internal 125MHz RTIO clock.", clk);
|
||||||
warn!(
|
|
||||||
"rtio_clock setting '{:?}' is unsupported. Falling back to default internal 125MHz RTIO clock.",
|
|
||||||
clk
|
|
||||||
);
|
|
||||||
(
|
(
|
||||||
si5324::FrequencySettings {
|
si5324::FrequencySettings {
|
||||||
n1_hs: 10,
|
n1_hs : 10,
|
||||||
nc1_ls: 4,
|
nc1_ls : 4,
|
||||||
n2_hs: 10,
|
n2_hs : 10,
|
||||||
n2_ls: 19972,
|
n2_ls : 19972,
|
||||||
n31: 4565,
|
n31 : 4565,
|
||||||
n32: 4565,
|
n32 : 4565,
|
||||||
bwsel: 4,
|
bwsel : 4,
|
||||||
crystal_as_ckin2: true,
|
crystal_ref: true
|
||||||
},
|
},
|
||||||
si5324::Input::Ckin2,
|
si5324::Input::Ckin2
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -240,19 +235,20 @@ fn setup_si5324(i2c: &mut I2c, timer: &mut GlobalTimer, clk: RtioClock) {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init(timer: &mut GlobalTimer, cfg: &Config) {
|
pub fn init(timer: &mut GlobalTimer, cfg: &Config) {
|
||||||
|
|
||||||
let clk = get_rtio_clock_cfg(cfg);
|
let clk = get_rtio_clock_cfg(cfg);
|
||||||
#[cfg(has_si5324)]
|
#[cfg(has_si5324)]
|
||||||
{
|
{
|
||||||
let i2c = unsafe { (&mut i2c::I2C_BUS).as_mut().unwrap() };
|
let i2c = unsafe { (&mut i2c::I2C_BUS).as_mut().unwrap() };
|
||||||
|
let si5324_ext_input = si5324::Input::Ckin1;
|
||||||
match clk {
|
match clk {
|
||||||
RtioClock::Ext0_Bypass => si5324::bypass(i2c, SI5324_EXT_INPUT, timer).expect("cannot bypass Si5324"),
|
RtioClock::Ext0_Bypass => si5324::bypass(i2c, si5324_ext_input, timer).expect("cannot bypass Si5324"),
|
||||||
_ => setup_si5324(i2c, timer, clk),
|
_ => setup_si5324(i2c, timer, clk),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(has_drtio)]
|
#[cfg(has_drtio)]
|
||||||
init_drtio(timer);
|
init_drtio(timer);
|
||||||
|
|
||||||
#[cfg(not(has_drtio))]
|
init_rtio(timer, clk);
|
||||||
init_rtio(timer);
|
|
||||||
}
|
}
|
|
@ -1,16 +1,17 @@
|
||||||
use core::ptr::{read_volatile, write_volatile};
|
use core::ptr::{read_volatile, write_volatile};
|
||||||
|
|
||||||
use cslice::CSlice;
|
use cslice::CSlice;
|
||||||
|
|
||||||
use crate::{artiq_raise, pl::csr, rtio_mgt::resolve_channel_name};
|
use crate::artiq_raise;
|
||||||
|
|
||||||
pub const RTIO_O_STATUS_WAIT: u8 = 1;
|
use crate::pl::csr;
|
||||||
pub const RTIO_O_STATUS_UNDERFLOW: u8 = 2;
|
|
||||||
pub const RTIO_O_STATUS_DESTINATION_UNREACHABLE: u8 = 4;
|
pub const RTIO_O_STATUS_WAIT: u8 = 1;
|
||||||
pub const RTIO_I_STATUS_WAIT_EVENT: u8 = 1;
|
pub const RTIO_O_STATUS_UNDERFLOW: u8 = 2;
|
||||||
pub const RTIO_I_STATUS_OVERFLOW: u8 = 2;
|
pub const RTIO_O_STATUS_DESTINATION_UNREACHABLE: u8 = 4;
|
||||||
pub const RTIO_I_STATUS_WAIT_STATUS: u8 = 4;
|
pub const RTIO_I_STATUS_WAIT_EVENT: u8 = 1;
|
||||||
pub const RTIO_I_STATUS_DESTINATION_UNREACHABLE: u8 = 8;
|
pub const RTIO_I_STATUS_OVERFLOW: u8 = 2;
|
||||||
|
pub const RTIO_I_STATUS_WAIT_STATUS: u8 = 4;
|
||||||
|
pub const RTIO_I_STATUS_DESTINATION_UNREACHABLE: u8 = 8;
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct TimestampedData {
|
pub struct TimestampedData {
|
||||||
|
@ -18,30 +19,32 @@ pub struct TimestampedData {
|
||||||
data: i32,
|
data: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub extern "C" fn init() {
|
pub extern fn init() {
|
||||||
unsafe {
|
unsafe {
|
||||||
csr::rtio_core::reset_write(1);
|
csr::rtio_core::reset_write(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub extern "C" fn get_counter() -> i64 {
|
pub extern fn get_counter() -> i64 {
|
||||||
unsafe {
|
unsafe {
|
||||||
csr::rtio::counter_update_write(1);
|
csr::rtio::counter_update_write(1);
|
||||||
csr::rtio::counter_read() as i64
|
csr::rtio::counter_read() as i64
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub extern "C" fn now_mu() -> i64 {
|
pub extern fn now_mu() -> i64 {
|
||||||
unsafe { csr::rtio::now_read() as i64 }
|
unsafe {
|
||||||
|
csr::rtio::now_read() as i64
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub extern "C" fn at_mu(t: i64) {
|
pub extern fn at_mu(t: i64) {
|
||||||
unsafe {
|
unsafe {
|
||||||
csr::rtio::now_write(t as u64);
|
csr::rtio::now_write(t as u64);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub extern "C" fn delay_mu(dt: i64) {
|
pub extern fn delay_mu(dt: i64) {
|
||||||
unsafe {
|
unsafe {
|
||||||
csr::rtio::now_write(csr::rtio::now_read() + dt as u64);
|
csr::rtio::now_write(csr::rtio::now_read() + dt as u64);
|
||||||
}
|
}
|
||||||
|
@ -52,13 +55,13 @@ pub extern "C" fn delay_mu(dt: i64) {
|
||||||
pub unsafe fn rtio_o_data_write(offset: usize, data: u32) {
|
pub unsafe fn rtio_o_data_write(offset: usize, data: u32) {
|
||||||
write_volatile(
|
write_volatile(
|
||||||
csr::rtio::O_DATA_ADDR.offset((csr::rtio::O_DATA_SIZE - 1 - offset) as isize),
|
csr::rtio::O_DATA_ADDR.offset((csr::rtio::O_DATA_SIZE - 1 - offset) as isize),
|
||||||
data,
|
data);
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub unsafe fn rtio_i_data_read(offset: usize) -> u32 {
|
pub unsafe fn rtio_i_data_read(offset: usize) -> u32 {
|
||||||
read_volatile(csr::rtio::I_DATA_ADDR.offset((csr::rtio::I_DATA_SIZE - 1 - offset) as isize))
|
read_volatile(
|
||||||
|
csr::rtio::I_DATA_ADDR.offset((csr::rtio::I_DATA_SIZE - 1 - offset) as isize))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
|
@ -68,34 +71,18 @@ unsafe fn process_exceptional_status(channel: i32, status: u8) {
|
||||||
while csr::rtio::o_status_read() & RTIO_O_STATUS_WAIT != 0 {}
|
while csr::rtio::o_status_read() & RTIO_O_STATUS_WAIT != 0 {}
|
||||||
}
|
}
|
||||||
if status & RTIO_O_STATUS_UNDERFLOW != 0 {
|
if status & RTIO_O_STATUS_UNDERFLOW != 0 {
|
||||||
artiq_raise!(
|
artiq_raise!("RTIOUnderflow",
|
||||||
"RTIOUnderflow",
|
"RTIO underflow at {0} mu, channel {1}, slack {2} mu",
|
||||||
format!(
|
timestamp, channel as i64, timestamp - get_counter());
|
||||||
"RTIO underflow at {{1}} mu, channel 0x{:04x}:{}, slack {{2}} mu",
|
|
||||||
channel,
|
|
||||||
resolve_channel_name(channel as u32)
|
|
||||||
),
|
|
||||||
channel as i64,
|
|
||||||
timestamp,
|
|
||||||
timestamp - get_counter()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
if status & RTIO_O_STATUS_DESTINATION_UNREACHABLE != 0 {
|
if status & RTIO_O_STATUS_DESTINATION_UNREACHABLE != 0 {
|
||||||
artiq_raise!(
|
artiq_raise!("RTIODestinationUnreachable",
|
||||||
"RTIODestinationUnreachable",
|
"RTIO destination unreachable, output, at {0} mu, channel {1}",
|
||||||
format!(
|
timestamp, channel as i64, 0);
|
||||||
"RTIO destination unreachable, output, at {{0}} mu, channel 0x{:04x}:{}",
|
|
||||||
channel,
|
|
||||||
resolve_channel_name(channel as u32)
|
|
||||||
),
|
|
||||||
timestamp,
|
|
||||||
channel as i64,
|
|
||||||
0
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub extern "C" fn output(target: i32, data: i32) {
|
pub extern fn output(target: i32, data: i32) {
|
||||||
unsafe {
|
unsafe {
|
||||||
csr::rtio::target_write(target as u32);
|
csr::rtio::target_write(target as u32);
|
||||||
// writing target clears o_data
|
// writing target clears o_data
|
||||||
|
@ -107,7 +94,7 @@ pub extern "C" fn output(target: i32, data: i32) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub extern "C" fn output_wide(target: i32, data: CSlice<i32>) {
|
pub extern fn output_wide(target: i32, data: CSlice<i32>) {
|
||||||
unsafe {
|
unsafe {
|
||||||
csr::rtio::target_write(target as u32);
|
csr::rtio::target_write(target as u32);
|
||||||
// writing target clears o_data
|
// writing target clears o_data
|
||||||
|
@ -121,7 +108,7 @@ pub extern "C" fn output_wide(target: i32, data: CSlice<i32>) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub extern "C" fn input_timestamp(timeout: i64, channel: i32) -> i64 {
|
pub extern fn input_timestamp(timeout: i64, channel: i32) -> i64 {
|
||||||
unsafe {
|
unsafe {
|
||||||
csr::rtio::target_write((channel as u32) << 8);
|
csr::rtio::target_write((channel as u32) << 8);
|
||||||
csr::rtio::i_timeout_write(timeout as u64);
|
csr::rtio::i_timeout_write(timeout as u64);
|
||||||
|
@ -132,40 +119,24 @@ pub extern "C" fn input_timestamp(timeout: i64, channel: i32) -> i64 {
|
||||||
}
|
}
|
||||||
|
|
||||||
if status & RTIO_I_STATUS_OVERFLOW != 0 {
|
if status & RTIO_I_STATUS_OVERFLOW != 0 {
|
||||||
artiq_raise!(
|
artiq_raise!("RTIOOverflow",
|
||||||
"RTIOOverflow",
|
"RTIO input overflow on channel {0}",
|
||||||
format!(
|
channel as i64, 0, 0);
|
||||||
"RTIO input overflow on channel 0x{:04x}:{}",
|
|
||||||
channel,
|
|
||||||
resolve_channel_name(channel as u32)
|
|
||||||
),
|
|
||||||
channel as i64,
|
|
||||||
0,
|
|
||||||
0
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
if status & RTIO_I_STATUS_WAIT_EVENT != 0 {
|
if status & RTIO_I_STATUS_WAIT_EVENT != 0 {
|
||||||
return -1;
|
return -1
|
||||||
}
|
}
|
||||||
if status & RTIO_I_STATUS_DESTINATION_UNREACHABLE != 0 {
|
if status & RTIO_I_STATUS_DESTINATION_UNREACHABLE != 0 {
|
||||||
artiq_raise!(
|
artiq_raise!("RTIODestinationUnreachable",
|
||||||
"RTIODestinationUnreachable",
|
"RTIO destination unreachable, input, on channel {0}",
|
||||||
format!(
|
channel as i64, 0, 0);
|
||||||
"RTIO destination unreachable, input, on channel 0x{:04x}:{}",
|
|
||||||
channel,
|
|
||||||
resolve_channel_name(channel as u32)
|
|
||||||
),
|
|
||||||
channel as i64,
|
|
||||||
0,
|
|
||||||
0
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
csr::rtio::i_timestamp_read() as i64
|
csr::rtio::i_timestamp_read() as i64
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub extern "C" fn input_data(channel: i32) -> i32 {
|
pub extern fn input_data(channel: i32) -> i32 {
|
||||||
unsafe {
|
unsafe {
|
||||||
csr::rtio::target_write((channel as u32) << 8);
|
csr::rtio::target_write((channel as u32) << 8);
|
||||||
csr::rtio::i_timeout_write(0xffffffff_ffffffff);
|
csr::rtio::i_timeout_write(0xffffffff_ffffffff);
|
||||||
|
@ -176,37 +147,21 @@ pub extern "C" fn input_data(channel: i32) -> i32 {
|
||||||
}
|
}
|
||||||
|
|
||||||
if status & RTIO_I_STATUS_OVERFLOW != 0 {
|
if status & RTIO_I_STATUS_OVERFLOW != 0 {
|
||||||
artiq_raise!(
|
artiq_raise!("RTIOOverflow",
|
||||||
"RTIOOverflow",
|
"RTIO input overflow on channel {0}",
|
||||||
format!(
|
channel as i64, 0, 0);
|
||||||
"RTIO input overflow on channel 0x{:04x}:{}",
|
|
||||||
channel,
|
|
||||||
resolve_channel_name(channel as u32)
|
|
||||||
),
|
|
||||||
channel as i64,
|
|
||||||
0,
|
|
||||||
0
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
if status & RTIO_I_STATUS_DESTINATION_UNREACHABLE != 0 {
|
if status & RTIO_I_STATUS_DESTINATION_UNREACHABLE != 0 {
|
||||||
artiq_raise!(
|
artiq_raise!("RTIODestinationUnreachable",
|
||||||
"RTIODestinationUnreachable",
|
"RTIO destination unreachable, input, on channel {0}",
|
||||||
format!(
|
channel as i64, 0, 0);
|
||||||
"RTIO destination unreachable, input, on channel 0x{:04x}:{}",
|
|
||||||
channel,
|
|
||||||
resolve_channel_name(channel as u32)
|
|
||||||
),
|
|
||||||
channel as i64,
|
|
||||||
0,
|
|
||||||
0
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rtio_i_data_read(0) as i32
|
rtio_i_data_read(0) as i32
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub extern "C" fn input_timestamped_data(timeout: i64, channel: i32) -> TimestampedData {
|
pub extern fn input_timestamped_data(timeout: i64, channel: i32) -> TimestampedData {
|
||||||
unsafe {
|
unsafe {
|
||||||
csr::rtio::target_write((channel as u32) << 8);
|
csr::rtio::target_write((channel as u32) << 8);
|
||||||
csr::rtio::i_timeout_write(timeout as u64);
|
csr::rtio::i_timeout_write(timeout as u64);
|
||||||
|
@ -217,38 +172,22 @@ pub extern "C" fn input_timestamped_data(timeout: i64, channel: i32) -> Timestam
|
||||||
}
|
}
|
||||||
|
|
||||||
if status & RTIO_I_STATUS_OVERFLOW != 0 {
|
if status & RTIO_I_STATUS_OVERFLOW != 0 {
|
||||||
artiq_raise!(
|
artiq_raise!("RTIOOverflow",
|
||||||
"RTIOOverflow",
|
"RTIO input overflow on channel {0}",
|
||||||
format!(
|
channel as i64, 0, 0);
|
||||||
"RTIO input overflow on channel 0x{:04x}:{}",
|
|
||||||
channel,
|
|
||||||
resolve_channel_name(channel as u32)
|
|
||||||
),
|
|
||||||
channel as i64,
|
|
||||||
0,
|
|
||||||
0
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
if status & RTIO_I_STATUS_WAIT_EVENT != 0 {
|
if status & RTIO_I_STATUS_WAIT_EVENT != 0 {
|
||||||
return TimestampedData { timestamp: -1, data: 0 };
|
return TimestampedData { timestamp: -1, data: 0 }
|
||||||
}
|
}
|
||||||
if status & RTIO_I_STATUS_DESTINATION_UNREACHABLE != 0 {
|
if status & RTIO_I_STATUS_DESTINATION_UNREACHABLE != 0 {
|
||||||
artiq_raise!(
|
artiq_raise!("RTIODestinationUnreachable",
|
||||||
"RTIODestinationUnreachable",
|
"RTIO destination unreachable, input, on channel {0}",
|
||||||
format!(
|
channel as i64, 0, 0);
|
||||||
"RTIO destination unreachable, input, on channel 0x{:04x}:{}",
|
|
||||||
channel,
|
|
||||||
resolve_channel_name(channel as u32)
|
|
||||||
),
|
|
||||||
channel as i64,
|
|
||||||
0,
|
|
||||||
0
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TimestampedData {
|
TimestampedData {
|
||||||
timestamp: csr::rtio::i_timestamp_read() as i64,
|
timestamp: csr::rtio::i_timestamp_read() as i64,
|
||||||
data: rtio_i_data_read(0) as i32,
|
data: rtio_i_data_read(0) as i32
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,349 +0,0 @@
|
||||||
use alloc::{collections::BTreeMap, rc::Rc, string::String, vec::Vec};
|
|
||||||
#[cfg(has_drtio)]
|
|
||||||
use core::mem;
|
|
||||||
|
|
||||||
#[cfg(has_drtio)]
|
|
||||||
use libasync::task;
|
|
||||||
use libboard_artiq::drtio_routing::RoutingTable;
|
|
||||||
use libboard_zynq::timer::GlobalTimer;
|
|
||||||
use libcortex_a9::{cache::dcci_slice, mutex::Mutex};
|
|
||||||
|
|
||||||
use crate::kernel::DmaRecorder;
|
|
||||||
|
|
||||||
const ALIGNMENT: usize = 16 * 8;
|
|
||||||
|
|
||||||
static DMA_RECORD_STORE: Mutex<BTreeMap<String, (u32, Vec<u8>, i64)>> = Mutex::new(BTreeMap::new());
|
|
||||||
|
|
||||||
#[cfg(has_drtio)]
|
|
||||||
pub mod remote_dma {
|
|
||||||
use libboard_zynq::time::Milliseconds;
|
|
||||||
use log::error;
|
|
||||||
|
|
||||||
use super::*;
|
|
||||||
use crate::rtio_mgt::drtio;
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
|
||||||
pub enum RemoteState {
|
|
||||||
NotLoaded,
|
|
||||||
Loaded,
|
|
||||||
PlaybackEnded { error: u8, channel: u32, timestamp: u64 },
|
|
||||||
}
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
struct RemoteTrace {
|
|
||||||
trace: Vec<u8>,
|
|
||||||
pub state: RemoteState,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Vec<u8>> for RemoteTrace {
|
|
||||||
fn from(trace: Vec<u8>) -> Self {
|
|
||||||
RemoteTrace {
|
|
||||||
trace: trace,
|
|
||||||
state: RemoteState::NotLoaded,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RemoteTrace {
|
|
||||||
pub fn get_trace(&self) -> &Vec<u8> {
|
|
||||||
&self.trace
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// represents all traces for a given ID
|
|
||||||
struct TraceSet {
|
|
||||||
id: u32,
|
|
||||||
done_count: Mutex<usize>,
|
|
||||||
traces: Mutex<BTreeMap<u8, RemoteTrace>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TraceSet {
|
|
||||||
pub fn new(id: u32, traces: BTreeMap<u8, Vec<u8>>) -> TraceSet {
|
|
||||||
let mut trace_map: BTreeMap<u8, RemoteTrace> = BTreeMap::new();
|
|
||||||
for (destination, trace) in traces {
|
|
||||||
trace_map.insert(destination, trace.into());
|
|
||||||
}
|
|
||||||
TraceSet {
|
|
||||||
id: id,
|
|
||||||
done_count: Mutex::new(0),
|
|
||||||
traces: Mutex::new(trace_map),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn await_done(&self, timeout: Option<u64>, timer: GlobalTimer) -> Result<RemoteState, &'static str> {
|
|
||||||
let timeout_ms = Milliseconds(timeout.unwrap_or(10_000));
|
|
||||||
let limit = timer.get_time() + timeout_ms;
|
|
||||||
while (timer.get_time() < limit)
|
|
||||||
& (*(self.done_count.async_lock().await) < self.traces.async_lock().await.len())
|
|
||||||
{
|
|
||||||
task::r#yield().await;
|
|
||||||
}
|
|
||||||
if timer.get_time() >= limit {
|
|
||||||
error!("Remote DMA await done timed out");
|
|
||||||
return Err("Timed out waiting for results.");
|
|
||||||
}
|
|
||||||
let mut playback_state: RemoteState = RemoteState::PlaybackEnded {
|
|
||||||
error: 0,
|
|
||||||
channel: 0,
|
|
||||||
timestamp: 0,
|
|
||||||
};
|
|
||||||
let mut lock = self.traces.async_lock().await;
|
|
||||||
let trace_iter = lock.iter_mut();
|
|
||||||
for (_dest, trace) in trace_iter {
|
|
||||||
match trace.state {
|
|
||||||
RemoteState::PlaybackEnded {
|
|
||||||
error: e,
|
|
||||||
channel: _c,
|
|
||||||
timestamp: _ts,
|
|
||||||
} => {
|
|
||||||
if e != 0 {
|
|
||||||
playback_state = trace.state.clone();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
trace.state = RemoteState::Loaded;
|
|
||||||
}
|
|
||||||
Ok(playback_state)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn upload_traces(
|
|
||||||
&mut self,
|
|
||||||
aux_mutex: &Rc<Mutex<bool>>,
|
|
||||||
routing_table: &RoutingTable,
|
|
||||||
timer: GlobalTimer,
|
|
||||||
) {
|
|
||||||
let mut lock = self.traces.async_lock().await;
|
|
||||||
let trace_iter = lock.iter_mut();
|
|
||||||
for (destination, trace) in trace_iter {
|
|
||||||
match drtio::ddma_upload_trace(
|
|
||||||
aux_mutex,
|
|
||||||
routing_table,
|
|
||||||
timer,
|
|
||||||
self.id,
|
|
||||||
*destination,
|
|
||||||
trace.get_trace(),
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
Ok(_) => trace.state = RemoteState::Loaded,
|
|
||||||
Err(e) => error!("Error adding DMA trace on destination {}: {}", destination, e),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*(self.done_count.async_lock().await) = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn erase(&mut self, aux_mutex: &Rc<Mutex<bool>>, routing_table: &RoutingTable, timer: GlobalTimer) {
|
|
||||||
let lock = self.traces.async_lock().await;
|
|
||||||
let trace_iter = lock.keys();
|
|
||||||
for destination in trace_iter {
|
|
||||||
match drtio::ddma_send_erase(aux_mutex, routing_table, timer, self.id, *destination).await {
|
|
||||||
Ok(_) => (),
|
|
||||||
Err(e) => error!("Error adding DMA trace on destination {}: {}", destination, e),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn playback_done(&mut self, destination: u8, error: u8, channel: u32, timestamp: u64) {
|
|
||||||
let mut traces_locked = self.traces.async_lock().await;
|
|
||||||
let mut trace = traces_locked.get_mut(&destination).unwrap();
|
|
||||||
trace.state = RemoteState::PlaybackEnded {
|
|
||||||
error: error,
|
|
||||||
channel: channel,
|
|
||||||
timestamp: timestamp,
|
|
||||||
};
|
|
||||||
*(self.done_count.async_lock().await) += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn playback(
|
|
||||||
&self,
|
|
||||||
aux_mutex: &Rc<Mutex<bool>>,
|
|
||||||
routing_table: &RoutingTable,
|
|
||||||
timer: GlobalTimer,
|
|
||||||
timestamp: u64,
|
|
||||||
) {
|
|
||||||
let mut dest_list: Vec<u8> = Vec::new();
|
|
||||||
{
|
|
||||||
let lock = self.traces.async_lock().await;
|
|
||||||
let trace_iter = lock.iter();
|
|
||||||
for (dest, trace) in trace_iter {
|
|
||||||
if trace.state != RemoteState::Loaded {
|
|
||||||
error!("Destination {} not ready for DMA, state: {:?}", dest, trace.state);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
dest_list.push(dest.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// mutex lock must be dropped before sending a playback request to avoid a deadlock,
|
|
||||||
// if PlaybackStatus is sent from another satellite and the state must be updated.
|
|
||||||
for destination in dest_list {
|
|
||||||
match drtio::ddma_send_playback(aux_mutex, routing_table, timer, self.id, destination, timestamp).await
|
|
||||||
{
|
|
||||||
Ok(_) => (),
|
|
||||||
Err(e) => error!("Error during remote DMA playback: {}", e),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn destination_changed(
|
|
||||||
&mut self,
|
|
||||||
aux_mutex: &Rc<Mutex<bool>>,
|
|
||||||
routing_table: &RoutingTable,
|
|
||||||
timer: GlobalTimer,
|
|
||||||
destination: u8,
|
|
||||||
up: bool,
|
|
||||||
) {
|
|
||||||
// update state of the destination, resend traces if it's up
|
|
||||||
if let Some(trace) = self.traces.lock().get_mut(&destination) {
|
|
||||||
if up {
|
|
||||||
match drtio::ddma_upload_trace(
|
|
||||||
aux_mutex,
|
|
||||||
routing_table,
|
|
||||||
timer,
|
|
||||||
self.id,
|
|
||||||
destination,
|
|
||||||
trace.get_trace(),
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
Ok(_) => trace.state = RemoteState::Loaded,
|
|
||||||
Err(e) => error!("Error adding DMA trace on destination {}: {}", destination, e),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
trace.state = RemoteState::NotLoaded;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static mut TRACES: BTreeMap<u32, TraceSet> = BTreeMap::new();
|
|
||||||
|
|
||||||
pub fn add_traces(id: u32, traces: BTreeMap<u8, Vec<u8>>) {
|
|
||||||
unsafe { TRACES.insert(id, TraceSet::new(id, traces)) };
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn await_done(id: u32, timeout: Option<u64>, timer: GlobalTimer) -> Result<RemoteState, &'static str> {
|
|
||||||
let trace_set = unsafe { TRACES.get_mut(&id).unwrap() };
|
|
||||||
trace_set.await_done(timeout, timer).await
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn erase(aux_mutex: &Rc<Mutex<bool>>, routing_table: &RoutingTable, timer: GlobalTimer, id: u32) {
|
|
||||||
let trace_set = unsafe { TRACES.get_mut(&id).unwrap() };
|
|
||||||
trace_set.erase(aux_mutex, routing_table, timer).await;
|
|
||||||
unsafe {
|
|
||||||
TRACES.remove(&id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn upload_traces(aux_mutex: &Rc<Mutex<bool>>, routing_table: &RoutingTable, timer: GlobalTimer, id: u32) {
|
|
||||||
let trace_set = unsafe { TRACES.get_mut(&id).unwrap() };
|
|
||||||
trace_set.upload_traces(aux_mutex, routing_table, timer).await;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn playback(
|
|
||||||
aux_mutex: &Rc<Mutex<bool>>,
|
|
||||||
routing_table: &RoutingTable,
|
|
||||||
timer: GlobalTimer,
|
|
||||||
id: u32,
|
|
||||||
timestamp: u64,
|
|
||||||
) {
|
|
||||||
let trace_set = unsafe { TRACES.get_mut(&id).unwrap() };
|
|
||||||
trace_set.playback(aux_mutex, routing_table, timer, timestamp).await;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn playback_done(id: u32, destination: u8, error: u8, channel: u32, timestamp: u64) {
|
|
||||||
let trace_set = unsafe { TRACES.get_mut(&id).unwrap() };
|
|
||||||
trace_set.playback_done(destination, error, channel, timestamp).await;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn destination_changed(
|
|
||||||
aux_mutex: &Rc<Mutex<bool>>,
|
|
||||||
routing_table: &RoutingTable,
|
|
||||||
timer: GlobalTimer,
|
|
||||||
destination: u8,
|
|
||||||
up: bool,
|
|
||||||
) {
|
|
||||||
let trace_iter = unsafe { TRACES.values_mut() };
|
|
||||||
for trace_set in trace_iter {
|
|
||||||
trace_set
|
|
||||||
.destination_changed(aux_mutex, routing_table, timer, destination, up)
|
|
||||||
.await;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn put_record(
|
|
||||||
_aux_mutex: &Rc<Mutex<bool>>,
|
|
||||||
_routing_table: &RoutingTable,
|
|
||||||
_timer: GlobalTimer,
|
|
||||||
mut recorder: DmaRecorder,
|
|
||||||
) -> u32 {
|
|
||||||
#[cfg(has_drtio)]
|
|
||||||
let mut remote_traces: BTreeMap<u8, Vec<u8>> = BTreeMap::new();
|
|
||||||
|
|
||||||
#[cfg(has_drtio)]
|
|
||||||
if recorder.enable_ddma {
|
|
||||||
let mut local_trace: Vec<u8> = Vec::new();
|
|
||||||
// analyze each entry and put in proper buckets, as the kernel core
|
|
||||||
// sends whole chunks, to limit comms/kernel CPU communication,
|
|
||||||
// and as only comms core has access to varios DMA buffers.
|
|
||||||
let mut ptr = 0;
|
|
||||||
recorder.buffer.push(0);
|
|
||||||
while recorder.buffer[ptr] != 0 {
|
|
||||||
// ptr + 3 = tgt >> 24 (destination)
|
|
||||||
let len = recorder.buffer[ptr] as usize;
|
|
||||||
let destination = recorder.buffer[ptr + 3];
|
|
||||||
if destination == 0 {
|
|
||||||
local_trace.extend(&recorder.buffer[ptr..ptr + len]);
|
|
||||||
} else {
|
|
||||||
if let Some(remote_trace) = remote_traces.get_mut(&destination) {
|
|
||||||
remote_trace.extend(&recorder.buffer[ptr..ptr + len]);
|
|
||||||
} else {
|
|
||||||
remote_traces.insert(destination, recorder.buffer[ptr..ptr + len].to_vec());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// and jump to the next event
|
|
||||||
ptr += len;
|
|
||||||
}
|
|
||||||
mem::swap(&mut recorder.buffer, &mut local_trace);
|
|
||||||
}
|
|
||||||
// trailing zero to indicate end of buffer
|
|
||||||
recorder.buffer.push(0);
|
|
||||||
recorder.buffer.reserve(ALIGNMENT - 1);
|
|
||||||
let original_length = recorder.buffer.len();
|
|
||||||
let padding = ALIGNMENT - recorder.buffer.as_ptr() as usize % ALIGNMENT;
|
|
||||||
let padding = if padding == ALIGNMENT { 0 } else { padding };
|
|
||||||
for _ in 0..padding {
|
|
||||||
recorder.buffer.push(0);
|
|
||||||
}
|
|
||||||
recorder.buffer.copy_within(0..original_length, padding);
|
|
||||||
dcci_slice(&recorder.buffer);
|
|
||||||
|
|
||||||
let ptr = recorder.buffer[padding..].as_ptr() as u32;
|
|
||||||
|
|
||||||
let _old_record = DMA_RECORD_STORE
|
|
||||||
.lock()
|
|
||||||
.insert(recorder.name, (ptr, recorder.buffer, recorder.duration));
|
|
||||||
|
|
||||||
#[cfg(has_drtio)]
|
|
||||||
{
|
|
||||||
if let Some((old_id, _v, _d)) = _old_record {
|
|
||||||
remote_dma::erase(_aux_mutex, _routing_table, _timer, old_id).await;
|
|
||||||
}
|
|
||||||
remote_dma::add_traces(ptr, remote_traces);
|
|
||||||
}
|
|
||||||
|
|
||||||
ptr
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn erase(name: String, _aux_mutex: &Rc<Mutex<bool>>, _routing_table: &RoutingTable, _timer: GlobalTimer) {
|
|
||||||
let _entry = DMA_RECORD_STORE.lock().remove(&name);
|
|
||||||
#[cfg(has_drtio)]
|
|
||||||
if let Some((id, _v, _d)) = _entry {
|
|
||||||
remote_dma::erase(_aux_mutex, _routing_table, _timer, id).await;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn retrieve(name: String) -> Option<(i32, i64)> {
|
|
||||||
let (ptr, _v, duration) = DMA_RECORD_STORE.lock().get(&name)?.clone();
|
|
||||||
Some((ptr as i32, duration))
|
|
||||||
}
|
|
|
@ -1,35 +1,26 @@
|
||||||
use alloc::{collections::BTreeMap, rc::Rc, string::String};
|
|
||||||
use core::cell::RefCell;
|
use core::cell::RefCell;
|
||||||
|
use alloc::rc::Rc;
|
||||||
use io::{Cursor, ProtoRead};
|
|
||||||
use libboard_artiq::{drtio_routing, pl::csr};
|
|
||||||
use libboard_zynq::timer::GlobalTimer;
|
use libboard_zynq::timer::GlobalTimer;
|
||||||
use libconfig::Config;
|
use libboard_artiq::{pl::csr, drtio_routing};
|
||||||
use libcortex_a9::mutex::Mutex;
|
use libcortex_a9::mutex::Mutex;
|
||||||
use log::warn;
|
|
||||||
|
|
||||||
static mut RTIO_DEVICE_MAP: BTreeMap<u32, String> = BTreeMap::new();
|
|
||||||
|
|
||||||
#[cfg(has_drtio)]
|
#[cfg(has_drtio)]
|
||||||
pub mod drtio {
|
pub mod drtio {
|
||||||
use alloc::vec::Vec;
|
|
||||||
|
|
||||||
use embedded_hal::blocking::delay::DelayMs;
|
|
||||||
use libasync::{delay, task};
|
|
||||||
use libboard_artiq::{drtioaux::Error, drtioaux_async, drtioaux_async::Packet, drtioaux_proto::DMA_TRACE_MAX_SIZE};
|
|
||||||
use libboard_zynq::time::Milliseconds;
|
|
||||||
use log::{error, info, warn};
|
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::{rtio_dma::remote_dma, ASYNC_ERROR_BUSY, ASYNC_ERROR_COLLISION, ASYNC_ERROR_SEQUENCE_ERROR,
|
use crate::{SEEN_ASYNC_ERRORS, ASYNC_ERROR_BUSY, ASYNC_ERROR_SEQUENCE_ERROR, ASYNC_ERROR_COLLISION};
|
||||||
SEEN_ASYNC_ERRORS};
|
use libboard_artiq::drtioaux_async;
|
||||||
|
use libboard_artiq::drtioaux_async::Packet;
|
||||||
|
use libboard_artiq::drtioaux::Error;
|
||||||
|
use log::{warn, error, info};
|
||||||
|
use embedded_hal::blocking::delay::DelayMs;
|
||||||
|
use libasync::{task, delay};
|
||||||
|
use libboard_zynq::time::Milliseconds;
|
||||||
|
|
||||||
pub fn startup(
|
pub fn startup(aux_mutex: &Rc<Mutex<bool>>,
|
||||||
aux_mutex: &Rc<Mutex<bool>>,
|
routing_table: &Rc<RefCell<drtio_routing::RoutingTable>>,
|
||||||
routing_table: &Rc<RefCell<drtio_routing::RoutingTable>>,
|
up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>,
|
||||||
up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>,
|
timer: GlobalTimer) {
|
||||||
timer: GlobalTimer,
|
|
||||||
) {
|
|
||||||
let aux_mutex = aux_mutex.clone();
|
let aux_mutex = aux_mutex.clone();
|
||||||
let routing_table = routing_table.clone();
|
let routing_table = routing_table.clone();
|
||||||
let up_destinations = up_destinations.clone();
|
let up_destinations = up_destinations.clone();
|
||||||
|
@ -41,7 +32,9 @@ pub mod drtio {
|
||||||
|
|
||||||
async fn link_rx_up(linkno: u8) -> bool {
|
async fn link_rx_up(linkno: u8) -> bool {
|
||||||
let linkno = linkno as usize;
|
let linkno = linkno as usize;
|
||||||
unsafe { (csr::DRTIO[linkno].rx_up_read)() == 1 }
|
unsafe {
|
||||||
|
(csr::DRTIO[linkno].rx_up_read)() == 1
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn recv_aux_timeout(linkno: u8, timeout: u64, timer: GlobalTimer) -> Result<Packet, &'static str> {
|
async fn recv_aux_timeout(linkno: u8, timeout: u64, timer: GlobalTimer) -> Result<Packet, &'static str> {
|
||||||
|
@ -55,33 +48,14 @@ pub mod drtio {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn aux_transact(
|
pub async fn aux_transact(aux_mutex: &Mutex<bool>, linkno: u8, request: &Packet,
|
||||||
aux_mutex: &Mutex<bool>,
|
timer: GlobalTimer) -> Result<Packet, &'static str> {
|
||||||
linkno: u8,
|
|
||||||
request: &Packet,
|
|
||||||
timer: GlobalTimer,
|
|
||||||
) -> Result<Packet, &'static str> {
|
|
||||||
if !link_rx_up(linkno).await {
|
if !link_rx_up(linkno).await {
|
||||||
return Err("link went down");
|
return Err("link went down");
|
||||||
}
|
}
|
||||||
let _lock = aux_mutex.async_lock().await;
|
let _lock = aux_mutex.async_lock().await;
|
||||||
drtioaux_async::send(linkno, request).await.unwrap();
|
drtioaux_async::send(linkno, request).await.unwrap();
|
||||||
loop {
|
recv_aux_timeout(linkno, 200, timer).await
|
||||||
let reply = recv_aux_timeout(linkno, 200, timer).await;
|
|
||||||
match reply {
|
|
||||||
Ok(Packet::DmaPlaybackStatus {
|
|
||||||
id,
|
|
||||||
destination,
|
|
||||||
error,
|
|
||||||
channel,
|
|
||||||
timestamp,
|
|
||||||
}) => {
|
|
||||||
remote_dma::playback_done(id, destination, error, channel, timestamp).await;
|
|
||||||
}
|
|
||||||
Ok(packet) => return Ok(packet),
|
|
||||||
Err(e) => return Err(e),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn drain_buffer(linkno: u8, draining_time: Milliseconds, timer: GlobalTimer) {
|
async fn drain_buffer(linkno: u8, draining_time: Milliseconds, timer: GlobalTimer) {
|
||||||
|
@ -98,7 +72,7 @@ pub mod drtio {
|
||||||
let mut count = 0;
|
let mut count = 0;
|
||||||
loop {
|
loop {
|
||||||
if !link_rx_up(linkno).await {
|
if !link_rx_up(linkno).await {
|
||||||
return 0;
|
return 0
|
||||||
}
|
}
|
||||||
count += 1;
|
count += 1;
|
||||||
if count > 100 {
|
if count > 100 {
|
||||||
|
@ -134,23 +108,13 @@ pub mod drtio {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn load_routing_table(
|
async fn load_routing_table(aux_mutex: &Rc<Mutex<bool>>, linkno: u8, routing_table: &drtio_routing::RoutingTable,
|
||||||
aux_mutex: &Rc<Mutex<bool>>,
|
timer: GlobalTimer) -> Result<(), &'static str> {
|
||||||
linkno: u8,
|
|
||||||
routing_table: &drtio_routing::RoutingTable,
|
|
||||||
timer: GlobalTimer,
|
|
||||||
) -> Result<(), &'static str> {
|
|
||||||
for i in 0..drtio_routing::DEST_COUNT {
|
for i in 0..drtio_routing::DEST_COUNT {
|
||||||
let reply = aux_transact(
|
let reply = aux_transact(aux_mutex, linkno, &Packet::RoutingSetPath {
|
||||||
aux_mutex,
|
destination: i as u8,
|
||||||
linkno,
|
hops: routing_table.0[i]
|
||||||
&Packet::RoutingSetPath {
|
}, timer).await?;
|
||||||
destination: i as u8,
|
|
||||||
hops: routing_table.0[i],
|
|
||||||
},
|
|
||||||
timer,
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
if reply != Packet::RoutingAck {
|
if reply != Packet::RoutingAck {
|
||||||
return Err("unexpected reply");
|
return Err("unexpected reply");
|
||||||
}
|
}
|
||||||
|
@ -158,13 +122,10 @@ pub mod drtio {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn set_rank(
|
async fn set_rank(aux_mutex: &Rc<Mutex<bool>>, linkno: u8, rank: u8, timer: GlobalTimer) -> Result<(), &'static str> {
|
||||||
aux_mutex: &Rc<Mutex<bool>>,
|
let reply = aux_transact(aux_mutex, linkno, &Packet::RoutingSetRank {
|
||||||
linkno: u8,
|
rank: rank
|
||||||
rank: u8,
|
}, timer).await?;
|
||||||
timer: GlobalTimer,
|
|
||||||
) -> Result<(), &'static str> {
|
|
||||||
let reply = aux_transact(aux_mutex, linkno, &Packet::RoutingSetRank { rank: rank }, timer).await?;
|
|
||||||
if reply != Packet::RoutingAck {
|
if reply != Packet::RoutingAck {
|
||||||
return Err("unexpected reply");
|
return Err("unexpected reply");
|
||||||
}
|
}
|
||||||
|
@ -178,11 +139,8 @@ pub mod drtio {
|
||||||
(csr::DRTIO[linkno].force_destination_write)(1);
|
(csr::DRTIO[linkno].force_destination_write)(1);
|
||||||
(csr::DRTIO[linkno].o_get_buffer_space_write)(1);
|
(csr::DRTIO[linkno].o_get_buffer_space_write)(1);
|
||||||
while (csr::DRTIO[linkno].o_wait_read)() == 1 {}
|
while (csr::DRTIO[linkno].o_wait_read)() == 1 {}
|
||||||
info!(
|
info!("[DEST#{}] buffer space is {}",
|
||||||
"[DEST#{}] buffer space is {}",
|
destination, (csr::DRTIO[linkno].o_dbg_buffer_space_read)());
|
||||||
destination,
|
|
||||||
(csr::DRTIO[linkno].o_dbg_buffer_space_read)()
|
|
||||||
);
|
|
||||||
(csr::DRTIO[linkno].force_destination_write)(0);
|
(csr::DRTIO[linkno].force_destination_write)(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -190,16 +148,9 @@ pub mod drtio {
|
||||||
async fn process_unsolicited_aux(aux_mutex: &Rc<Mutex<bool>>, linkno: u8) {
|
async fn process_unsolicited_aux(aux_mutex: &Rc<Mutex<bool>>, linkno: u8) {
|
||||||
let _lock = aux_mutex.async_lock().await;
|
let _lock = aux_mutex.async_lock().await;
|
||||||
match drtioaux_async::recv(linkno).await {
|
match drtioaux_async::recv(linkno).await {
|
||||||
Ok(Some(Packet::DmaPlaybackStatus {
|
|
||||||
id,
|
|
||||||
destination,
|
|
||||||
error,
|
|
||||||
channel,
|
|
||||||
timestamp,
|
|
||||||
})) => remote_dma::playback_done(id, destination, error, channel, timestamp).await,
|
|
||||||
Ok(Some(packet)) => warn!("[LINK#{}] unsolicited aux packet: {:?}", linkno, packet),
|
Ok(Some(packet)) => warn!("[LINK#{}] unsolicited aux packet: {:?}", linkno, packet),
|
||||||
Ok(None) => (),
|
Ok(None) => (),
|
||||||
Err(_) => warn!("[LINK#{}] aux packet error", linkno),
|
Err(_) => warn!("[LINK#{}] aux packet error", linkno)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -224,12 +175,9 @@ pub mod drtio {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn destination_set_up(
|
async fn destination_set_up(routing_table: &drtio_routing::RoutingTable,
|
||||||
routing_table: &drtio_routing::RoutingTable,
|
up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>,
|
||||||
up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>,
|
destination: u8, up: bool) {
|
||||||
destination: u8,
|
|
||||||
up: bool,
|
|
||||||
) {
|
|
||||||
let mut up_destinations = up_destinations.borrow_mut();
|
let mut up_destinations = up_destinations.borrow_mut();
|
||||||
up_destinations[destination as usize] = up;
|
up_destinations[destination as usize] = up;
|
||||||
if up {
|
if up {
|
||||||
|
@ -246,13 +194,10 @@ pub mod drtio {
|
||||||
up_destinations[destination as usize]
|
up_destinations[destination as usize]
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn destination_survey(
|
async fn destination_survey(aux_mutex: &Rc<Mutex<bool>>, routing_table: &drtio_routing::RoutingTable,
|
||||||
aux_mutex: &Rc<Mutex<bool>>,
|
up_links: &[bool],
|
||||||
routing_table: &drtio_routing::RoutingTable,
|
up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>,
|
||||||
up_links: &[bool],
|
timer: GlobalTimer) {
|
||||||
up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>,
|
|
||||||
timer: GlobalTimer,
|
|
||||||
) {
|
|
||||||
for destination in 0..drtio_routing::DEST_COUNT {
|
for destination in 0..drtio_routing::DEST_COUNT {
|
||||||
let hop = routing_table.0[destination][0];
|
let hop = routing_table.0[destination][0];
|
||||||
let destination = destination as u8;
|
let destination = destination as u8;
|
||||||
|
@ -266,77 +211,44 @@ pub mod drtio {
|
||||||
let linkno = hop - 1;
|
let linkno = hop - 1;
|
||||||
if destination_up(up_destinations, destination).await {
|
if destination_up(up_destinations, destination).await {
|
||||||
if up_links[linkno as usize] {
|
if up_links[linkno as usize] {
|
||||||
let reply = aux_transact(
|
let reply = aux_transact(aux_mutex, linkno, &Packet::DestinationStatusRequest {
|
||||||
aux_mutex,
|
destination: destination
|
||||||
linkno,
|
}, timer).await;
|
||||||
&Packet::DestinationStatusRequest {
|
|
||||||
destination: destination,
|
|
||||||
},
|
|
||||||
timer,
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
match reply {
|
match reply {
|
||||||
Ok(Packet::DestinationDownReply) => {
|
Ok(Packet::DestinationDownReply) =>
|
||||||
destination_set_up(routing_table, up_destinations, destination, false).await;
|
destination_set_up(routing_table, up_destinations, destination, false).await,
|
||||||
remote_dma::destination_changed(aux_mutex, routing_table, timer, destination, false)
|
|
||||||
.await;
|
|
||||||
}
|
|
||||||
Ok(Packet::DestinationOkReply) => (),
|
Ok(Packet::DestinationOkReply) => (),
|
||||||
Ok(Packet::DestinationSequenceErrorReply { channel }) => {
|
Ok(Packet::DestinationSequenceErrorReply { channel }) =>{
|
||||||
error!(
|
error!("[DEST#{}] RTIO sequence error involving channel 0x{:04x}", destination, channel);
|
||||||
"[DEST#{}] RTIO sequence error involving channel 0x{:04x}:{}",
|
|
||||||
destination,
|
|
||||||
channel,
|
|
||||||
resolve_channel_name(channel as u32)
|
|
||||||
);
|
|
||||||
unsafe { SEEN_ASYNC_ERRORS |= ASYNC_ERROR_SEQUENCE_ERROR };
|
unsafe { SEEN_ASYNC_ERRORS |= ASYNC_ERROR_SEQUENCE_ERROR };
|
||||||
}
|
}
|
||||||
Ok(Packet::DestinationCollisionReply { channel }) => {
|
Ok(Packet::DestinationCollisionReply { channel }) =>{
|
||||||
error!(
|
error!("[DEST#{}] RTIO collision involving channel 0x{:04x}", destination, channel);
|
||||||
"[DEST#{}] RTIO collision involving channel 0x{:04x}:{}",
|
|
||||||
destination,
|
|
||||||
channel,
|
|
||||||
resolve_channel_name(channel as u32)
|
|
||||||
);
|
|
||||||
unsafe { SEEN_ASYNC_ERRORS |= ASYNC_ERROR_COLLISION };
|
unsafe { SEEN_ASYNC_ERRORS |= ASYNC_ERROR_COLLISION };
|
||||||
}
|
}
|
||||||
Ok(Packet::DestinationBusyReply { channel }) => {
|
Ok(Packet::DestinationBusyReply { channel }) =>{
|
||||||
error!(
|
error!("[DEST#{}] RTIO busy error involving channel 0x{:04x}", destination, channel);
|
||||||
"[DEST#{}] RTIO busy error involving channel 0x{:04x}:{}",
|
|
||||||
destination,
|
|
||||||
channel,
|
|
||||||
resolve_channel_name(channel as u32)
|
|
||||||
);
|
|
||||||
unsafe { SEEN_ASYNC_ERRORS |= ASYNC_ERROR_BUSY };
|
unsafe { SEEN_ASYNC_ERRORS |= ASYNC_ERROR_BUSY };
|
||||||
}
|
}
|
||||||
Ok(packet) => error!("[DEST#{}] received unexpected aux packet: {:?}", destination, packet),
|
Ok(packet) => error!("[DEST#{}] received unexpected aux packet: {:?}", destination, packet),
|
||||||
Err(e) => error!("[DEST#{}] communication failed ({})", destination, e),
|
Err(e) => error!("[DEST#{}] communication failed ({})", destination, e)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
destination_set_up(routing_table, up_destinations, destination, false).await;
|
destination_set_up(routing_table, up_destinations, destination, false).await;
|
||||||
remote_dma::destination_changed(aux_mutex, routing_table, timer, destination, false).await;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if up_links[linkno as usize] {
|
if up_links[linkno as usize] {
|
||||||
let reply = aux_transact(
|
let reply = aux_transact(aux_mutex, linkno, &Packet::DestinationStatusRequest {
|
||||||
aux_mutex,
|
destination: destination
|
||||||
linkno,
|
}, timer).await;
|
||||||
&Packet::DestinationStatusRequest {
|
|
||||||
destination: destination,
|
|
||||||
},
|
|
||||||
timer,
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
match reply {
|
match reply {
|
||||||
Ok(Packet::DestinationDownReply) => (),
|
Ok(Packet::DestinationDownReply) => (),
|
||||||
Ok(Packet::DestinationOkReply) => {
|
Ok(Packet::DestinationOkReply) => {
|
||||||
destination_set_up(routing_table, up_destinations, destination, true).await;
|
destination_set_up(routing_table, up_destinations, destination, true).await;
|
||||||
init_buffer_space(destination as u8, linkno).await;
|
init_buffer_space(destination as u8, linkno).await;
|
||||||
remote_dma::destination_changed(aux_mutex, routing_table, timer, destination, true)
|
},
|
||||||
.await;
|
|
||||||
}
|
|
||||||
Ok(packet) => error!("[DEST#{}] received unexpected aux packet: {:?}", destination, packet),
|
Ok(packet) => error!("[DEST#{}] received unexpected aux packet: {:?}", destination, packet),
|
||||||
Err(e) => error!("[DEST#{}] communication failed ({})", destination, e),
|
Err(e) => error!("[DEST#{}] communication failed ({})", destination, e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -344,12 +256,10 @@ pub mod drtio {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn link_task(
|
pub async fn link_task(aux_mutex: &Rc<Mutex<bool>>,
|
||||||
aux_mutex: &Rc<Mutex<bool>>,
|
routing_table: &drtio_routing::RoutingTable,
|
||||||
routing_table: &drtio_routing::RoutingTable,
|
up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>,
|
||||||
up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>,
|
timer: GlobalTimer) {
|
||||||
timer: GlobalTimer,
|
|
||||||
) {
|
|
||||||
let mut up_links = [false; csr::DRTIO.len()];
|
let mut up_links = [false; csr::DRTIO.len()];
|
||||||
loop {
|
loop {
|
||||||
for linkno in 0..csr::DRTIO.len() {
|
for linkno in 0..csr::DRTIO.len() {
|
||||||
|
@ -410,186 +320,33 @@ pub mod drtio {
|
||||||
for linkno in 0..csr::DRTIO.len() {
|
for linkno in 0..csr::DRTIO.len() {
|
||||||
let linkno = linkno as u8;
|
let linkno = linkno as u8;
|
||||||
if task::block_on(link_rx_up(linkno)) {
|
if task::block_on(link_rx_up(linkno)) {
|
||||||
let reply = task::block_on(aux_transact(&aux_mutex, linkno, &Packet::ResetRequest, timer));
|
let reply = task::block_on(aux_transact(&aux_mutex, linkno,
|
||||||
|
&Packet::ResetRequest, timer));
|
||||||
match reply {
|
match reply {
|
||||||
Ok(Packet::ResetAck) => (),
|
Ok(Packet::ResetAck) => (),
|
||||||
Ok(_) => error!("[LINK#{}] reset failed, received unexpected aux packet", linkno),
|
Ok(_) => error!("[LINK#{}] reset failed, received unexpected aux packet", linkno),
|
||||||
Err(e) => error!("[LINK#{}] reset failed, aux packet error ({})", linkno, e),
|
Err(e) => error!("[LINK#{}] reset failed, aux packet error ({})", linkno, e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn ddma_upload_trace(
|
|
||||||
aux_mutex: &Rc<Mutex<bool>>,
|
|
||||||
routing_table: &drtio_routing::RoutingTable,
|
|
||||||
timer: GlobalTimer,
|
|
||||||
id: u32,
|
|
||||||
destination: u8,
|
|
||||||
trace: &Vec<u8>,
|
|
||||||
) -> Result<(), &'static str> {
|
|
||||||
let linkno = routing_table.0[destination as usize][0] - 1;
|
|
||||||
let mut i = 0;
|
|
||||||
while i < trace.len() {
|
|
||||||
let mut trace_slice: [u8; DMA_TRACE_MAX_SIZE] = [0; DMA_TRACE_MAX_SIZE];
|
|
||||||
let len: usize = if i + DMA_TRACE_MAX_SIZE < trace.len() {
|
|
||||||
DMA_TRACE_MAX_SIZE
|
|
||||||
} else {
|
|
||||||
trace.len() - i
|
|
||||||
} as usize;
|
|
||||||
let last = i + len == trace.len();
|
|
||||||
trace_slice[..len].clone_from_slice(&trace[i..i + len]);
|
|
||||||
i += len;
|
|
||||||
let reply = aux_transact(
|
|
||||||
aux_mutex,
|
|
||||||
linkno,
|
|
||||||
&Packet::DmaAddTraceRequest {
|
|
||||||
id: id,
|
|
||||||
destination: destination,
|
|
||||||
last: last,
|
|
||||||
length: len as u16,
|
|
||||||
trace: trace_slice,
|
|
||||||
},
|
|
||||||
timer,
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
match reply {
|
|
||||||
Ok(Packet::DmaAddTraceReply { succeeded: true }) => (),
|
|
||||||
Ok(Packet::DmaAddTraceReply { succeeded: false }) => {
|
|
||||||
return Err("error adding trace on satellite");
|
|
||||||
}
|
|
||||||
Ok(_) => {
|
|
||||||
return Err("adding DMA trace failed, unexpected aux packet");
|
|
||||||
}
|
|
||||||
Err(_) => {
|
|
||||||
return Err("adding DMA trace failed, aux error");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn ddma_send_erase(
|
|
||||||
aux_mutex: &Rc<Mutex<bool>>,
|
|
||||||
routing_table: &drtio_routing::RoutingTable,
|
|
||||||
timer: GlobalTimer,
|
|
||||||
id: u32,
|
|
||||||
destination: u8,
|
|
||||||
) -> Result<(), &'static str> {
|
|
||||||
let linkno = routing_table.0[destination as usize][0] - 1;
|
|
||||||
let reply = aux_transact(
|
|
||||||
aux_mutex,
|
|
||||||
linkno,
|
|
||||||
&Packet::DmaRemoveTraceRequest {
|
|
||||||
id: id,
|
|
||||||
destination: destination,
|
|
||||||
},
|
|
||||||
timer,
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
match reply {
|
|
||||||
Ok(Packet::DmaRemoveTraceReply { succeeded: true }) => Ok(()),
|
|
||||||
Ok(Packet::DmaRemoveTraceReply { succeeded: false }) => Err("satellite DMA erase error"),
|
|
||||||
Ok(_) => Err("adding trace failed, unexpected aux packet"),
|
|
||||||
Err(_) => Err("erasing trace failed, aux error"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn ddma_send_playback(
|
|
||||||
aux_mutex: &Rc<Mutex<bool>>,
|
|
||||||
routing_table: &drtio_routing::RoutingTable,
|
|
||||||
timer: GlobalTimer,
|
|
||||||
id: u32,
|
|
||||||
destination: u8,
|
|
||||||
timestamp: u64,
|
|
||||||
) -> Result<(), &'static str> {
|
|
||||||
let linkno = routing_table.0[destination as usize][0] - 1;
|
|
||||||
let reply = aux_transact(
|
|
||||||
aux_mutex,
|
|
||||||
linkno,
|
|
||||||
&Packet::DmaPlaybackRequest {
|
|
||||||
id: id,
|
|
||||||
destination: destination,
|
|
||||||
timestamp: timestamp,
|
|
||||||
},
|
|
||||||
timer,
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
match reply {
|
|
||||||
Ok(Packet::DmaPlaybackReply { succeeded: true }) => Ok(()),
|
|
||||||
Ok(Packet::DmaPlaybackReply { succeeded: false }) => Err("error on DMA playback request"),
|
|
||||||
Ok(_) => Err("received unexpected aux packet during DMA playback"),
|
|
||||||
Err(_) => Err("aux error on DMA playback"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read_device_map(cfg: &Config) -> BTreeMap<u32, String> {
|
|
||||||
let mut device_map: BTreeMap<u32, String> = BTreeMap::new();
|
|
||||||
let _ = cfg
|
|
||||||
.read("device_map")
|
|
||||||
.and_then(|raw_bytes| {
|
|
||||||
let mut bytes_cr = Cursor::new(raw_bytes);
|
|
||||||
let size = bytes_cr.read_u32().unwrap();
|
|
||||||
for _ in 0..size {
|
|
||||||
let channel = bytes_cr.read_u32().unwrap();
|
|
||||||
let device_name = bytes_cr.read_string().unwrap();
|
|
||||||
if let Some(old_entry) = device_map.insert(channel, device_name.clone()) {
|
|
||||||
warn!(
|
|
||||||
"conflicting device map entries for RTIO channel {}: '{}' and '{}'",
|
|
||||||
channel, old_entry, device_name
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
})
|
|
||||||
.or_else(|err| {
|
|
||||||
warn!(
|
|
||||||
"error reading device map ({}), device names will not be available in RTIO error messages",
|
|
||||||
err
|
|
||||||
);
|
|
||||||
Err(err)
|
|
||||||
});
|
|
||||||
device_map
|
|
||||||
}
|
|
||||||
|
|
||||||
fn _resolve_channel_name(channel: u32, device_map: &BTreeMap<u32, String>) -> String {
|
|
||||||
match device_map.get(&channel) {
|
|
||||||
Some(val) => val.clone(),
|
|
||||||
None => String::from("unknown"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn resolve_channel_name(channel: u32) -> String {
|
|
||||||
_resolve_channel_name(channel, unsafe { &RTIO_DEVICE_MAP })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(has_drtio))]
|
#[cfg(not(has_drtio))]
|
||||||
pub mod drtio {
|
pub mod drtio {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
pub fn startup(
|
pub fn startup(_aux_mutex: &Rc<Mutex<bool>>, _routing_table: &Rc<RefCell<drtio_routing::RoutingTable>>,
|
||||||
_aux_mutex: &Rc<Mutex<bool>>,
|
_up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>, _timer: GlobalTimer) {}
|
||||||
_routing_table: &Rc<RefCell<drtio_routing::RoutingTable>>,
|
|
||||||
_up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>,
|
|
||||||
_timer: GlobalTimer,
|
|
||||||
) {
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn reset(_aux_mutex: Rc<Mutex<bool>>, mut _timer: GlobalTimer) {}
|
pub fn reset(_aux_mutex: Rc<Mutex<bool>>, mut _timer: GlobalTimer) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn startup(
|
pub fn startup(aux_mutex: &Rc<Mutex<bool>>,
|
||||||
aux_mutex: &Rc<Mutex<bool>>,
|
routing_table: &Rc<RefCell<drtio_routing::RoutingTable>>,
|
||||||
routing_table: &Rc<RefCell<drtio_routing::RoutingTable>>,
|
up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>,
|
||||||
up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>,
|
timer: GlobalTimer) {
|
||||||
timer: GlobalTimer,
|
|
||||||
cfg: &Config,
|
|
||||||
) {
|
|
||||||
unsafe {
|
|
||||||
RTIO_DEVICE_MAP = read_device_map(cfg);
|
|
||||||
}
|
|
||||||
drtio::startup(aux_mutex, routing_table, up_destinations, timer);
|
drtio::startup(aux_mutex, routing_table, up_destinations, timer);
|
||||||
unsafe {
|
unsafe {
|
||||||
csr::rtio_core::reset_phy_write(1);
|
csr::rtio_core::reset_phy_write(1);
|
||||||
|
|
|
@ -1,68 +0,0 @@
|
||||||
max_width = 120
|
|
||||||
hard_tabs = false
|
|
||||||
tab_spaces = 4
|
|
||||||
newline_style = "Auto"
|
|
||||||
use_small_heuristics = "Default"
|
|
||||||
indent_style = "Block"
|
|
||||||
wrap_comments = false
|
|
||||||
format_code_in_doc_comments = false
|
|
||||||
comment_width = 100
|
|
||||||
normalize_comments = false
|
|
||||||
normalize_doc_attributes = false
|
|
||||||
license_template_path = ""
|
|
||||||
format_strings = true
|
|
||||||
format_macro_matchers = true
|
|
||||||
format_macro_bodies = true
|
|
||||||
empty_item_single_line = true
|
|
||||||
struct_lit_single_line = true
|
|
||||||
fn_single_line = false
|
|
||||||
where_single_line = true
|
|
||||||
imports_indent = "Visual"
|
|
||||||
imports_layout = "Mixed"
|
|
||||||
merge_imports = true
|
|
||||||
group_imports = "StdExternalCrate"
|
|
||||||
reorder_imports = true
|
|
||||||
reorder_modules = true
|
|
||||||
reorder_impl_items = false
|
|
||||||
type_punctuation_density = "Wide"
|
|
||||||
space_before_colon = false
|
|
||||||
space_after_colon = true
|
|
||||||
spaces_around_ranges = false
|
|
||||||
binop_separator = "Front"
|
|
||||||
remove_nested_parens = true
|
|
||||||
combine_control_expr = true
|
|
||||||
overflow_delimited_expr = false
|
|
||||||
struct_field_align_threshold = 0
|
|
||||||
enum_discrim_align_threshold = 0
|
|
||||||
match_arm_blocks = true
|
|
||||||
match_arm_leading_pipes = "Never"
|
|
||||||
force_multiline_blocks = false
|
|
||||||
fn_args_layout = "Tall"
|
|
||||||
brace_style = "SameLineWhere"
|
|
||||||
control_brace_style = "AlwaysSameLine"
|
|
||||||
trailing_semicolon = true
|
|
||||||
trailing_comma = "Vertical"
|
|
||||||
match_block_trailing_comma = false
|
|
||||||
blank_lines_upper_bound = 1
|
|
||||||
blank_lines_lower_bound = 0
|
|
||||||
edition = "2018"
|
|
||||||
version = "Two"
|
|
||||||
inline_attribute_width = 0
|
|
||||||
merge_derives = true
|
|
||||||
use_try_shorthand = false
|
|
||||||
use_field_init_shorthand = false
|
|
||||||
force_explicit_abi = true
|
|
||||||
condense_wildcard_suffixes = false
|
|
||||||
color = "Auto"
|
|
||||||
required_version = "1.4.32"
|
|
||||||
unstable_features = false
|
|
||||||
disable_all_formatting = false
|
|
||||||
skip_children = false
|
|
||||||
hide_parse_errors = false
|
|
||||||
error_on_line_overflow = false
|
|
||||||
error_on_unformatted = false
|
|
||||||
report_todo = "Never"
|
|
||||||
report_fixme = "Never"
|
|
||||||
ignore = []
|
|
||||||
emit_mode = "Files"
|
|
||||||
make_backup = false
|
|
|
@ -1,173 +0,0 @@
|
||||||
use alloc::{collections::btree_map::BTreeMap, vec::Vec};
|
|
||||||
|
|
||||||
use libboard_artiq::pl::csr;
|
|
||||||
use libcortex_a9::cache::dcci_slice;
|
|
||||||
|
|
||||||
const ALIGNMENT: usize = 64;
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
|
||||||
enum ManagerState {
|
|
||||||
Idle,
|
|
||||||
Playback,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct RtioStatus {
|
|
||||||
pub id: u32,
|
|
||||||
pub error: u8,
|
|
||||||
pub channel: u32,
|
|
||||||
pub timestamp: u64,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum Error {
|
|
||||||
IdNotFound,
|
|
||||||
PlaybackInProgress,
|
|
||||||
EntryNotComplete,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct Entry {
|
|
||||||
trace: Vec<u8>,
|
|
||||||
padding_len: usize,
|
|
||||||
complete: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Manager {
|
|
||||||
entries: BTreeMap<u32, Entry>,
|
|
||||||
state: ManagerState,
|
|
||||||
currentid: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Manager {
|
|
||||||
pub fn new() -> Manager {
|
|
||||||
// in case Manager is created during a DMA in progress
|
|
||||||
// wait for it to end
|
|
||||||
unsafe { while csr::rtio_dma::enable_read() != 0 {} }
|
|
||||||
Manager {
|
|
||||||
entries: BTreeMap::new(),
|
|
||||||
currentid: 0,
|
|
||||||
state: ManagerState::Idle,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add(&mut self, id: u32, last: bool, trace: &[u8], trace_len: usize) -> Result<(), Error> {
|
|
||||||
let entry = match self.entries.get_mut(&id) {
|
|
||||||
Some(entry) => {
|
|
||||||
if entry.complete {
|
|
||||||
// replace entry
|
|
||||||
self.entries.remove(&id);
|
|
||||||
self.entries.insert(
|
|
||||||
id,
|
|
||||||
Entry {
|
|
||||||
trace: Vec::new(),
|
|
||||||
padding_len: 0,
|
|
||||||
complete: false,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
self.entries.get_mut(&id).unwrap()
|
|
||||||
} else {
|
|
||||||
entry
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
self.entries.insert(
|
|
||||||
id,
|
|
||||||
Entry {
|
|
||||||
trace: Vec::new(),
|
|
||||||
padding_len: 0,
|
|
||||||
complete: false,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
self.entries.get_mut(&id).unwrap()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
entry.trace.extend(&trace[0..trace_len]);
|
|
||||||
|
|
||||||
if last {
|
|
||||||
entry.trace.push(0);
|
|
||||||
let data_len = entry.trace.len();
|
|
||||||
|
|
||||||
// Realign.
|
|
||||||
entry.trace.reserve(ALIGNMENT - 1);
|
|
||||||
let padding = ALIGNMENT - entry.trace.as_ptr() as usize % ALIGNMENT;
|
|
||||||
let padding = if padding == ALIGNMENT { 0 } else { padding };
|
|
||||||
for _ in 0..padding {
|
|
||||||
// Vec guarantees that this will not reallocate
|
|
||||||
entry.trace.push(0)
|
|
||||||
}
|
|
||||||
for i in 1..data_len + 1 {
|
|
||||||
entry.trace[data_len + padding - i] = entry.trace[data_len - i]
|
|
||||||
}
|
|
||||||
entry.complete = true;
|
|
||||||
entry.padding_len = padding;
|
|
||||||
dcci_slice(&entry.trace);
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn erase(&mut self, id: u32) -> Result<(), Error> {
|
|
||||||
match self.entries.remove(&id) {
|
|
||||||
Some(_) => Ok(()),
|
|
||||||
None => Err(Error::IdNotFound),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn playback(&mut self, id: u32, timestamp: u64) -> Result<(), Error> {
|
|
||||||
if self.state != ManagerState::Idle {
|
|
||||||
return Err(Error::PlaybackInProgress);
|
|
||||||
}
|
|
||||||
|
|
||||||
let entry = match self.entries.get(&id) {
|
|
||||||
Some(entry) => entry,
|
|
||||||
None => {
|
|
||||||
return Err(Error::IdNotFound);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
if !entry.complete {
|
|
||||||
return Err(Error::EntryNotComplete);
|
|
||||||
}
|
|
||||||
let ptr = entry.trace[entry.padding_len..].as_ptr();
|
|
||||||
assert!(ptr as u32 % 64 == 0);
|
|
||||||
|
|
||||||
self.state = ManagerState::Playback;
|
|
||||||
self.currentid = id;
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
csr::rtio_dma::base_address_write(ptr as u32);
|
|
||||||
csr::rtio_dma::time_offset_write(timestamp as u64);
|
|
||||||
|
|
||||||
csr::cri_con::selected_write(1);
|
|
||||||
csr::rtio_dma::enable_write(1);
|
|
||||||
// playback has begun here, for status call check_state
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn check_state(&mut self) -> Option<RtioStatus> {
|
|
||||||
if self.state != ManagerState::Playback {
|
|
||||||
// nothing to report
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
let dma_enable = unsafe { csr::rtio_dma::enable_read() };
|
|
||||||
if dma_enable != 0 {
|
|
||||||
return None;
|
|
||||||
} else {
|
|
||||||
self.state = ManagerState::Idle;
|
|
||||||
unsafe {
|
|
||||||
csr::cri_con::selected_write(0);
|
|
||||||
let error = csr::rtio_dma::error_read();
|
|
||||||
let channel = csr::rtio_dma::error_channel_read();
|
|
||||||
let timestamp = csr::rtio_dma::error_timestamp_read();
|
|
||||||
if error != 0 {
|
|
||||||
csr::rtio_dma::error_write(1);
|
|
||||||
}
|
|
||||||
return Some(RtioStatus {
|
|
||||||
id: self.currentid,
|
|
||||||
error: error,
|
|
||||||
channel: channel,
|
|
||||||
timestamp: timestamp,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -8,37 +8,29 @@ extern crate log;
|
||||||
|
|
||||||
extern crate embedded_hal;
|
extern crate embedded_hal;
|
||||||
|
|
||||||
extern crate libboard_artiq;
|
|
||||||
extern crate libboard_zynq;
|
extern crate libboard_zynq;
|
||||||
|
extern crate libboard_artiq;
|
||||||
|
extern crate libsupport_zynq;
|
||||||
extern crate libcortex_a9;
|
extern crate libcortex_a9;
|
||||||
extern crate libregister;
|
extern crate libregister;
|
||||||
extern crate libsupport_zynq;
|
|
||||||
|
|
||||||
extern crate unwind;
|
extern crate unwind;
|
||||||
|
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
use core::sync::atomic::{AtomicBool, Ordering};
|
use libboard_zynq::{i2c::I2c, timer::GlobalTimer, time::Milliseconds, print, println, mpcore, gic, stdio};
|
||||||
|
use libsupport_zynq::ram;
|
||||||
use dma::Manager as DmaManager;
|
|
||||||
use embedded_hal::blocking::delay::DelayUs;
|
|
||||||
#[cfg(feature = "target_kasli_soc")]
|
|
||||||
use libboard_artiq::io_expander;
|
|
||||||
#[cfg(has_si5324)]
|
#[cfg(has_si5324)]
|
||||||
use libboard_artiq::si5324;
|
use libboard_artiq::si5324;
|
||||||
use libboard_artiq::{drtio_routing, drtioaux, identifier_read, logger, pl::csr};
|
|
||||||
#[cfg(feature = "target_kasli_soc")]
|
#[cfg(feature = "target_kasli_soc")]
|
||||||
use libboard_zynq::error_led::ErrorLED;
|
use libboard_artiq::io_expander;
|
||||||
use libboard_zynq::{gic, i2c::I2c, mpcore, print, println, stdio, time::Milliseconds, timer::GlobalTimer};
|
use libboard_artiq::{pl::csr, drtio_routing, drtioaux, logger, identifier_read, init_gateware};
|
||||||
use libcortex_a9::{asm, interrupt_handler,
|
use libcortex_a9::{spin_lock_yield, interrupt_handler, regs::{MPIDR, SP}, notify_spin_lock, asm, l2c::enable_l2_cache};
|
||||||
l2c::enable_l2_cache,
|
use libregister::{RegisterW, RegisterR};
|
||||||
notify_spin_lock,
|
|
||||||
regs::{MPIDR, SP},
|
use embedded_hal::blocking::delay::DelayUs;
|
||||||
spin_lock_yield};
|
use core::sync::atomic::{AtomicBool, Ordering};
|
||||||
use libregister::{RegisterR, RegisterW};
|
|
||||||
use libsupport_zynq::ram;
|
|
||||||
|
|
||||||
mod dma;
|
|
||||||
mod repeater;
|
mod repeater;
|
||||||
|
|
||||||
fn drtiosat_reset(reset: bool) {
|
fn drtiosat_reset(reset: bool) {
|
||||||
|
@ -54,7 +46,9 @@ fn drtiosat_reset_phy(reset: bool) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn drtiosat_link_rx_up() -> bool {
|
fn drtiosat_link_rx_up() -> bool {
|
||||||
unsafe { csr::drtiosat::rx_up_read() == 1 }
|
unsafe {
|
||||||
|
csr::drtiosat::rx_up_read() == 1
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn drtiosat_tsc_loaded() -> bool {
|
fn drtiosat_tsc_loaded() -> bool {
|
||||||
|
@ -67,6 +61,7 @@ fn drtiosat_tsc_loaded() -> bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[cfg(has_drtio_routing)]
|
#[cfg(has_drtio_routing)]
|
||||||
macro_rules! forward {
|
macro_rules! forward {
|
||||||
($routing_table:expr, $destination:expr, $rank:expr, $repeaters:expr, $packet:expr, $timer:expr) => {{
|
($routing_table:expr, $destination:expr, $rank:expr, $repeaters:expr, $packet:expr, $timer:expr) => {{
|
||||||
|
@ -79,27 +74,22 @@ macro_rules! forward {
|
||||||
return Err(drtioaux::Error::RoutingError);
|
return Err(drtioaux::Error::RoutingError);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}};
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(has_drtio_routing))]
|
#[cfg(not(has_drtio_routing))]
|
||||||
macro_rules! forward {
|
macro_rules! forward {
|
||||||
($routing_table:expr, $destination:expr, $rank:expr, $repeaters:expr, $packet:expr, $timer:expr) => {};
|
($routing_table:expr, $destination:expr, $rank:expr, $repeaters:expr, $packet:expr, $timer:expr) => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_aux_packet(
|
fn process_aux_packet(_repeaters: &mut [repeater::Repeater],
|
||||||
_repeaters: &mut [repeater::Repeater],
|
_routing_table: &mut drtio_routing::RoutingTable, _rank: &mut u8,
|
||||||
_routing_table: &mut drtio_routing::RoutingTable,
|
packet: drtioaux::Packet, timer: &mut GlobalTimer, i2c: &mut I2c) -> Result<(), drtioaux::Error> {
|
||||||
_rank: &mut u8,
|
|
||||||
packet: drtioaux::Packet,
|
|
||||||
timer: &mut GlobalTimer,
|
|
||||||
i2c: &mut I2c,
|
|
||||||
dma_manager: &mut DmaManager,
|
|
||||||
) -> Result<(), drtioaux::Error> {
|
|
||||||
// In the code below, *_chan_sel_write takes an u8 if there are fewer than 256 channels,
|
// In the code below, *_chan_sel_write takes an u8 if there are fewer than 256 channels,
|
||||||
// and u16 otherwise; hence the `as _` conversion.
|
// and u16 otherwise; hence the `as _` conversion.
|
||||||
match packet {
|
match packet {
|
||||||
drtioaux::Packet::EchoRequest => drtioaux::send(0, &drtioaux::Packet::EchoReply),
|
drtioaux::Packet::EchoRequest =>
|
||||||
|
drtioaux::send(0, &drtioaux::Packet::EchoReply),
|
||||||
drtioaux::Packet::ResetRequest => {
|
drtioaux::Packet::ResetRequest => {
|
||||||
info!("resetting RTIO");
|
info!("resetting RTIO");
|
||||||
drtiosat_reset(true);
|
drtiosat_reset(true);
|
||||||
|
@ -111,11 +101,9 @@ fn process_aux_packet(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
drtioaux::send(0, &drtioaux::Packet::ResetAck)
|
drtioaux::send(0, &drtioaux::Packet::ResetAck)
|
||||||
}
|
},
|
||||||
|
|
||||||
drtioaux::Packet::DestinationStatusRequest {
|
drtioaux::Packet::DestinationStatusRequest { destination: _destination } => {
|
||||||
destination: _destination,
|
|
||||||
} => {
|
|
||||||
#[cfg(has_drtio_routing)]
|
#[cfg(has_drtio_routing)]
|
||||||
let hop = _routing_table.0[_destination as usize][*_rank as usize];
|
let hop = _routing_table.0[_destination as usize][*_rank as usize];
|
||||||
#[cfg(not(has_drtio_routing))]
|
#[cfg(not(has_drtio_routing))]
|
||||||
|
@ -132,22 +120,26 @@ fn process_aux_packet(
|
||||||
channel = csr::drtiosat::sequence_error_channel_read();
|
channel = csr::drtiosat::sequence_error_channel_read();
|
||||||
csr::drtiosat::rtio_error_write(1);
|
csr::drtiosat::rtio_error_write(1);
|
||||||
}
|
}
|
||||||
drtioaux::send(0, &drtioaux::Packet::DestinationSequenceErrorReply { channel })?;
|
drtioaux::send(0,
|
||||||
|
&drtioaux::Packet::DestinationSequenceErrorReply { channel })?;
|
||||||
} else if errors & 2 != 0 {
|
} else if errors & 2 != 0 {
|
||||||
let channel;
|
let channel;
|
||||||
unsafe {
|
unsafe {
|
||||||
channel = csr::drtiosat::collision_channel_read();
|
channel = csr::drtiosat::collision_channel_read();
|
||||||
csr::drtiosat::rtio_error_write(2);
|
csr::drtiosat::rtio_error_write(2);
|
||||||
}
|
}
|
||||||
drtioaux::send(0, &drtioaux::Packet::DestinationCollisionReply { channel })?;
|
drtioaux::send(0,
|
||||||
|
&drtioaux::Packet::DestinationCollisionReply { channel })?;
|
||||||
} else if errors & 4 != 0 {
|
} else if errors & 4 != 0 {
|
||||||
let channel;
|
let channel;
|
||||||
unsafe {
|
unsafe {
|
||||||
channel = csr::drtiosat::busy_channel_read();
|
channel = csr::drtiosat::busy_channel_read();
|
||||||
csr::drtiosat::rtio_error_write(4);
|
csr::drtiosat::rtio_error_write(4);
|
||||||
}
|
}
|
||||||
drtioaux::send(0, &drtioaux::Packet::DestinationBusyReply { channel })?;
|
drtioaux::send(0,
|
||||||
} else {
|
&drtioaux::Packet::DestinationBusyReply { channel })?;
|
||||||
|
}
|
||||||
|
else {
|
||||||
drtioaux::send(0, &drtioaux::Packet::DestinationOkReply)?;
|
drtioaux::send(0, &drtioaux::Packet::DestinationOkReply)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -158,20 +150,15 @@ fn process_aux_packet(
|
||||||
let hop = hop as usize;
|
let hop = hop as usize;
|
||||||
if hop <= csr::DRTIOREP.len() {
|
if hop <= csr::DRTIOREP.len() {
|
||||||
let repno = hop - 1;
|
let repno = hop - 1;
|
||||||
match _repeaters[repno].aux_forward(
|
match _repeaters[repno].aux_forward(&drtioaux::Packet::DestinationStatusRequest {
|
||||||
&drtioaux::Packet::DestinationStatusRequest {
|
destination: _destination
|
||||||
destination: _destination,
|
}, timer) {
|
||||||
},
|
|
||||||
timer,
|
|
||||||
) {
|
|
||||||
Ok(()) => (),
|
Ok(()) => (),
|
||||||
Err(drtioaux::Error::LinkDown) => {
|
Err(drtioaux::Error::LinkDown) => drtioaux::send(0, &drtioaux::Packet::DestinationDownReply)?,
|
||||||
drtioaux::send(0, &drtioaux::Packet::DestinationDownReply)?
|
|
||||||
}
|
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
drtioaux::send(0, &drtioaux::Packet::DestinationDownReply)?;
|
drtioaux::send(0, &drtioaux::Packet::DestinationDownReply)?;
|
||||||
error!("aux error when handling destination status request: {:?}", e);
|
error!("aux error when handling destination status request: {:?}", e);
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
drtioaux::send(0, &drtioaux::Packet::DestinationDownReply)?;
|
drtioaux::send(0, &drtioaux::Packet::DestinationDownReply)?;
|
||||||
|
@ -211,18 +198,15 @@ fn process_aux_packet(
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(has_drtio_routing))]
|
#[cfg(not(has_drtio_routing))]
|
||||||
drtioaux::Packet::RoutingSetPath {
|
drtioaux::Packet::RoutingSetPath { destination: _, hops: _ } => {
|
||||||
destination: _,
|
drtioaux::send(0, &drtioaux::Packet::RoutingAck)
|
||||||
hops: _,
|
}
|
||||||
} => drtioaux::send(0, &drtioaux::Packet::RoutingAck),
|
|
||||||
#[cfg(not(has_drtio_routing))]
|
#[cfg(not(has_drtio_routing))]
|
||||||
drtioaux::Packet::RoutingSetRank { rank: _ } => drtioaux::send(0, &drtioaux::Packet::RoutingAck),
|
drtioaux::Packet::RoutingSetRank { rank: _ } => {
|
||||||
|
drtioaux::send(0, &drtioaux::Packet::RoutingAck)
|
||||||
|
}
|
||||||
|
|
||||||
drtioaux::Packet::MonitorRequest {
|
drtioaux::Packet::MonitorRequest { destination: _destination, channel: _channel, probe: _probe } => {
|
||||||
destination: _destination,
|
|
||||||
channel: _channel,
|
|
||||||
probe: _probe,
|
|
||||||
} => {
|
|
||||||
forward!(_routing_table, _destination, *_rank, _repeaters, &packet, timer);
|
forward!(_routing_table, _destination, *_rank, _repeaters, &packet, timer);
|
||||||
let value;
|
let value;
|
||||||
#[cfg(has_rtio_moninj)]
|
#[cfg(has_rtio_moninj)]
|
||||||
|
@ -238,13 +222,9 @@ fn process_aux_packet(
|
||||||
}
|
}
|
||||||
let reply = drtioaux::Packet::MonitorReply { value: value };
|
let reply = drtioaux::Packet::MonitorReply { value: value };
|
||||||
drtioaux::send(0, &reply)
|
drtioaux::send(0, &reply)
|
||||||
}
|
},
|
||||||
drtioaux::Packet::InjectionRequest {
|
drtioaux::Packet::InjectionRequest { destination: _destination, channel: _channel,
|
||||||
destination: _destination,
|
overrd: _overrd, value: _value } => {
|
||||||
channel: _channel,
|
|
||||||
overrd: _overrd,
|
|
||||||
value: _value,
|
|
||||||
} => {
|
|
||||||
forward!(_routing_table, _destination, *_rank, _repeaters, &packet, timer);
|
forward!(_routing_table, _destination, *_rank, _repeaters, &packet, timer);
|
||||||
#[cfg(has_rtio_moninj)]
|
#[cfg(has_rtio_moninj)]
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -253,12 +233,9 @@ fn process_aux_packet(
|
||||||
csr::rtio_moninj::inj_value_write(value);
|
csr::rtio_moninj::inj_value_write(value);
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
},
|
||||||
drtioaux::Packet::InjectionStatusRequest {
|
drtioaux::Packet::InjectionStatusRequest { destination: _destination,
|
||||||
destination: _destination,
|
channel: _channel, overrd: _overrd } => {
|
||||||
channel: _channel,
|
|
||||||
overrd: _overrd,
|
|
||||||
} => {
|
|
||||||
forward!(_routing_table, _destination, *_rank, _repeaters, &packet, timer);
|
forward!(_routing_table, _destination, *_rank, _repeaters, &packet, timer);
|
||||||
let value;
|
let value;
|
||||||
#[cfg(has_rtio_moninj)]
|
#[cfg(has_rtio_moninj)]
|
||||||
|
@ -272,87 +249,44 @@ fn process_aux_packet(
|
||||||
value = 0;
|
value = 0;
|
||||||
}
|
}
|
||||||
drtioaux::send(0, &drtioaux::Packet::InjectionStatusReply { value: value })
|
drtioaux::send(0, &drtioaux::Packet::InjectionStatusReply { value: value })
|
||||||
}
|
},
|
||||||
|
|
||||||
drtioaux::Packet::I2cStartRequest {
|
drtioaux::Packet::I2cStartRequest { destination: _destination, busno: _busno } => {
|
||||||
destination: _destination,
|
|
||||||
busno: _busno,
|
|
||||||
} => {
|
|
||||||
forward!(_routing_table, _destination, *_rank, _repeaters, &packet, timer);
|
forward!(_routing_table, _destination, *_rank, _repeaters, &packet, timer);
|
||||||
let succeeded = i2c.start().is_ok();
|
let succeeded = i2c.start().is_ok();
|
||||||
drtioaux::send(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded })
|
drtioaux::send(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded })
|
||||||
}
|
}
|
||||||
drtioaux::Packet::I2cRestartRequest {
|
drtioaux::Packet::I2cRestartRequest { destination: _destination, busno: _busno } => {
|
||||||
destination: _destination,
|
|
||||||
busno: _busno,
|
|
||||||
} => {
|
|
||||||
forward!(_routing_table, _destination, *_rank, _repeaters, &packet, timer);
|
forward!(_routing_table, _destination, *_rank, _repeaters, &packet, timer);
|
||||||
let succeeded = i2c.restart().is_ok();
|
let succeeded = i2c.restart().is_ok();
|
||||||
drtioaux::send(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded })
|
drtioaux::send(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded })
|
||||||
}
|
}
|
||||||
drtioaux::Packet::I2cStopRequest {
|
drtioaux::Packet::I2cStopRequest { destination: _destination, busno: _busno } => {
|
||||||
destination: _destination,
|
|
||||||
busno: _busno,
|
|
||||||
} => {
|
|
||||||
forward!(_routing_table, _destination, *_rank, _repeaters, &packet, timer);
|
forward!(_routing_table, _destination, *_rank, _repeaters, &packet, timer);
|
||||||
let succeeded = i2c.stop().is_ok();
|
let succeeded = i2c.stop().is_ok();
|
||||||
drtioaux::send(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded })
|
drtioaux::send(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded })
|
||||||
}
|
}
|
||||||
drtioaux::Packet::I2cWriteRequest {
|
drtioaux::Packet::I2cWriteRequest { destination: _destination, busno: _busno, data } => {
|
||||||
destination: _destination,
|
|
||||||
busno: _busno,
|
|
||||||
data,
|
|
||||||
} => {
|
|
||||||
forward!(_routing_table, _destination, *_rank, _repeaters, &packet, timer);
|
forward!(_routing_table, _destination, *_rank, _repeaters, &packet, timer);
|
||||||
match i2c.write(data) {
|
match i2c.write(data) {
|
||||||
Ok(ack) => drtioaux::send(
|
Ok(ack) => drtioaux::send(0,
|
||||||
0,
|
&drtioaux::Packet::I2cWriteReply { succeeded: true, ack: ack }),
|
||||||
&drtioaux::Packet::I2cWriteReply {
|
Err(_) => drtioaux::send(0,
|
||||||
succeeded: true,
|
&drtioaux::Packet::I2cWriteReply { succeeded: false, ack: false })
|
||||||
ack: ack,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
Err(_) => drtioaux::send(
|
|
||||||
0,
|
|
||||||
&drtioaux::Packet::I2cWriteReply {
|
|
||||||
succeeded: false,
|
|
||||||
ack: false,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
drtioaux::Packet::I2cReadRequest {
|
drtioaux::Packet::I2cReadRequest { destination: _destination, busno: _busno, ack } => {
|
||||||
destination: _destination,
|
|
||||||
busno: _busno,
|
|
||||||
ack,
|
|
||||||
} => {
|
|
||||||
forward!(_routing_table, _destination, *_rank, _repeaters, &packet, timer);
|
forward!(_routing_table, _destination, *_rank, _repeaters, &packet, timer);
|
||||||
match i2c.read(ack) {
|
match i2c.read(ack) {
|
||||||
Ok(data) => drtioaux::send(
|
Ok(data) => drtioaux::send(0,
|
||||||
0,
|
&drtioaux::Packet::I2cReadReply { succeeded: true, data: data }),
|
||||||
&drtioaux::Packet::I2cReadReply {
|
Err(_) => drtioaux::send(0,
|
||||||
succeeded: true,
|
&drtioaux::Packet::I2cReadReply { succeeded: false, data: 0xff })
|
||||||
data: data,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
Err(_) => drtioaux::send(
|
|
||||||
0,
|
|
||||||
&drtioaux::Packet::I2cReadReply {
|
|
||||||
succeeded: false,
|
|
||||||
data: 0xff,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
drtioaux::Packet::I2cSwitchSelectRequest {
|
drtioaux::Packet::I2cSwitchSelectRequest { destination: _destination, busno: _busno, address, mask } => {
|
||||||
destination: _destination,
|
|
||||||
busno: _busno,
|
|
||||||
address,
|
|
||||||
mask,
|
|
||||||
} => {
|
|
||||||
forward!(_routing_table, _destination, *_rank, _repeaters, &packet, timer);
|
forward!(_routing_table, _destination, *_rank, _repeaters, &packet, timer);
|
||||||
let ch = match mask {
|
let ch = match mask { //decode from mainline, PCA9548-centric API
|
||||||
//decode from mainline, PCA9548-centric API
|
|
||||||
0x00 => None,
|
0x00 => None,
|
||||||
0x01 => Some(0),
|
0x01 => Some(0),
|
||||||
0x02 => Some(1),
|
0x02 => Some(1),
|
||||||
|
@ -362,39 +296,28 @@ fn process_aux_packet(
|
||||||
0x20 => Some(5),
|
0x20 => Some(5),
|
||||||
0x40 => Some(6),
|
0x40 => Some(6),
|
||||||
0x80 => Some(7),
|
0x80 => Some(7),
|
||||||
_ => return drtioaux::send(0, &drtioaux::Packet::I2cBasicReply { succeeded: false }),
|
_ => { return drtioaux::send(0, &drtioaux::Packet::I2cBasicReply { succeeded: false }); }
|
||||||
};
|
};
|
||||||
let succeeded = i2c.pca954x_select(address, ch).is_ok();
|
let succeeded = i2c.pca954x_select(address, ch).is_ok();
|
||||||
drtioaux::send(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded })
|
drtioaux::send(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded })
|
||||||
}
|
}
|
||||||
|
|
||||||
drtioaux::Packet::SpiSetConfigRequest {
|
drtioaux::Packet::SpiSetConfigRequest { destination: _destination, busno: _busno,
|
||||||
destination: _destination,
|
flags: _flags, length: _length, div: _div, cs: _cs } => {
|
||||||
busno: _busno,
|
|
||||||
flags: _flags,
|
|
||||||
length: _length,
|
|
||||||
div: _div,
|
|
||||||
cs: _cs,
|
|
||||||
} => {
|
|
||||||
forward!(_routing_table, _destination, *_rank, _repeaters, &packet, timer);
|
forward!(_routing_table, _destination, *_rank, _repeaters, &packet, timer);
|
||||||
// todo: reimplement when/if SPI is available
|
// todo: reimplement when/if SPI is available
|
||||||
//let succeeded = spi::set_config(busno, flags, length, div, cs).is_ok();
|
//let succeeded = spi::set_config(busno, flags, length, div, cs).is_ok();
|
||||||
drtioaux::send(0, &drtioaux::Packet::SpiBasicReply { succeeded: false })
|
drtioaux::send(0,
|
||||||
}
|
&drtioaux::Packet::SpiBasicReply { succeeded: false })
|
||||||
drtioaux::Packet::SpiWriteRequest {
|
},
|
||||||
destination: _destination,
|
drtioaux::Packet::SpiWriteRequest { destination: _destination, busno: _busno, data: _data } => {
|
||||||
busno: _busno,
|
|
||||||
data: _data,
|
|
||||||
} => {
|
|
||||||
forward!(_routing_table, _destination, *_rank, _repeaters, &packet, timer);
|
forward!(_routing_table, _destination, *_rank, _repeaters, &packet, timer);
|
||||||
// todo: reimplement when/if SPI is available
|
// todo: reimplement when/if SPI is available
|
||||||
//let succeeded = spi::write(busno, data).is_ok();
|
//let succeeded = spi::write(busno, data).is_ok();
|
||||||
drtioaux::send(0, &drtioaux::Packet::SpiBasicReply { succeeded: false })
|
drtioaux::send(0,
|
||||||
|
&drtioaux::Packet::SpiBasicReply { succeeded: false })
|
||||||
}
|
}
|
||||||
drtioaux::Packet::SpiReadRequest {
|
drtioaux::Packet::SpiReadRequest { destination: _destination, busno: _busno } => {
|
||||||
destination: _destination,
|
|
||||||
busno: _busno,
|
|
||||||
} => {
|
|
||||||
forward!(_routing_table, _destination, *_rank, _repeaters, &packet, timer);
|
forward!(_routing_table, _destination, *_rank, _repeaters, &packet, timer);
|
||||||
// todo: reimplement when/if SPI is available
|
// todo: reimplement when/if SPI is available
|
||||||
// match spi::read(busno) {
|
// match spi::read(busno) {
|
||||||
|
@ -403,42 +326,8 @@ fn process_aux_packet(
|
||||||
// Err(_) => drtioaux::send(0,
|
// Err(_) => drtioaux::send(0,
|
||||||
// &drtioaux::Packet::SpiReadReply { succeeded: false, data: 0 })
|
// &drtioaux::Packet::SpiReadReply { succeeded: false, data: 0 })
|
||||||
// }
|
// }
|
||||||
drtioaux::send(
|
drtioaux::send(0,
|
||||||
0,
|
&drtioaux::Packet::SpiReadReply { succeeded: false, data: 0 })
|
||||||
&drtioaux::Packet::SpiReadReply {
|
|
||||||
succeeded: false,
|
|
||||||
data: 0,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
drtioaux::Packet::DmaAddTraceRequest {
|
|
||||||
destination: _destination,
|
|
||||||
id,
|
|
||||||
last,
|
|
||||||
length,
|
|
||||||
trace,
|
|
||||||
} => {
|
|
||||||
forward!(_routing_table, _destination, *_rank, _repeaters, &packet, timer);
|
|
||||||
let succeeded = dma_manager.add(id, last, &trace, length as usize).is_ok();
|
|
||||||
drtioaux::send(0, &drtioaux::Packet::DmaAddTraceReply { succeeded: succeeded })
|
|
||||||
}
|
|
||||||
drtioaux::Packet::DmaRemoveTraceRequest {
|
|
||||||
destination: _destination,
|
|
||||||
id,
|
|
||||||
} => {
|
|
||||||
forward!(_routing_table, _destination, *_rank, _repeaters, &packet, timer);
|
|
||||||
let succeeded = dma_manager.erase(id).is_ok();
|
|
||||||
drtioaux::send(0, &drtioaux::Packet::DmaRemoveTraceReply { succeeded: succeeded })
|
|
||||||
}
|
|
||||||
drtioaux::Packet::DmaPlaybackRequest {
|
|
||||||
destination: _destination,
|
|
||||||
id,
|
|
||||||
timestamp,
|
|
||||||
} => {
|
|
||||||
forward!(_routing_table, _destination, *_rank, _repeaters, &packet, timer);
|
|
||||||
let succeeded = dma_manager.playback(id, timestamp).is_ok();
|
|
||||||
drtioaux::send(0, &drtioaux::Packet::DmaPlaybackReply { succeeded: succeeded })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => {
|
_ => {
|
||||||
|
@ -448,24 +337,20 @@ fn process_aux_packet(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_aux_packets(
|
fn process_aux_packets(repeaters: &mut [repeater::Repeater],
|
||||||
repeaters: &mut [repeater::Repeater],
|
routing_table: &mut drtio_routing::RoutingTable, rank: &mut u8,
|
||||||
routing_table: &mut drtio_routing::RoutingTable,
|
timer: &mut GlobalTimer, i2c: &mut I2c) {
|
||||||
rank: &mut u8,
|
let result =
|
||||||
timer: &mut GlobalTimer,
|
drtioaux::recv(0).and_then(|packet| {
|
||||||
i2c: &mut I2c,
|
if let Some(packet) = packet {
|
||||||
dma_manager: &mut DmaManager,
|
process_aux_packet(repeaters, routing_table, rank, packet, timer, i2c)
|
||||||
) {
|
} else {
|
||||||
let result = drtioaux::recv(0).and_then(|packet| {
|
Ok(())
|
||||||
if let Some(packet) = packet {
|
}
|
||||||
process_aux_packet(repeaters, routing_table, rank, packet, timer, i2c, dma_manager)
|
});
|
||||||
} else {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
});
|
|
||||||
match result {
|
match result {
|
||||||
Ok(()) => (),
|
Ok(()) => (),
|
||||||
Err(e) => warn!("aux packet error ({:?})", e),
|
Err(e) => warn!("aux packet error ({:?})", e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -485,10 +370,7 @@ fn drtiosat_process_errors() {
|
||||||
unsafe {
|
unsafe {
|
||||||
destination = csr::drtiosat::buffer_space_timeout_dest_read();
|
destination = csr::drtiosat::buffer_space_timeout_dest_read();
|
||||||
}
|
}
|
||||||
error!(
|
error!("timeout attempting to get buffer space from CRI, destination=0x{:02x}", destination)
|
||||||
"timeout attempting to get buffer space from CRI, destination=0x{:02x}",
|
|
||||||
destination
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
if errors & 8 != 0 {
|
if errors & 8 != 0 {
|
||||||
let channel;
|
let channel;
|
||||||
|
@ -499,13 +381,8 @@ fn drtiosat_process_errors() {
|
||||||
timestamp_event = csr::drtiosat::underflow_timestamp_event_read() as i64;
|
timestamp_event = csr::drtiosat::underflow_timestamp_event_read() as i64;
|
||||||
timestamp_counter = csr::drtiosat::underflow_timestamp_counter_read() as i64;
|
timestamp_counter = csr::drtiosat::underflow_timestamp_counter_read() as i64;
|
||||||
}
|
}
|
||||||
error!(
|
error!("write underflow, channel={}, timestamp={}, counter={}, slack={}",
|
||||||
"write underflow, channel={}, timestamp={}, counter={}, slack={}",
|
channel, timestamp_event, timestamp_counter, timestamp_event-timestamp_counter);
|
||||||
channel,
|
|
||||||
timestamp_event,
|
|
||||||
timestamp_counter,
|
|
||||||
timestamp_event - timestamp_counter
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
if errors & 16 != 0 {
|
if errors & 16 != 0 {
|
||||||
error!("write overflow");
|
error!("write overflow");
|
||||||
|
@ -515,6 +392,25 @@ fn drtiosat_process_errors() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[cfg(has_rtio_crg)]
|
||||||
|
fn init_rtio_crg(timer: &mut GlobalTimer) {
|
||||||
|
unsafe {
|
||||||
|
csr::rtio_crg::pll_reset_write(0);
|
||||||
|
}
|
||||||
|
timer.delay_us(150);
|
||||||
|
let locked = unsafe { csr::rtio_crg::pll_locked_read() != 0 };
|
||||||
|
if !locked {
|
||||||
|
error!("RTIO clock failed");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
info!("RTIO PLL locked");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(has_rtio_crg))]
|
||||||
|
fn init_rtio_crg(_timer: &mut GlobalTimer) { }
|
||||||
|
|
||||||
fn hardware_tick(ts: &mut u64, timer: &mut GlobalTimer) {
|
fn hardware_tick(ts: &mut u64, timer: &mut GlobalTimer) {
|
||||||
let now = timer.get_time();
|
let now = timer.get_time();
|
||||||
let mut ts_ms = Milliseconds(*ts);
|
let mut ts_ms = Milliseconds(*ts);
|
||||||
|
@ -525,41 +421,47 @@ fn hardware_tick(ts: &mut u64, timer: &mut GlobalTimer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(all(has_si5324, rtio_frequency = "125.0"))]
|
#[cfg(all(has_si5324, rtio_frequency = "125.0"))]
|
||||||
const SI5324_SETTINGS: si5324::FrequencySettings = si5324::FrequencySettings {
|
const SI5324_SETTINGS: si5324::FrequencySettings
|
||||||
n1_hs: 5,
|
= si5324::FrequencySettings {
|
||||||
nc1_ls: 8,
|
n1_hs : 5,
|
||||||
n2_hs: 7,
|
nc1_ls : 8,
|
||||||
n2_ls: 360,
|
n2_hs : 7,
|
||||||
n31: 63,
|
n2_ls : 360,
|
||||||
n32: 63,
|
n31 : 63,
|
||||||
bwsel: 4,
|
n32 : 63,
|
||||||
crystal_as_ckin2: true,
|
bwsel : 4,
|
||||||
|
crystal_ref: true
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(all(has_si5324, rtio_frequency = "100.0"))]
|
#[cfg(all(has_si5324, rtio_frequency = "100.0"))]
|
||||||
const SI5324_SETTINGS: si5324::FrequencySettings = si5324::FrequencySettings {
|
const SI5324_SETTINGS: si5324::FrequencySettings
|
||||||
n1_hs: 5,
|
= si5324::FrequencySettings {
|
||||||
nc1_ls: 10,
|
n1_hs : 5,
|
||||||
n2_hs: 10,
|
nc1_ls : 10,
|
||||||
n2_ls: 250,
|
n2_hs : 10,
|
||||||
n31: 50,
|
n2_ls : 250,
|
||||||
n32: 50,
|
n31 : 50,
|
||||||
bwsel: 4,
|
n32 : 50,
|
||||||
crystal_as_ckin2: true,
|
bwsel : 4,
|
||||||
|
crystal_ref: true
|
||||||
};
|
};
|
||||||
|
|
||||||
static mut LOG_BUFFER: [u8; 1 << 17] = [0; 1 << 17];
|
static mut LOG_BUFFER: [u8; 1<<17] = [0; 1<<17];
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn main_core0() -> i32 {
|
pub extern fn main_core0() -> i32 {
|
||||||
enable_l2_cache(0x8);
|
enable_l2_cache(0x8);
|
||||||
|
|
||||||
let mut timer = GlobalTimer::start();
|
let mut timer = GlobalTimer::start();
|
||||||
|
|
||||||
let buffer_logger = unsafe { logger::BufferLogger::new(&mut LOG_BUFFER[..]) };
|
let buffer_logger = unsafe {
|
||||||
|
logger::BufferLogger::new(&mut LOG_BUFFER[..])
|
||||||
|
};
|
||||||
buffer_logger.set_uart_log_level(log::LevelFilter::Info);
|
buffer_logger.set_uart_log_level(log::LevelFilter::Info);
|
||||||
buffer_logger.register();
|
buffer_logger.register();
|
||||||
log::set_max_level(log::LevelFilter::Info);
|
log::set_max_level(log::LevelFilter::Info);
|
||||||
|
|
||||||
|
init_gateware();
|
||||||
|
|
||||||
info!("ARTIQ satellite manager starting...");
|
info!("ARTIQ satellite manager starting...");
|
||||||
info!("gateware ident {}", identifier_read(&mut [0; 64]));
|
info!("gateware ident {}", identifier_read(&mut [0; 64]));
|
||||||
|
@ -585,22 +487,15 @@ pub extern "C" fn main_core0() -> i32 {
|
||||||
#[cfg(has_si5324)]
|
#[cfg(has_si5324)]
|
||||||
si5324::setup(&mut i2c, &SI5324_SETTINGS, si5324::Input::Ckin1, &mut timer).expect("cannot initialize Si5324");
|
si5324::setup(&mut i2c, &SI5324_SETTINGS, si5324::Input::Ckin1, &mut timer).expect("cannot initialize Si5324");
|
||||||
|
|
||||||
timer.delay_us(100_000);
|
|
||||||
info!("Switching SYS clocks...");
|
|
||||||
unsafe {
|
unsafe {
|
||||||
csr::drtio_transceiver::stable_clkin_write(1);
|
csr::drtio_transceiver::stable_clkin_write(1);
|
||||||
}
|
}
|
||||||
timer.delay_us(20_000); // wait for CPLL/QPLL/MMCM lock
|
timer.delay_us(1500); // wait for CPLL/QPLL lock
|
||||||
let clk = unsafe { csr::sys_crg::current_clock_read() };
|
|
||||||
if clk == 1 {
|
|
||||||
info!("SYS CLK switched successfully");
|
|
||||||
} else {
|
|
||||||
panic!("SYS CLK did not switch");
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
csr::drtio_transceiver::txenable_write(0xffffffffu32 as _);
|
csr::drtio_transceiver::txenable_write(0xffffffffu32 as _);
|
||||||
}
|
}
|
||||||
|
init_rtio_crg(&mut timer);
|
||||||
|
|
||||||
#[cfg(has_drtio_routing)]
|
#[cfg(has_drtio_routing)]
|
||||||
let mut repeaters = [repeater::Repeater::default(); csr::DRTIOREP.len()];
|
let mut repeaters = [repeater::Repeater::default(); csr::DRTIOREP.len()];
|
||||||
|
@ -608,7 +503,7 @@ pub extern "C" fn main_core0() -> i32 {
|
||||||
let mut repeaters = [repeater::Repeater::default(); 0];
|
let mut repeaters = [repeater::Repeater::default(); 0];
|
||||||
for i in 0..repeaters.len() {
|
for i in 0..repeaters.len() {
|
||||||
repeaters[i] = repeater::Repeater::new(i as u8);
|
repeaters[i] = repeater::Repeater::new(i as u8);
|
||||||
}
|
}
|
||||||
let mut routing_table = drtio_routing::RoutingTable::default_empty();
|
let mut routing_table = drtio_routing::RoutingTable::default_empty();
|
||||||
let mut rank = 1;
|
let mut rank = 1;
|
||||||
|
|
||||||
|
@ -631,25 +526,13 @@ pub extern "C" fn main_core0() -> i32 {
|
||||||
si5324::siphaser::calibrate_skew(&mut timer).expect("failed to calibrate skew");
|
si5324::siphaser::calibrate_skew(&mut timer).expect("failed to calibrate skew");
|
||||||
}
|
}
|
||||||
|
|
||||||
// DMA manager created here, so when link is dropped, all DMA traces
|
|
||||||
// are cleared out for a clean slate on subsequent connections,
|
|
||||||
// without a manual intervention.
|
|
||||||
let mut dma_manager = DmaManager::new();
|
|
||||||
|
|
||||||
drtioaux::reset(0);
|
drtioaux::reset(0);
|
||||||
drtiosat_reset(false);
|
drtiosat_reset(false);
|
||||||
drtiosat_reset_phy(false);
|
drtiosat_reset_phy(false);
|
||||||
|
|
||||||
while drtiosat_link_rx_up() {
|
while drtiosat_link_rx_up() {
|
||||||
drtiosat_process_errors();
|
drtiosat_process_errors();
|
||||||
process_aux_packets(
|
process_aux_packets(&mut repeaters, &mut routing_table, &mut rank, &mut timer, &mut i2c);
|
||||||
&mut repeaters,
|
|
||||||
&mut routing_table,
|
|
||||||
&mut rank,
|
|
||||||
&mut timer,
|
|
||||||
&mut i2c,
|
|
||||||
&mut dma_manager,
|
|
||||||
);
|
|
||||||
#[allow(unused_mut)]
|
#[allow(unused_mut)]
|
||||||
for mut rep in repeaters.iter_mut() {
|
for mut rep in repeaters.iter_mut() {
|
||||||
rep.service(&routing_table, rank, &mut timer);
|
rep.service(&routing_table, rank, &mut timer);
|
||||||
|
@ -666,24 +549,6 @@ pub extern "C" fn main_core0() -> i32 {
|
||||||
error!("aux packet error: {:?}", e);
|
error!("aux packet error: {:?}", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(status) = dma_manager.check_state() {
|
|
||||||
info!(
|
|
||||||
"playback done, error: {}, channel: {}, timestamp: {}",
|
|
||||||
status.error, status.channel, status.timestamp
|
|
||||||
);
|
|
||||||
if let Err(e) = drtioaux::send(
|
|
||||||
0,
|
|
||||||
&drtioaux::Packet::DmaPlaybackStatus {
|
|
||||||
destination: rank,
|
|
||||||
id: status.id,
|
|
||||||
error: status.error,
|
|
||||||
channel: status.channel,
|
|
||||||
timestamp: status.timestamp,
|
|
||||||
},
|
|
||||||
) {
|
|
||||||
error!("error sending DMA playback status: {:?}", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
drtiosat_reset_phy(true);
|
drtiosat_reset_phy(true);
|
||||||
|
@ -700,7 +565,7 @@ extern "C" {
|
||||||
}
|
}
|
||||||
|
|
||||||
interrupt_handler!(IRQ, irq, __irq_stack0_start, __irq_stack1_start, {
|
interrupt_handler!(IRQ, irq, __irq_stack0_start, __irq_stack1_start, {
|
||||||
if MPIDR.read().cpu_id() == 1 {
|
if MPIDR.read().cpu_id() == 1{
|
||||||
let mpcore = mpcore::RegisterBlock::mpcore();
|
let mpcore = mpcore::RegisterBlock::mpcore();
|
||||||
let mut gic = gic::InterruptController::gic(mpcore);
|
let mut gic = gic::InterruptController::gic(mpcore);
|
||||||
let id = gic.get_interrupt_id();
|
let id = gic.get_interrupt_id();
|
||||||
|
@ -713,7 +578,7 @@ interrupt_handler!(IRQ, irq, __irq_stack0_start, __irq_stack1_start, {
|
||||||
notify_spin_lock();
|
notify_spin_lock();
|
||||||
main_core1();
|
main_core1();
|
||||||
}
|
}
|
||||||
stdio::drop_uart();
|
stdio::drop_uart();
|
||||||
}
|
}
|
||||||
loop {}
|
loop {}
|
||||||
});
|
});
|
||||||
|
@ -740,21 +605,18 @@ pub fn main_core1() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn exception(_vect: u32, _regs: *const u32, pc: u32, ea: u32) {
|
pub extern fn exception(_vect: u32, _regs: *const u32, pc: u32, ea: u32) {
|
||||||
|
|
||||||
fn hexdump(addr: u32) {
|
fn hexdump(addr: u32) {
|
||||||
let addr = (addr - addr % 4) as *const u32;
|
let addr = (addr - addr % 4) as *const u32;
|
||||||
let mut ptr = addr;
|
let mut ptr = addr;
|
||||||
println!("@ {:08p}", ptr);
|
println!("@ {:08p}", ptr);
|
||||||
for _ in 0..4 {
|
for _ in 0..4 {
|
||||||
print!("+{:04x}: ", ptr as usize - addr as usize);
|
print!("+{:04x}: ", ptr as usize - addr as usize);
|
||||||
print!("{:08x} ", unsafe { *ptr });
|
print!("{:08x} ", unsafe { *ptr }); ptr = ptr.wrapping_offset(1);
|
||||||
ptr = ptr.wrapping_offset(1);
|
print!("{:08x} ", unsafe { *ptr }); ptr = ptr.wrapping_offset(1);
|
||||||
print!("{:08x} ", unsafe { *ptr });
|
print!("{:08x} ", unsafe { *ptr }); ptr = ptr.wrapping_offset(1);
|
||||||
ptr = ptr.wrapping_offset(1);
|
print!("{:08x}\n", unsafe { *ptr }); ptr = ptr.wrapping_offset(1);
|
||||||
print!("{:08x} ", unsafe { *ptr });
|
|
||||||
ptr = ptr.wrapping_offset(1);
|
|
||||||
print!("{:08x}\n", unsafe { *ptr });
|
|
||||||
ptr = ptr.wrapping_offset(1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -786,11 +648,7 @@ pub fn panic_fmt(info: &core::panic::PanicInfo) -> ! {
|
||||||
} else {
|
} else {
|
||||||
println!("");
|
println!("");
|
||||||
}
|
}
|
||||||
#[cfg(feature = "target_kasli_soc")]
|
|
||||||
{
|
|
||||||
let mut err_led = ErrorLED::error_led();
|
|
||||||
err_led.toggle(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
@ -804,7 +662,7 @@ extern "C" {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
extern "C" fn dl_unwind_find_exidx(_pc: *const u32, len_ptr: *mut u32) -> *const u32 {
|
extern fn dl_unwind_find_exidx(_pc: *const u32, len_ptr: *mut u32) -> *const u32 {
|
||||||
let length;
|
let length;
|
||||||
let start: *const u32;
|
let start: *const u32;
|
||||||
unsafe {
|
unsafe {
|
||||||
|
|
|
@ -1,16 +1,19 @@
|
||||||
|
use libboard_artiq::{drtioaux, drtio_routing};
|
||||||
|
use libboard_zynq::timer::GlobalTimer;
|
||||||
|
|
||||||
#[cfg(has_drtio_routing)]
|
#[cfg(has_drtio_routing)]
|
||||||
use embedded_hal::prelude::_embedded_hal_blocking_delay_DelayUs;
|
use libboard_artiq::{pl::csr};
|
||||||
#[cfg(has_drtio_routing)]
|
|
||||||
use libboard_artiq::pl::csr;
|
|
||||||
use libboard_artiq::{drtio_routing, drtioaux};
|
|
||||||
#[cfg(has_drtio_routing)]
|
#[cfg(has_drtio_routing)]
|
||||||
use libboard_zynq::time::Milliseconds;
|
use libboard_zynq::time::Milliseconds;
|
||||||
use libboard_zynq::timer::GlobalTimer;
|
#[cfg(has_drtio_routing)]
|
||||||
|
use embedded_hal::prelude::_embedded_hal_blocking_delay_DelayUs;
|
||||||
|
|
||||||
#[cfg(has_drtio_routing)]
|
#[cfg(has_drtio_routing)]
|
||||||
fn rep_link_rx_up(repno: u8) -> bool {
|
fn rep_link_rx_up(repno: u8) -> bool {
|
||||||
let repno = repno as usize;
|
let repno = repno as usize;
|
||||||
unsafe { (csr::DRTIOREP[repno].rx_up_read)() == 1 }
|
unsafe {
|
||||||
|
(csr::DRTIOREP[repno].rx_up_read)() == 1
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(has_drtio_routing)]
|
#[cfg(has_drtio_routing)]
|
||||||
|
@ -20,14 +23,12 @@ enum RepeaterState {
|
||||||
SendPing { ping_count: u16 },
|
SendPing { ping_count: u16 },
|
||||||
WaitPingReply { ping_count: u16, timeout: Milliseconds },
|
WaitPingReply { ping_count: u16, timeout: Milliseconds },
|
||||||
Up,
|
Up,
|
||||||
Failed,
|
Failed
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(has_drtio_routing)]
|
#[cfg(has_drtio_routing)]
|
||||||
impl Default for RepeaterState {
|
impl Default for RepeaterState {
|
||||||
fn default() -> RepeaterState {
|
fn default() -> RepeaterState { RepeaterState::Down }
|
||||||
RepeaterState::Down
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(has_drtio_routing)]
|
#[cfg(has_drtio_routing)]
|
||||||
|
@ -35,7 +36,7 @@ impl Default for RepeaterState {
|
||||||
pub struct Repeater {
|
pub struct Repeater {
|
||||||
repno: u8,
|
repno: u8,
|
||||||
auxno: u8,
|
auxno: u8,
|
||||||
state: RepeaterState,
|
state: RepeaterState
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(has_drtio_routing)]
|
#[cfg(has_drtio_routing)]
|
||||||
|
@ -44,7 +45,7 @@ impl Repeater {
|
||||||
Repeater {
|
Repeater {
|
||||||
repno: repno,
|
repno: repno,
|
||||||
auxno: repno + 1,
|
auxno: repno + 1,
|
||||||
state: RepeaterState::Down,
|
state: RepeaterState::Down
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,7 +54,8 @@ impl Repeater {
|
||||||
self.state == RepeaterState::Up
|
self.state == RepeaterState::Up
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn service(&mut self, routing_table: &drtio_routing::RoutingTable, rank: u8, timer: &mut GlobalTimer) {
|
pub fn service(&mut self, routing_table: &drtio_routing::RoutingTable, rank: u8,
|
||||||
|
timer: &mut GlobalTimer) {
|
||||||
self.process_local_errors();
|
self.process_local_errors();
|
||||||
|
|
||||||
match self.state {
|
match self.state {
|
||||||
|
@ -68,7 +70,7 @@ impl Repeater {
|
||||||
drtioaux::send(self.auxno, &drtioaux::Packet::EchoRequest).unwrap();
|
drtioaux::send(self.auxno, &drtioaux::Packet::EchoRequest).unwrap();
|
||||||
self.state = RepeaterState::WaitPingReply {
|
self.state = RepeaterState::WaitPingReply {
|
||||||
ping_count: ping_count + 1,
|
ping_count: ping_count + 1,
|
||||||
timeout: timer.get_time() + Milliseconds(100),
|
timeout: timer.get_time() + Milliseconds(100)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
error!("[REP#{}] link RX went down during ping", self.repno);
|
error!("[REP#{}] link RX went down during ping", self.repno);
|
||||||
|
@ -130,7 +132,7 @@ impl Repeater {
|
||||||
match drtioaux::recv(self.auxno) {
|
match drtioaux::recv(self.auxno) {
|
||||||
Ok(Some(packet)) => warn!("[REP#{}] unsolicited aux packet: {:?}", self.repno, packet),
|
Ok(Some(packet)) => warn!("[REP#{}] unsolicited aux packet: {:?}", self.repno, packet),
|
||||||
Ok(None) => (),
|
Ok(None) => (),
|
||||||
Err(_) => warn!("[REP#{}] aux packet error", self.repno),
|
Err(_) => warn!("[REP#{}] aux packet error", self.repno)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,20 +155,14 @@ impl Repeater {
|
||||||
cmd = (csr::DRTIOREP[repno].command_missed_cmd_read)();
|
cmd = (csr::DRTIOREP[repno].command_missed_cmd_read)();
|
||||||
chan_sel = (csr::DRTIOREP[repno].command_missed_chan_sel_read)();
|
chan_sel = (csr::DRTIOREP[repno].command_missed_chan_sel_read)();
|
||||||
}
|
}
|
||||||
error!(
|
error!("[REP#{}] CRI command missed, cmd={}, chan_sel=0x{:06x}", repno, cmd, chan_sel)
|
||||||
"[REP#{}] CRI command missed, cmd={}, chan_sel=0x{:06x}",
|
|
||||||
repno, cmd, chan_sel
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
if errors & 8 != 0 {
|
if errors & 8 != 0 {
|
||||||
let destination;
|
let destination;
|
||||||
unsafe {
|
unsafe {
|
||||||
destination = (csr::DRTIOREP[repno].buffer_space_timeout_dest_read)();
|
destination = (csr::DRTIOREP[repno].buffer_space_timeout_dest_read)();
|
||||||
}
|
}
|
||||||
error!(
|
error!("[REP#{}] timeout attempting to get remote buffer space, destination=0x{:02x}", repno, destination);
|
||||||
"[REP#{}] timeout attempting to get remote buffer space, destination=0x{:02x}",
|
|
||||||
repno, destination
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
unsafe {
|
unsafe {
|
||||||
(csr::DRTIOREP[repno].protocol_error_write)(errors);
|
(csr::DRTIOREP[repno].protocol_error_write)(errors);
|
||||||
|
@ -185,7 +181,7 @@ impl Repeater {
|
||||||
match drtioaux::recv(self.auxno) {
|
match drtioaux::recv(self.auxno) {
|
||||||
Ok(Some(packet)) => return Ok(packet),
|
Ok(Some(packet)) => return Ok(packet),
|
||||||
Ok(None) => (),
|
Ok(None) => (),
|
||||||
Err(e) => return Err(e),
|
Err(e) => return Err(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -221,24 +217,15 @@ impl Repeater {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_path(
|
pub fn set_path(&self, destination: u8, hops: &[u8; drtio_routing::MAX_HOPS], timer: &mut GlobalTimer) -> Result<(), drtioaux::Error> {
|
||||||
&self,
|
|
||||||
destination: u8,
|
|
||||||
hops: &[u8; drtio_routing::MAX_HOPS],
|
|
||||||
timer: &mut GlobalTimer,
|
|
||||||
) -> Result<(), drtioaux::Error> {
|
|
||||||
if self.state != RepeaterState::Up {
|
if self.state != RepeaterState::Up {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
drtioaux::send(
|
drtioaux::send(self.auxno, &drtioaux::Packet::RoutingSetPath {
|
||||||
self.auxno,
|
destination: destination,
|
||||||
&drtioaux::Packet::RoutingSetPath {
|
hops: *hops
|
||||||
destination: destination,
|
}).unwrap();
|
||||||
hops: *hops,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
let reply = self.recv_aux_timeout(200, timer)?;
|
let reply = self.recv_aux_timeout(200, timer)?;
|
||||||
if reply != drtioaux::Packet::RoutingAck {
|
if reply != drtioaux::Packet::RoutingAck {
|
||||||
return Err(drtioaux::Error::UnexpectedReply);
|
return Err(drtioaux::Error::UnexpectedReply);
|
||||||
|
@ -246,11 +233,7 @@ impl Repeater {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load_routing_table(
|
pub fn load_routing_table(&self, routing_table: &drtio_routing::RoutingTable, timer: &mut GlobalTimer) -> Result<(), drtioaux::Error> {
|
||||||
&self,
|
|
||||||
routing_table: &drtio_routing::RoutingTable,
|
|
||||||
timer: &mut GlobalTimer,
|
|
||||||
) -> Result<(), drtioaux::Error> {
|
|
||||||
for i in 0..drtio_routing::DEST_COUNT {
|
for i in 0..drtio_routing::DEST_COUNT {
|
||||||
self.set_path(i as u8, &routing_table.0[i], timer)?;
|
self.set_path(i as u8, &routing_table.0[i], timer)?;
|
||||||
}
|
}
|
||||||
|
@ -261,7 +244,9 @@ impl Repeater {
|
||||||
if self.state != RepeaterState::Up {
|
if self.state != RepeaterState::Up {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
drtioaux::send(self.auxno, &drtioaux::Packet::RoutingSetRank { rank: rank }).unwrap();
|
drtioaux::send(self.auxno, &drtioaux::Packet::RoutingSetRank {
|
||||||
|
rank: rank
|
||||||
|
}).unwrap();
|
||||||
let reply = self.recv_aux_timeout(200, timer)?;
|
let reply = self.recv_aux_timeout(200, timer)?;
|
||||||
if reply != drtioaux::Packet::RoutingAck {
|
if reply != drtioaux::Packet::RoutingAck {
|
||||||
return Err(drtioaux::Error::UnexpectedReply);
|
return Err(drtioaux::Error::UnexpectedReply);
|
||||||
|
@ -271,13 +256,9 @@ impl Repeater {
|
||||||
|
|
||||||
pub fn rtio_reset(&self, timer: &mut GlobalTimer) -> Result<(), drtioaux::Error> {
|
pub fn rtio_reset(&self, timer: &mut GlobalTimer) -> Result<(), drtioaux::Error> {
|
||||||
let repno = self.repno as usize;
|
let repno = self.repno as usize;
|
||||||
unsafe {
|
unsafe { (csr::DRTIOREP[repno].reset_write)(1); }
|
||||||
(csr::DRTIOREP[repno].reset_write)(1);
|
|
||||||
}
|
|
||||||
timer.delay_us(100);
|
timer.delay_us(100);
|
||||||
unsafe {
|
unsafe { (csr::DRTIOREP[repno].reset_write)(0); }
|
||||||
(csr::DRTIOREP[repno].reset_write)(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if self.state != RepeaterState::Up {
|
if self.state != RepeaterState::Up {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
@ -294,21 +275,16 @@ impl Repeater {
|
||||||
|
|
||||||
#[cfg(not(has_drtio_routing))]
|
#[cfg(not(has_drtio_routing))]
|
||||||
#[derive(Clone, Copy, Default)]
|
#[derive(Clone, Copy, Default)]
|
||||||
pub struct Repeater {}
|
pub struct Repeater {
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(not(has_drtio_routing))]
|
#[cfg(not(has_drtio_routing))]
|
||||||
impl Repeater {
|
impl Repeater {
|
||||||
pub fn new(_repno: u8) -> Repeater {
|
pub fn new(_repno: u8) -> Repeater { Repeater::default() }
|
||||||
Repeater::default()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn service(&self, _routing_table: &drtio_routing::RoutingTable, _rank: u8, _timer: &mut GlobalTimer) {}
|
pub fn service(&self, _routing_table: &drtio_routing::RoutingTable, _rank: u8, _timer: &mut GlobalTimer) { }
|
||||||
|
|
||||||
pub fn sync_tsc(&self, _timer: &mut GlobalTimer) -> Result<(), drtioaux::Error> {
|
pub fn sync_tsc(&self, _timer: &mut GlobalTimer) -> Result<(), drtioaux::Error> { Ok(()) }
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn rtio_reset(&self, _timer: &mut GlobalTimer) -> Result<(), drtioaux::Error> {
|
pub fn rtio_reset(&self, _timer: &mut GlobalTimer) -> Result<(), drtioaux::Error> { Ok(()) }
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue