forked from M-Labs/artiq-zynq
Compare commits
No commits in common. "fix_nalgebra_typo" and "master" have entirely different histories.
fix_nalgeb
...
master
|
@ -62,7 +62,7 @@ Notes:
|
||||||
License
|
License
|
||||||
-------
|
-------
|
||||||
|
|
||||||
Copyright (C) 2019-2024 M-Labs Limited.
|
Copyright (C) 2019-2023 M-Labs Limited.
|
||||||
|
|
||||||
ARTIQ is free software: you can redistribute it and/or modify
|
ARTIQ is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU Lesser General Public License as published by
|
it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
|
111
flake.lock
111
flake.lock
|
@ -3,19 +3,19 @@
|
||||||
"artiq": {
|
"artiq": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"artiq-comtools": "artiq-comtools",
|
"artiq-comtools": "artiq-comtools",
|
||||||
|
"mozilla-overlay": "mozilla-overlay",
|
||||||
"nixpkgs": "nixpkgs",
|
"nixpkgs": "nixpkgs",
|
||||||
"rust-overlay": "rust-overlay",
|
|
||||||
"sipyco": "sipyco",
|
"sipyco": "sipyco",
|
||||||
"src-migen": "src-migen",
|
"src-migen": "src-migen",
|
||||||
"src-misoc": "src-misoc",
|
"src-misoc": "src-misoc",
|
||||||
"src-pythonparser": "src-pythonparser"
|
"src-pythonparser": "src-pythonparser"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1722417433,
|
"lastModified": 1697537883,
|
||||||
"narHash": "sha256-QEbcVdL1sUQEbMCvCUvPM8DKqwOth3gJpdiLTf4hPN8=",
|
"narHash": "sha256-GfadmYHFkczltX+rPf08YpAHjYa/31ZmmVD578BcFow=",
|
||||||
"ref": "refs/heads/master",
|
"ref": "refs/heads/master",
|
||||||
"rev": "0623480c82c28d57e14dc4f363374758a52284d3",
|
"rev": "b168f0bb4be1697ff100475c20ee304dcc31fcc2",
|
||||||
"revCount": 8952,
|
"revCount": 8573,
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/m-labs/artiq.git"
|
"url": "https://github.com/m-labs/artiq.git"
|
||||||
},
|
},
|
||||||
|
@ -37,11 +37,11 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1720768567,
|
"lastModified": 1693473687,
|
||||||
"narHash": "sha256-3VoK7o5MtHtbHLrc6Pv+eQWFtaz5Gd/YWyV5TD3c5Ss=",
|
"narHash": "sha256-BdLddCWbvoEyakcGwhph9b5dIU1iA0hCQV7KYgU8nos=",
|
||||||
"owner": "m-labs",
|
"owner": "m-labs",
|
||||||
"repo": "artiq-comtools",
|
"repo": "artiq-comtools",
|
||||||
"rev": "f93570d8f2ed5a3cfb3e1c16ab00f2540551e994",
|
"rev": "f522ef3dbc65961f17b2d3d41e927409d970fd79",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -55,11 +55,11 @@
|
||||||
"systems": "systems"
|
"systems": "systems"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1710146030,
|
"lastModified": 1692799911,
|
||||||
"narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
|
"narHash": "sha256-3eihraek4qL744EvQXsK1Ha6C3CR7nnT8X2qWap4RNk=",
|
||||||
"owner": "numtide",
|
"owner": "numtide",
|
||||||
"repo": "flake-utils",
|
"repo": "flake-utils",
|
||||||
"rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
|
"rev": "f9e7cf818399d17d347f847525c5a5a8032e4e44",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -71,11 +71,11 @@
|
||||||
"mozilla-overlay": {
|
"mozilla-overlay": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1704373101,
|
"lastModified": 1695805681,
|
||||||
"narHash": "sha256-+gi59LRWRQmwROrmE1E2b3mtocwueCQqZ60CwLG+gbg=",
|
"narHash": "sha256-1ElPLD8eFfnuIk0G52HGGpRtQZ4QPCjChRlEOfkZ5ro=",
|
||||||
"owner": "mozilla",
|
"owner": "mozilla",
|
||||||
"repo": "nixpkgs-mozilla",
|
"repo": "nixpkgs-mozilla",
|
||||||
"rev": "9b11a87c0cc54e308fa83aac5b4ee1816d5418a2",
|
"rev": "6eabade97bc28d707a8b9d82ad13ef143836736e",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -87,11 +87,27 @@
|
||||||
"mozilla-overlay_2": {
|
"mozilla-overlay_2": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1704373101,
|
"lastModified": 1695805681,
|
||||||
"narHash": "sha256-+gi59LRWRQmwROrmE1E2b3mtocwueCQqZ60CwLG+gbg=",
|
"narHash": "sha256-1ElPLD8eFfnuIk0G52HGGpRtQZ4QPCjChRlEOfkZ5ro=",
|
||||||
"owner": "mozilla",
|
"owner": "mozilla",
|
||||||
"repo": "nixpkgs-mozilla",
|
"repo": "nixpkgs-mozilla",
|
||||||
"rev": "9b11a87c0cc54e308fa83aac5b4ee1816d5418a2",
|
"rev": "6eabade97bc28d707a8b9d82ad13ef143836736e",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "mozilla",
|
||||||
|
"repo": "nixpkgs-mozilla",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"mozilla-overlay_3": {
|
||||||
|
"flake": false,
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1695805681,
|
||||||
|
"narHash": "sha256-1ElPLD8eFfnuIk0G52HGGpRtQZ4QPCjChRlEOfkZ5ro=",
|
||||||
|
"owner": "mozilla",
|
||||||
|
"repo": "nixpkgs-mozilla",
|
||||||
|
"rev": "6eabade97bc28d707a8b9d82ad13ef143836736e",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -102,16 +118,16 @@
|
||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1721924956,
|
"lastModified": 1697226376,
|
||||||
"narHash": "sha256-Sb1jlyRO+N8jBXEX9Pg9Z1Qb8Bw9QyOgLDNMEpmjZ2M=",
|
"narHash": "sha256-cumLLb1QOUtWieUnLGqo+ylNt3+fU8Lcv5Zl+tYbRUE=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "5ad6a14c6bf098e98800b091668718c336effc95",
|
"rev": "898cb2064b6e98b8c5499f37e81adbdf2925f7c5",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"ref": "nixos-unstable",
|
"ref": "nixos-23.05",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
|
@ -119,31 +135,10 @@
|
||||||
"root": {
|
"root": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"artiq": "artiq",
|
"artiq": "artiq",
|
||||||
"mozilla-overlay": "mozilla-overlay",
|
"mozilla-overlay": "mozilla-overlay_2",
|
||||||
"zynq-rs": "zynq-rs"
|
"zynq-rs": "zynq-rs"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"rust-overlay": {
|
|
||||||
"inputs": {
|
|
||||||
"nixpkgs": [
|
|
||||||
"artiq",
|
|
||||||
"nixpkgs"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1722046723,
|
|
||||||
"narHash": "sha256-G7/gHz8ORRvHd1/RIURrdcswKRPe9K0FsIYR4v5jSWo=",
|
|
||||||
"owner": "oxalica",
|
|
||||||
"repo": "rust-overlay",
|
|
||||||
"rev": "56baac5e6b2743d4730e664ea64f6d8a2aad0fbb",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "oxalica",
|
|
||||||
"repo": "rust-overlay",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"sipyco": {
|
"sipyco": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"nixpkgs": [
|
"nixpkgs": [
|
||||||
|
@ -152,11 +147,11 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1717637367,
|
"lastModified": 1697528004,
|
||||||
"narHash": "sha256-4mSm9wl5EMgzzrW6w86IDUevkEOT99FESHGcxcyQbD0=",
|
"narHash": "sha256-FFa2MbhAJEjwY58uOs0swvgymfjubHyWba6Q0X6CbB0=",
|
||||||
"owner": "m-labs",
|
"owner": "m-labs",
|
||||||
"repo": "sipyco",
|
"repo": "sipyco",
|
||||||
"rev": "02b96ec2473a3c3d3c980899de2564ddce949dab",
|
"rev": "c0a7ed350ccfb85474217057fc47b3f258ca8d99",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -168,11 +163,11 @@
|
||||||
"src-migen": {
|
"src-migen": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1721561053,
|
"lastModified": 1697013661,
|
||||||
"narHash": "sha256-z3LRhNmKZrjr6rFD0yxtccSa/SWvFIYmb+G/D5d2Jd8=",
|
"narHash": "sha256-qNCqgWyE4vTDmyjE2XMJqW1djuBxT25A36AzQfZqluU=",
|
||||||
"owner": "m-labs",
|
"owner": "m-labs",
|
||||||
"repo": "migen",
|
"repo": "migen",
|
||||||
"rev": "9279e8623f8433bc4f23ac51e5e2331bfe544417",
|
"rev": "aadc19df93b7aa9ca761aaebbb98a11e0cf2d7c7",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -184,11 +179,11 @@
|
||||||
"src-misoc": {
|
"src-misoc": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1715647536,
|
"lastModified": 1693709836,
|
||||||
"narHash": "sha256-q+USDcaKHABwW56Jzq8u94iGPWlyLXMyVt0j/Gyg+IE=",
|
"narHash": "sha256-YiCk05RYLzZu1CYkQ2r7XtjwVEqkUGTQn388uOls9tI=",
|
||||||
"ref": "refs/heads/master",
|
"ref": "refs/heads/master",
|
||||||
"rev": "fea9de558c730bc394a5936094ae95bb9d6fa726",
|
"rev": "58dc4ee60d165ce9145cf3d904241fc154b6407f",
|
||||||
"revCount": 2455,
|
"revCount": 2448,
|
||||||
"submodules": true,
|
"submodules": true,
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/m-labs/misoc.git"
|
"url": "https://github.com/m-labs/misoc.git"
|
||||||
|
@ -232,18 +227,18 @@
|
||||||
},
|
},
|
||||||
"zynq-rs": {
|
"zynq-rs": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"mozilla-overlay": "mozilla-overlay_2",
|
"mozilla-overlay": "mozilla-overlay_3",
|
||||||
"nixpkgs": [
|
"nixpkgs": [
|
||||||
"artiq",
|
"artiq",
|
||||||
"nixpkgs"
|
"nixpkgs"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1720537402,
|
"lastModified": 1697795161,
|
||||||
"narHash": "sha256-ybvaQ48SVBqYVqgYmGUdefGZkni7PJ90qYQPHnFOwDs=",
|
"narHash": "sha256-p89w9eoFJ2VFTDZ5Mrv5vsH0E1Ko9z1C6Ett281hCHg=",
|
||||||
"ref": "refs/heads/master",
|
"ref": "refs/heads/master",
|
||||||
"rev": "b2b3e5c933cbc4b7cb14adde480d7561a3ae71ee",
|
"rev": "be672ab662d8134ee11412a651864824f6483d4a",
|
||||||
"revCount": 648,
|
"revCount": 630,
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://git.m-labs.hk/m-labs/zynq-rs"
|
"url": "https://git.m-labs.hk/m-labs/zynq-rs"
|
||||||
},
|
},
|
||||||
|
|
75
flake.nix
75
flake.nix
|
@ -11,18 +11,17 @@
|
||||||
pkgs = import artiq.inputs.nixpkgs { system = "x86_64-linux"; overlays = [ (import mozilla-overlay) ]; };
|
pkgs = import artiq.inputs.nixpkgs { system = "x86_64-linux"; overlays = [ (import mozilla-overlay) ]; };
|
||||||
zynqpkgs = zynq-rs.packages.x86_64-linux;
|
zynqpkgs = zynq-rs.packages.x86_64-linux;
|
||||||
artiqpkgs = artiq.packages.x86_64-linux;
|
artiqpkgs = artiq.packages.x86_64-linux;
|
||||||
llvmPackages_11 = zynq-rs.llvmPackages_11;
|
|
||||||
|
|
||||||
rust = zynq-rs.rust;
|
rust = zynq-rs.rust;
|
||||||
rustPlatform = zynq-rs.rustPlatform;
|
rustPlatform = zynq-rs.rustPlatform;
|
||||||
|
|
||||||
fastnumbers = pkgs.python3Packages.buildPythonPackage rec {
|
fastnumbers = pkgs.python3Packages.buildPythonPackage rec {
|
||||||
pname = "fastnumbers";
|
pname = "fastnumbers";
|
||||||
version = "5.1.0";
|
version = "2.2.1";
|
||||||
|
|
||||||
src = pkgs.python3Packages.fetchPypi {
|
src = pkgs.python3Packages.fetchPypi {
|
||||||
inherit pname version;
|
inherit pname version;
|
||||||
sha256 = "sha256-4JLTP4uVwxcaL7NOV57+DFSwKQ3X+W/6onYkN2AdkKc=";
|
sha256 = "0j15i54p7nri6hkzn1wal9pxri4pgql01wgjccig6ar0v5jjbvsy";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -79,7 +78,6 @@
|
||||||
|
|
||||||
# migen/misoc version checks are broken with pyproject for some reason
|
# migen/misoc version checks are broken with pyproject for some reason
|
||||||
postPatch = ''
|
postPatch = ''
|
||||||
sed -i "1,4d" pyproject.toml
|
|
||||||
substituteInPlace pyproject.toml \
|
substituteInPlace pyproject.toml \
|
||||||
--replace '"migen@git+https://github.com/m-labs/migen",' ""
|
--replace '"migen@git+https://github.com/m-labs/migen",' ""
|
||||||
substituteInPlace pyproject.toml \
|
substituteInPlace pyproject.toml \
|
||||||
|
@ -114,7 +112,7 @@
|
||||||
"nist_clock_satellite" "nist_qc2_satellite" "acpki_nist_clock_satellite" "acpki_nist_qc2_satellite"
|
"nist_clock_satellite" "nist_qc2_satellite" "acpki_nist_clock_satellite" "acpki_nist_qc2_satellite"
|
||||||
"nist_clock_satellite_100mhz" "nist_qc2_satellite_100mhz" "acpki_nist_clock_satellite_100mhz" "acpki_nist_qc2_satellite_100mhz"
|
"nist_clock_satellite_100mhz" "nist_qc2_satellite_100mhz" "acpki_nist_clock_satellite_100mhz" "acpki_nist_qc2_satellite_100mhz"
|
||||||
];
|
];
|
||||||
board-package-set = { target, variant, json ? null }: let
|
build = { target, variant, json ? null }: let
|
||||||
szl = zynqpkgs."${target}-szl";
|
szl = zynqpkgs."${target}-szl";
|
||||||
fsbl = zynqpkgs."${target}-fsbl";
|
fsbl = zynqpkgs."${target}-fsbl";
|
||||||
fwtype = if builtins.elem variant sat_variants then "satman" else "runtime";
|
fwtype = if builtins.elem variant sat_variants then "satman" else "runtime";
|
||||||
|
@ -124,22 +122,18 @@
|
||||||
src = ./src;
|
src = ./src;
|
||||||
cargoLock = {
|
cargoLock = {
|
||||||
lockFile = src/Cargo.lock;
|
lockFile = src/Cargo.lock;
|
||||||
outputHashes = {
|
|
||||||
"tar-no-std-0.1.8" = "sha256-xm17108v4smXOqxdLvHl9CxTCJslmeogjm4Y87IXFuM=";
|
|
||||||
"nalgebra-0.32.6" = "sha256-L/YudkVOtfGYoNQKBD7LMk/sMYgRDzPDdpGL5rO7G2I=";
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
nativeBuildInputs = [
|
nativeBuildInputs = [
|
||||||
pkgs.gnumake
|
pkgs.gnumake
|
||||||
(pkgs.python3.withPackages(ps: [ ps.jsonschema artiqpkgs.migen migen-axi artiqpkgs.misoc artiqpkgs.artiq ]))
|
(pkgs.python3.withPackages(ps: [ ps.jsonschema artiqpkgs.migen migen-axi artiqpkgs.misoc artiqpkgs.artiq ]))
|
||||||
zynqpkgs.cargo-xbuild
|
zynqpkgs.cargo-xbuild
|
||||||
llvmPackages_11.llvm
|
pkgs.llvmPackages_9.llvm
|
||||||
llvmPackages_11.clang-unwrapped
|
pkgs.llvmPackages_9.clang-unwrapped
|
||||||
];
|
];
|
||||||
buildPhase = ''
|
buildPhase = ''
|
||||||
export XARGO_RUST_SRC="${rust}/lib/rustlib/src/rust/library"
|
export XARGO_RUST_SRC="${rust}/lib/rustlib/src/rust/library"
|
||||||
export CLANG_EXTRA_INCLUDE_DIR="${llvmPackages_11.clang-unwrapped.lib}/lib/clang/11.1.0/include"
|
export CLANG_EXTRA_INCLUDE_DIR="${pkgs.llvmPackages_9.clang-unwrapped.lib}/lib/clang/9.0.1/include"
|
||||||
export CARGO_HOME=$(mktemp -d cargo-home.XXX)
|
export CARGO_HOME=$(mktemp -d cargo-home.XXX)
|
||||||
export ZYNQ_RS=${zynq-rs}
|
export ZYNQ_RS=${zynq-rs}
|
||||||
make TARGET=${target} GWARGS="${if json == null then "-V ${variant}" else json}" ${fwtype}
|
make TARGET=${target} GWARGS="${if json == null then "-V ${variant}" else json}" ${fwtype}
|
||||||
|
@ -155,7 +149,6 @@
|
||||||
|
|
||||||
doCheck = false;
|
doCheck = false;
|
||||||
dontFixup = true;
|
dontFixup = true;
|
||||||
auditable = false;
|
|
||||||
};
|
};
|
||||||
gateware = pkgs.runCommand "${target}-${variant}-gateware"
|
gateware = pkgs.runCommand "${target}-${variant}-gateware"
|
||||||
{
|
{
|
||||||
|
@ -275,7 +268,7 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
# for hitl-tests
|
# for hitl-tests
|
||||||
zc706-nist_qc2 = (board-package-set { 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 {
|
||||||
name = "zc706-hitl-tests";
|
name = "zc706-hitl-tests";
|
||||||
|
|
||||||
|
@ -342,29 +335,29 @@
|
||||||
{
|
{
|
||||||
inherit fastnumbers artiq-netboot ramda migen-axi binutils-arm;
|
inherit fastnumbers artiq-netboot ramda migen-axi binutils-arm;
|
||||||
} //
|
} //
|
||||||
(board-package-set { target = "zc706"; variant = "nist_clock"; }) //
|
(build { target = "zc706"; variant = "nist_clock"; }) //
|
||||||
(board-package-set { target = "zc706"; variant = "nist_clock_master"; }) //
|
(build { target = "zc706"; variant = "nist_clock_master"; }) //
|
||||||
(board-package-set { target = "zc706"; variant = "nist_clock_master_100mhz"; }) //
|
(build { target = "zc706"; variant = "nist_clock_master_100mhz"; }) //
|
||||||
(board-package-set { target = "zc706"; variant = "nist_clock_satellite"; }) //
|
(build { target = "zc706"; variant = "nist_clock_satellite"; }) //
|
||||||
(board-package-set { target = "zc706"; variant = "nist_clock_satellite_100mhz"; }) //
|
(build { target = "zc706"; variant = "nist_clock_satellite_100mhz"; }) //
|
||||||
(board-package-set { target = "zc706"; variant = "nist_qc2"; }) //
|
(build { target = "zc706"; variant = "nist_qc2"; }) //
|
||||||
(board-package-set { target = "zc706"; variant = "nist_qc2_master"; }) //
|
(build { target = "zc706"; variant = "nist_qc2_master"; }) //
|
||||||
(board-package-set { target = "zc706"; variant = "nist_qc2_master_100mhz"; }) //
|
(build { target = "zc706"; variant = "nist_qc2_master_100mhz"; }) //
|
||||||
(board-package-set { target = "zc706"; variant = "nist_qc2_satellite"; }) //
|
(build { target = "zc706"; variant = "nist_qc2_satellite"; }) //
|
||||||
(board-package-set { target = "zc706"; variant = "nist_qc2_satellite_100mhz"; }) //
|
(build { target = "zc706"; variant = "nist_qc2_satellite_100mhz"; }) //
|
||||||
(board-package-set { target = "zc706"; variant = "acpki_nist_clock"; }) //
|
(build { target = "zc706"; variant = "acpki_nist_clock"; }) //
|
||||||
(board-package-set { target = "zc706"; variant = "acpki_nist_clock_master"; }) //
|
(build { target = "zc706"; variant = "acpki_nist_clock_master"; }) //
|
||||||
(board-package-set { target = "zc706"; variant = "acpki_nist_clock_master_100mhz"; }) //
|
(build { target = "zc706"; variant = "acpki_nist_clock_master_100mhz"; }) //
|
||||||
(board-package-set { target = "zc706"; variant = "acpki_nist_clock_satellite"; }) //
|
(build { target = "zc706"; variant = "acpki_nist_clock_satellite"; }) //
|
||||||
(board-package-set { target = "zc706"; variant = "acpki_nist_clock_satellite_100mhz"; }) //
|
(build { target = "zc706"; variant = "acpki_nist_clock_satellite_100mhz"; }) //
|
||||||
(board-package-set { target = "zc706"; variant = "acpki_nist_qc2"; }) //
|
(build { target = "zc706"; variant = "acpki_nist_qc2"; }) //
|
||||||
(board-package-set { target = "zc706"; variant = "acpki_nist_qc2_master"; }) //
|
(build { target = "zc706"; variant = "acpki_nist_qc2_master"; }) //
|
||||||
(board-package-set { target = "zc706"; variant = "acpki_nist_qc2_master_100mhz"; }) //
|
(build { target = "zc706"; variant = "acpki_nist_qc2_master_100mhz"; }) //
|
||||||
(board-package-set { target = "zc706"; variant = "acpki_nist_qc2_satellite"; }) //
|
(build { target = "zc706"; variant = "acpki_nist_qc2_satellite"; }) //
|
||||||
(board-package-set { target = "zc706"; variant = "acpki_nist_qc2_satellite_100mhz"; }) //
|
(build { target = "zc706"; variant = "acpki_nist_qc2_satellite_100mhz"; }) //
|
||||||
(board-package-set { target = "kasli_soc"; variant = "demo"; json = ./demo.json; }) //
|
(build { target = "kasli_soc"; variant = "demo"; json = ./demo.json; }) //
|
||||||
(board-package-set { target = "kasli_soc"; variant = "master"; json = ./kasli-soc-master.json; }) //
|
(build { target = "kasli_soc"; variant = "master"; json = ./kasli-soc-master.json; }) //
|
||||||
(board-package-set { 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; inherit fmt-check; };
|
||||||
|
|
||||||
|
@ -372,8 +365,8 @@
|
||||||
name = "artiq-zynq-dev-shell";
|
name = "artiq-zynq-dev-shell";
|
||||||
buildInputs = with pkgs; [
|
buildInputs = with pkgs; [
|
||||||
rust
|
rust
|
||||||
llvmPackages_11.llvm
|
llvmPackages_9.llvm
|
||||||
llvmPackages_11.clang-unwrapped
|
llvmPackages_9.clang-unwrapped
|
||||||
gnumake
|
gnumake
|
||||||
cacert
|
cacert
|
||||||
zynqpkgs.cargo-xbuild
|
zynqpkgs.cargo-xbuild
|
||||||
|
@ -386,13 +379,13 @@
|
||||||
binutils-arm
|
binutils-arm
|
||||||
];
|
];
|
||||||
XARGO_RUST_SRC = "${rust}/lib/rustlib/src/rust/library";
|
XARGO_RUST_SRC = "${rust}/lib/rustlib/src/rust/library";
|
||||||
CLANG_EXTRA_INCLUDE_DIR = "${llvmPackages_11.clang-unwrapped.lib}/lib/clang/11.1.0/include";
|
CLANG_EXTRA_INCLUDE_DIR = "${pkgs.llvmPackages_9.clang-unwrapped.lib}/lib/clang/9.0.1/include";
|
||||||
ZYNQ_RS = "${zynq-rs}";
|
ZYNQ_RS = "${zynq-rs}";
|
||||||
OPENOCD_ZYNQ = "${zynq-rs}/openocd";
|
OPENOCD_ZYNQ = "${zynq-rs}/openocd";
|
||||||
SZL = "${zynqpkgs.szl}";
|
SZL = "${zynqpkgs.szl}";
|
||||||
};
|
};
|
||||||
|
|
||||||
makeArtiqZynqPackage = board-package-set;
|
makeArtiqZynqPackage = build;
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,21 +2,6 @@
|
||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 3
|
version = 3
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "approx"
|
|
||||||
version = "0.5.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6"
|
|
||||||
dependencies = [
|
|
||||||
"num-traits",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "arrayvec"
|
|
||||||
version = "0.7.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "async-recursion"
|
name = "async-recursion"
|
||||||
version = "0.3.2"
|
version = "0.3.2"
|
||||||
|
@ -255,7 +240,6 @@ dependencies = [
|
||||||
"libsupport_zynq",
|
"libsupport_zynq",
|
||||||
"log",
|
"log",
|
||||||
"log_buffer",
|
"log_buffer",
|
||||||
"nalgebra",
|
|
||||||
"nb 0.1.3",
|
"nb 0.1.3",
|
||||||
"unwind",
|
"unwind",
|
||||||
"vcell",
|
"vcell",
|
||||||
|
@ -392,19 +376,6 @@ version = "0.7.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c75de51135344a4f8ed3cfe2720dc27736f7711989703a0b43aadf3753c55577"
|
checksum = "c75de51135344a4f8ed3cfe2720dc27736f7711989703a0b43aadf3753c55577"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "nalgebra"
|
|
||||||
version = "0.32.6"
|
|
||||||
source = "git+https://git.m-labs.hk/M-Labs/nalgebra.git?rev=dd00f9b#dd00f9b46046e0b931d1b470166db02fd29591be"
|
|
||||||
dependencies = [
|
|
||||||
"approx",
|
|
||||||
"num-complex",
|
|
||||||
"num-rational",
|
|
||||||
"num-traits",
|
|
||||||
"simba",
|
|
||||||
"typenum",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nb"
|
name = "nb"
|
||||||
version = "0.1.3"
|
version = "0.1.3"
|
||||||
|
@ -420,15 +391,6 @@ version = "1.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "546c37ac5d9e56f55e73b677106873d9d9f5190605e41a856503623648488cae"
|
checksum = "546c37ac5d9e56f55e73b677106873d9d9f5190605e41a856503623648488cae"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "num-complex"
|
|
||||||
version = "0.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "26873667bbbb7c5182d4a37c1add32cdf09f841af72da53318fdb81543c15085"
|
|
||||||
dependencies = [
|
|
||||||
"num-traits",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-derive"
|
name = "num-derive"
|
||||||
version = "0.3.3"
|
version = "0.3.3"
|
||||||
|
@ -440,26 +402,6 @@ dependencies = [
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "num-integer"
|
|
||||||
version = "0.1.46"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
|
|
||||||
dependencies = [
|
|
||||||
"num-traits",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "num-rational"
|
|
||||||
version = "0.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d41702bd167c2df5520b384281bc111a4b5efcf7fbc4c9c222c815b07e0a6a6a"
|
|
||||||
dependencies = [
|
|
||||||
"autocfg",
|
|
||||||
"num-integer",
|
|
||||||
"num-traits",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-traits"
|
name = "num-traits"
|
||||||
version = "0.2.15"
|
version = "0.2.15"
|
||||||
|
@ -467,15 +409,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
|
checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"autocfg",
|
"autocfg",
|
||||||
"libm",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "paste"
|
|
||||||
version = "1.0.15"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pin-project-lite"
|
name = "pin-project-lite"
|
||||||
version = "0.2.9"
|
version = "0.2.9"
|
||||||
|
@ -539,7 +474,6 @@ dependencies = [
|
||||||
"log_buffer",
|
"log_buffer",
|
||||||
"num-derive",
|
"num-derive",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
"tar-no-std",
|
|
||||||
"unwind",
|
"unwind",
|
||||||
"vcell",
|
"vcell",
|
||||||
"void",
|
"void",
|
||||||
|
@ -582,18 +516,6 @@ version = "0.1.20"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d4f410fedcf71af0345d7607d246e7ad15faaadd49d240ee3b24e5dc21a820ac"
|
checksum = "d4f410fedcf71af0345d7607d246e7ad15faaadd49d240ee3b24e5dc21a820ac"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "simba"
|
|
||||||
version = "0.8.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "50582927ed6f77e4ac020c057f37a268fc6aebc29225050365aacbb9deeeddc4"
|
|
||||||
dependencies = [
|
|
||||||
"approx",
|
|
||||||
"num-complex",
|
|
||||||
"num-traits",
|
|
||||||
"paste",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "smoltcp"
|
name = "smoltcp"
|
||||||
version = "0.7.5"
|
version = "0.7.5"
|
||||||
|
@ -616,22 +538,6 @@ dependencies = [
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tar-no-std"
|
|
||||||
version = "0.1.8"
|
|
||||||
source = "git+https://git.m-labs.hk/M-Labs/tar-no-std?rev=2ab6dc5#2ab6dc58e5249c59c4eb03eaf3a119bcdd678d32"
|
|
||||||
dependencies = [
|
|
||||||
"arrayvec",
|
|
||||||
"bitflags",
|
|
||||||
"log",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "typenum"
|
|
||||||
version = "1.17.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-ident"
|
name = "unicode-ident"
|
||||||
version = "1.0.5"
|
version = "1.0.5"
|
||||||
|
|
|
@ -1,119 +0,0 @@
|
||||||
from migen import *
|
|
||||||
from migen.genlib.cdc import PulseSynchronizer, MultiReg
|
|
||||||
from misoc.interconnect.csr import *
|
|
||||||
|
|
||||||
|
|
||||||
class DDMTDSampler(Module):
|
|
||||||
def __init__(self, cd_ref, main_clk_se):
|
|
||||||
self.ref_beating = Signal()
|
|
||||||
self.main_beating = Signal()
|
|
||||||
|
|
||||||
# # #
|
|
||||||
|
|
||||||
ref_clk = Signal()
|
|
||||||
self.specials +=[
|
|
||||||
# ISERDESE2 can only be driven from fabric via IDELAYE2 (see UG471)
|
|
||||||
Instance("IDELAYE2",
|
|
||||||
p_DELAY_SRC="DATAIN",
|
|
||||||
p_HIGH_PERFORMANCE_MODE="TRUE",
|
|
||||||
p_REFCLK_FREQUENCY=208.3, # REFCLK frequency from IDELAYCTRL
|
|
||||||
p_IDELAY_VALUE=0,
|
|
||||||
|
|
||||||
i_DATAIN=cd_ref.clk,
|
|
||||||
|
|
||||||
o_DATAOUT=ref_clk
|
|
||||||
),
|
|
||||||
Instance("ISERDESE2",
|
|
||||||
p_IOBDELAY="IFD", # use DDLY as input
|
|
||||||
p_DATA_RATE="SDR",
|
|
||||||
p_DATA_WIDTH=2, # min is 2
|
|
||||||
p_NUM_CE=1,
|
|
||||||
|
|
||||||
i_DDLY=ref_clk,
|
|
||||||
i_CE1=1,
|
|
||||||
i_CLK=ClockSignal("helper"),
|
|
||||||
i_CLKDIV=ClockSignal("helper"),
|
|
||||||
|
|
||||||
o_Q1=self.ref_beating
|
|
||||||
),
|
|
||||||
Instance("ISERDESE2",
|
|
||||||
p_DATA_RATE="SDR",
|
|
||||||
p_DATA_WIDTH=2, # min is 2
|
|
||||||
p_NUM_CE=1,
|
|
||||||
|
|
||||||
i_D=main_clk_se,
|
|
||||||
i_CE1=1,
|
|
||||||
i_CLK=ClockSignal("helper"),
|
|
||||||
i_CLKDIV=ClockSignal("helper"),
|
|
||||||
|
|
||||||
o_Q1=self.main_beating,
|
|
||||||
),
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
class DDMTDDeglitcherMedianEdge(Module):
|
|
||||||
def __init__(self, counter, input_signal, stable_0_period=100, stable_1_period=100):
|
|
||||||
self.tag = Signal(len(counter))
|
|
||||||
self.detect = Signal()
|
|
||||||
|
|
||||||
stable_0_counter = Signal(reset=stable_0_period - 1, max=stable_0_period)
|
|
||||||
stable_1_counter = Signal(reset=stable_1_period - 1, max=stable_1_period)
|
|
||||||
|
|
||||||
# # #
|
|
||||||
|
|
||||||
# Based on CERN's median edge deglitcher FSM
|
|
||||||
# https://white-rabbit.web.cern.ch/documents/Precise_time_and_frequency_transfer_in_a_White_Rabbit_network.pdf (p.72)
|
|
||||||
fsm = ClockDomainsRenamer("helper")(FSM(reset_state="WAIT_STABLE_0"))
|
|
||||||
self.submodules += fsm
|
|
||||||
|
|
||||||
fsm.act("WAIT_STABLE_0",
|
|
||||||
If(stable_0_counter != 0,
|
|
||||||
NextValue(stable_0_counter, stable_0_counter - 1)
|
|
||||||
).Else(
|
|
||||||
NextValue(stable_0_counter, stable_0_period - 1),
|
|
||||||
NextState("WAIT_EDGE")
|
|
||||||
),
|
|
||||||
If(input_signal,
|
|
||||||
NextValue(stable_0_counter, stable_0_period - 1)
|
|
||||||
),
|
|
||||||
)
|
|
||||||
fsm.act("WAIT_EDGE",
|
|
||||||
If(input_signal,
|
|
||||||
NextValue(self.tag, counter),
|
|
||||||
NextState("GOT_EDGE")
|
|
||||||
)
|
|
||||||
)
|
|
||||||
fsm.act("GOT_EDGE",
|
|
||||||
If(stable_1_counter != 0,
|
|
||||||
NextValue(stable_1_counter, stable_1_counter - 1)
|
|
||||||
).Else(
|
|
||||||
NextValue(stable_1_counter, stable_1_period - 1),
|
|
||||||
self.detect.eq(1),
|
|
||||||
NextState("WAIT_STABLE_0")
|
|
||||||
),
|
|
||||||
If(~input_signal,
|
|
||||||
NextValue(self.tag, self.tag + 1),
|
|
||||||
NextValue(stable_1_counter, stable_1_period - 1)
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class DDMTD(Module):
|
|
||||||
def __init__(self, counter, input_signal):
|
|
||||||
|
|
||||||
# in helper clock domain
|
|
||||||
self.h_tag = Signal(len(counter))
|
|
||||||
self.h_tag_update = Signal()
|
|
||||||
|
|
||||||
# # #
|
|
||||||
|
|
||||||
deglitcher = DDMTDDeglitcherMedianEdge(counter, input_signal)
|
|
||||||
self.submodules += deglitcher
|
|
||||||
|
|
||||||
self.sync.helper += [
|
|
||||||
self.h_tag_update.eq(0),
|
|
||||||
If(deglitcher.detect,
|
|
||||||
self.h_tag_update.eq(1),
|
|
||||||
self.h_tag.eq(deglitcher.tag)
|
|
||||||
)
|
|
||||||
]
|
|
|
@ -1,12 +1,12 @@
|
||||||
"""Auxiliary controller, common to satellite and master"""
|
"""Auxiliary controller, common to satellite and master"""
|
||||||
|
|
||||||
from artiq.gateware.drtio.aux_controller import (max_packet, aux_buffer_count,
|
from artiq.gateware.drtio.aux_controller import Transmitter, Receiver
|
||||||
Transmitter, Receiver)
|
|
||||||
from migen.fhdl.simplify import FullMemoryWE
|
from migen.fhdl.simplify import FullMemoryWE
|
||||||
from misoc.interconnect.csr import *
|
from misoc.interconnect.csr import *
|
||||||
from migen_axi.interconnect.sram import SRAM
|
from migen_axi.interconnect.sram import SRAM
|
||||||
from migen_axi.interconnect import axi
|
from migen_axi.interconnect import axi
|
||||||
|
|
||||||
|
max_packet = 1024
|
||||||
|
|
||||||
class _DRTIOAuxControllerBase(Module):
|
class _DRTIOAuxControllerBase(Module):
|
||||||
def __init__(self, link_layer):
|
def __init__(self, link_layer):
|
||||||
|
@ -27,12 +27,12 @@ class DRTIOAuxControllerAxi(_DRTIOAuxControllerBase):
|
||||||
tx_sdram_if = SRAM(self.transmitter.mem, read_only=False)
|
tx_sdram_if = SRAM(self.transmitter.mem, read_only=False)
|
||||||
rx_sdram_if = SRAM(self.receiver.mem, read_only=True)
|
rx_sdram_if = SRAM(self.receiver.mem, read_only=True)
|
||||||
aw_decoder = axi.AddressDecoder(self.bus.aw,
|
aw_decoder = axi.AddressDecoder(self.bus.aw,
|
||||||
[(lambda a: a[log2_int(max_packet*aux_buffer_count)] == 0, tx_sdram_if.bus.aw),
|
[(lambda a: a[log2_int(max_packet)] == 0, tx_sdram_if.bus.aw),
|
||||||
(lambda a: a[log2_int(max_packet*aux_buffer_count)] == 1, rx_sdram_if.bus.aw)],
|
(lambda a: a[log2_int(max_packet)] == 1, rx_sdram_if.bus.aw)],
|
||||||
register=True)
|
register=True)
|
||||||
ar_decoder = axi.AddressDecoder(self.bus.ar,
|
ar_decoder = axi.AddressDecoder(self.bus.ar,
|
||||||
[(lambda a: a[log2_int(max_packet*aux_buffer_count)] == 0, tx_sdram_if.bus.ar),
|
[(lambda a: a[log2_int(max_packet)] == 0, tx_sdram_if.bus.ar),
|
||||||
(lambda a: a[log2_int(max_packet*aux_buffer_count)] == 1, rx_sdram_if.bus.ar)],
|
(lambda a: a[log2_int(max_packet)] == 1, rx_sdram_if.bus.ar)],
|
||||||
register=True)
|
register=True)
|
||||||
# unlike wb, axi address decoder only connects ar/aw lanes,
|
# unlike wb, axi address decoder only connects ar/aw lanes,
|
||||||
# the rest must also be connected!
|
# the rest must also be connected!
|
||||||
|
@ -82,4 +82,4 @@ class DRTIOAuxControllerBare(_DRTIOAuxControllerBase):
|
||||||
return self.receiver.mem.get_port(write_capable=False)
|
return self.receiver.mem.get_port(write_capable=False)
|
||||||
|
|
||||||
def get_mem_size(self):
|
def get_mem_size(self):
|
||||||
return max_packet*aux_buffer_count
|
return max_packet
|
||||||
|
|
|
@ -20,7 +20,6 @@ from artiq.gateware.drtio.transceiver import gtx_7series, eem_serdes
|
||||||
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
|
||||||
from artiq.gateware.drtio import *
|
from artiq.gateware.drtio import *
|
||||||
from artiq.gateware.wrpll import wrpll
|
|
||||||
|
|
||||||
import dma
|
import dma
|
||||||
import analyzer
|
import analyzer
|
||||||
|
@ -109,7 +108,6 @@ class GenericStandalone(SoCCore):
|
||||||
def __init__(self, description, acpki=False):
|
def __init__(self, description, acpki=False):
|
||||||
self.acpki = acpki
|
self.acpki = acpki
|
||||||
clk_freq = description["rtio_frequency"]
|
clk_freq = description["rtio_frequency"]
|
||||||
with_wrpll = description["enable_wrpll"]
|
|
||||||
|
|
||||||
platform = kasli_soc.Platform()
|
platform = kasli_soc.Platform()
|
||||||
platform.toolchain.bitstream_commands.extend([
|
platform.toolchain.bitstream_commands.extend([
|
||||||
|
@ -121,6 +119,13 @@ class GenericStandalone(SoCCore):
|
||||||
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, ps_cd_sys=False)
|
||||||
|
|
||||||
self.config["HW_REV"] = description["hw_rev"]
|
self.config["HW_REV"] = description["hw_rev"]
|
||||||
|
|
||||||
|
|
||||||
|
self.submodules += SMAClkinForward(self.platform)
|
||||||
|
|
||||||
|
self.config["HAS_SI5324"] = None
|
||||||
|
self.config["SI5324_SOFT_RESET"] = None
|
||||||
|
|
||||||
clk_synth = platform.request("cdr_clk_clean_fabric")
|
clk_synth = platform.request("cdr_clk_clean_fabric")
|
||||||
clk_synth_se = Signal()
|
clk_synth_se = Signal()
|
||||||
clk_synth_se_buf = Signal()
|
clk_synth_se_buf = Signal()
|
||||||
|
@ -135,7 +140,6 @@ class GenericStandalone(SoCCore):
|
||||||
]
|
]
|
||||||
fix_serdes_timing_path(platform)
|
fix_serdes_timing_path(platform)
|
||||||
self.submodules.bootstrap = GTPBootstrapClock(self.platform, clk_freq)
|
self.submodules.bootstrap = GTPBootstrapClock(self.platform, clk_freq)
|
||||||
self.config["RTIO_FREQUENCY"] = str(clk_freq/1e6)
|
|
||||||
self.config["CLOCK_FREQUENCY"] = int(clk_freq)
|
self.config["CLOCK_FREQUENCY"] = int(clk_freq)
|
||||||
|
|
||||||
self.submodules.sys_crg = zynq_clocking.SYSCRG(self.platform, self.ps7, clk_synth_se_buf)
|
self.submodules.sys_crg = zynq_clocking.SYSCRG(self.platform, self.ps7, clk_synth_se_buf)
|
||||||
|
@ -145,23 +149,6 @@ class GenericStandalone(SoCCore):
|
||||||
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.crg.cd_sys = self.sys_crg.cd_sys
|
||||||
|
|
||||||
if with_wrpll:
|
|
||||||
self.submodules.wrpll_refclk = wrpll.FrequencyMultiplier(platform.request("sma_clkin"))
|
|
||||||
self.submodules.wrpll = wrpll.WRPLL(
|
|
||||||
platform=self.platform,
|
|
||||||
cd_ref=self.wrpll_refclk.cd_ref,
|
|
||||||
main_clk_se=clk_synth_se)
|
|
||||||
self.csr_devices.append("wrpll_refclk")
|
|
||||||
self.csr_devices.append("wrpll")
|
|
||||||
self.comb += self.ps7.core.core0.nfiq.eq(self.wrpll.ev.irq)
|
|
||||||
self.config["HAS_SI549"] = None
|
|
||||||
self.config["WRPLL_REF_CLK"] = "SMA_CLKIN"
|
|
||||||
else:
|
|
||||||
self.submodules += SMAClkinForward(self.platform)
|
|
||||||
self.config["HAS_SI5324"] = None
|
|
||||||
self.config["SI5324_SOFT_RESET"] = None
|
|
||||||
|
|
||||||
|
|
||||||
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:
|
||||||
|
@ -220,7 +207,6 @@ class GenericStandalone(SoCCore):
|
||||||
class GenericMaster(SoCCore):
|
class GenericMaster(SoCCore):
|
||||||
def __init__(self, description, acpki=False):
|
def __init__(self, description, acpki=False):
|
||||||
clk_freq = description["rtio_frequency"]
|
clk_freq = description["rtio_frequency"]
|
||||||
with_wrpll = description["enable_wrpll"]
|
|
||||||
|
|
||||||
has_drtio_over_eem = any(peripheral["type"] == "shuttler" for peripheral in description["peripherals"])
|
has_drtio_over_eem = any(peripheral["type"] == "shuttler" for peripheral in description["peripherals"])
|
||||||
self.acpki = acpki
|
self.acpki = acpki
|
||||||
|
@ -236,6 +222,8 @@ class GenericMaster(SoCCore):
|
||||||
|
|
||||||
self.config["HW_REV"] = description["hw_rev"]
|
self.config["HW_REV"] = description["hw_rev"]
|
||||||
|
|
||||||
|
self.submodules += SMAClkinForward(self.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.gt_drtio = gtx_7series.GTX(
|
self.submodules.gt_drtio = gtx_7series.GTX(
|
||||||
|
@ -243,23 +231,18 @@ class GenericMaster(SoCCore):
|
||||||
pads=data_pads,
|
pads=data_pads,
|
||||||
clk_freq=clk_freq)
|
clk_freq=clk_freq)
|
||||||
self.csr_devices.append("gt_drtio")
|
self.csr_devices.append("gt_drtio")
|
||||||
self.config["RTIO_FREQUENCY"] = str(clk_freq/1e6)
|
|
||||||
self.config["CLOCK_FREQUENCY"] = int(clk_freq)
|
self.config["CLOCK_FREQUENCY"] = int(clk_freq)
|
||||||
|
|
||||||
txout_buf = Signal()
|
txout_buf = Signal()
|
||||||
gtx0 = self.gt_drtio.gtxs[0]
|
gtx0 = self.gt_drtio.gtxs[0]
|
||||||
self.specials += Instance("BUFG", i_I=gtx0.txoutclk, o_O=txout_buf)
|
self.specials += Instance("BUFG", i_I=gtx0.txoutclk, o_O=txout_buf)
|
||||||
|
|
||||||
ext_async_rst = Signal()
|
|
||||||
|
|
||||||
self.submodules.bootstrap = GTPBootstrapClock(self.platform, clk_freq)
|
self.submodules.bootstrap = GTPBootstrapClock(self.platform, clk_freq)
|
||||||
self.submodules.sys_crg = zynq_clocking.SYSCRG(
|
self.submodules.sys_crg = zynq_clocking.SYSCRG(
|
||||||
self.platform,
|
self.platform,
|
||||||
self.ps7,
|
self.ps7,
|
||||||
txout_buf,
|
txout_buf,
|
||||||
clk_sw=self.gt_drtio.stable_clkin.storage,
|
clk_sw=gtx0.tx_init.done)
|
||||||
clk_sw_status=gtx0.tx_init.done,
|
|
||||||
ext_async_rst=ext_async_rst)
|
|
||||||
self.csr_devices.append("sys_crg")
|
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.crg.cd_sys = self.sys_crg.cd_sys
|
||||||
|
@ -267,28 +250,8 @@ class GenericMaster(SoCCore):
|
||||||
self.bootstrap.cd_bootstrap.clk, self.sys_crg.cd_sys.clk)
|
self.bootstrap.cd_bootstrap.clk, self.sys_crg.cd_sys.clk)
|
||||||
fix_serdes_timing_path(platform)
|
fix_serdes_timing_path(platform)
|
||||||
|
|
||||||
self.comb += ext_async_rst.eq(self.sys_crg.clk_sw_fsm.o_clk_sw & ~gtx0.tx_init.done)
|
self.config["HAS_SI5324"] = None
|
||||||
self.specials += MultiReg(self.sys_crg.clk_sw_fsm.o_clk_sw & self.sys_crg.mmcm_locked, self.gt_drtio.clk_path_ready, odomain="bootstrap")
|
self.config["SI5324_SOFT_RESET"] = None
|
||||||
|
|
||||||
if with_wrpll:
|
|
||||||
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)
|
|
||||||
self.submodules.wrpll_refclk = wrpll.FrequencyMultiplier(platform.request("sma_clkin"))
|
|
||||||
self.submodules.wrpll = wrpll.WRPLL(
|
|
||||||
platform=self.platform,
|
|
||||||
cd_ref=self.wrpll_refclk.cd_ref,
|
|
||||||
main_clk_se=clk_synth_se)
|
|
||||||
self.csr_devices.append("wrpll_refclk")
|
|
||||||
self.csr_devices.append("wrpll")
|
|
||||||
self.comb += self.ps7.core.core0.nfiq.eq(self.wrpll.ev.irq)
|
|
||||||
self.config["HAS_SI549"] = None
|
|
||||||
self.config["WRPLL_REF_CLK"] = "SMA_CLKIN"
|
|
||||||
else:
|
|
||||||
self.submodules += SMAClkinForward(self.platform)
|
|
||||||
self.config["HAS_SI5324"] = None
|
|
||||||
self.config["SI5324_SOFT_RESET"] = None
|
|
||||||
|
|
||||||
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"])
|
||||||
|
@ -430,7 +393,6 @@ 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"]
|
clk_freq = description["rtio_frequency"]
|
||||||
with_wrpll = description["enable_wrpll"]
|
|
||||||
|
|
||||||
self.acpki = acpki
|
self.acpki = acpki
|
||||||
|
|
||||||
|
@ -457,16 +419,12 @@ class GenericSatellite(SoCCore):
|
||||||
gtx0 = self.gt_drtio.gtxs[0]
|
gtx0 = self.gt_drtio.gtxs[0]
|
||||||
self.specials += Instance("BUFG", i_I=gtx0.txoutclk, o_O=txout_buf)
|
self.specials += Instance("BUFG", i_I=gtx0.txoutclk, o_O=txout_buf)
|
||||||
|
|
||||||
ext_async_rst = Signal()
|
|
||||||
|
|
||||||
self.submodules.bootstrap = GTPBootstrapClock(self.platform, clk_freq)
|
self.submodules.bootstrap = GTPBootstrapClock(self.platform, clk_freq)
|
||||||
self.submodules.sys_crg = zynq_clocking.SYSCRG(
|
self.submodules.sys_crg = zynq_clocking.SYSCRG(
|
||||||
self.platform,
|
self.platform,
|
||||||
self.ps7,
|
self.ps7,
|
||||||
txout_buf,
|
txout_buf,
|
||||||
clk_sw=self.gt_drtio.stable_clkin.storage,
|
clk_sw=gtx0.tx_init.done)
|
||||||
clk_sw_status=gtx0.tx_init.done,
|
|
||||||
ext_async_rst=ext_async_rst)
|
|
||||||
platform.add_false_path_constraints(
|
platform.add_false_path_constraints(
|
||||||
self.bootstrap.cd_bootstrap.clk, self.sys_crg.cd_sys.clk)
|
self.bootstrap.cd_bootstrap.clk, self.sys_crg.cd_sys.clk)
|
||||||
self.csr_devices.append("sys_crg")
|
self.csr_devices.append("sys_crg")
|
||||||
|
@ -475,9 +433,6 @@ class GenericSatellite(SoCCore):
|
||||||
|
|
||||||
fix_serdes_timing_path(platform)
|
fix_serdes_timing_path(platform)
|
||||||
|
|
||||||
self.comb += ext_async_rst.eq(self.sys_crg.clk_sw_fsm.o_clk_sw & ~gtx0.tx_init.done)
|
|
||||||
self.specials += MultiReg(self.sys_crg.clk_sw_fsm.o_clk_sw & self.sys_crg.mmcm_locked, self.gt_drtio.clk_path_ready, odomain="bootstrap")
|
|
||||||
|
|
||||||
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:
|
||||||
|
@ -560,10 +515,7 @@ class GenericSatellite(SoCCore):
|
||||||
self.submodules.local_io = SyncRTIO(
|
self.submodules.local_io = SyncRTIO(
|
||||||
self.rtio_tsc, self.rtio_channels, lane_count=description["sed_lanes"]
|
self.rtio_tsc, self.rtio_channels, lane_count=description["sed_lanes"]
|
||||||
)
|
)
|
||||||
self.comb += [
|
self.comb += self.drtiosat.async_errors.eq(self.local_io.async_errors)
|
||||||
self.drtiosat.async_errors.eq(self.local_io.async_errors),
|
|
||||||
self.local_io.sed_spread_enable.eq(self.drtiosat.sed_spread_enable.storage)
|
|
||||||
]
|
|
||||||
|
|
||||||
self.submodules.cri_con = rtio.CRIInterconnectShared(
|
self.submodules.cri_con = rtio.CRIInterconnectShared(
|
||||||
[self.drtiosat.cri, self.rtio_dma.cri, self.rtio.cri],
|
[self.drtiosat.cri, self.rtio_dma.cri, self.rtio.cri],
|
||||||
|
@ -585,30 +537,14 @@ class GenericSatellite(SoCCore):
|
||||||
self.config["RTIO_FREQUENCY"] = str(clk_freq/1e6)
|
self.config["RTIO_FREQUENCY"] = str(clk_freq/1e6)
|
||||||
self.config["CLOCK_FREQUENCY"] = int(clk_freq)
|
self.config["CLOCK_FREQUENCY"] = int(clk_freq)
|
||||||
|
|
||||||
if with_wrpll:
|
self.submodules.siphaser = SiPhaser7Series(
|
||||||
clk_synth = platform.request("cdr_clk_clean_fabric")
|
si5324_clkin=platform.request("cdr_clk"),
|
||||||
clk_synth_se = Signal()
|
rx_synchronizer=self.rx_synchronizer,
|
||||||
platform.add_period_constraint(clk_synth.p, 8.0)
|
ultrascale=False,
|
||||||
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)
|
rtio_clk_freq=self.gt_drtio.rtio_clk_freq)
|
||||||
self.submodules.wrpll = wrpll.WRPLL(
|
self.csr_devices.append("siphaser")
|
||||||
platform=self.platform,
|
self.config["HAS_SI5324"] = None
|
||||||
cd_ref=self.gt_drtio.cd_rtio_rx0,
|
self.config["SI5324_SOFT_RESET"] = None
|
||||||
main_clk_se=clk_synth_se)
|
|
||||||
self.submodules.wrpll_skewtester = wrpll.SkewTester(self.rx_synchronizer)
|
|
||||||
self.csr_devices.append("wrpll_skewtester")
|
|
||||||
self.csr_devices.append("wrpll")
|
|
||||||
self.comb += self.ps7.core.core0.nfiq.eq(self.wrpll.ev.irq)
|
|
||||||
self.config["HAS_SI549"] = None
|
|
||||||
self.config["WRPLL_REF_CLK"] = "GT_CDR"
|
|
||||||
else:
|
|
||||||
self.submodules.siphaser = SiPhaser7Series(
|
|
||||||
si5324_clkin=platform.request("cdr_clk"),
|
|
||||||
rx_synchronizer=self.rx_synchronizer,
|
|
||||||
ultrascale=False,
|
|
||||||
rtio_clk_freq=self.gt_drtio.rtio_clk_freq)
|
|
||||||
self.csr_devices.append("siphaser")
|
|
||||||
self.config["HAS_SI5324"] = None
|
|
||||||
self.config["SI5324_SOFT_RESET"] = None
|
|
||||||
|
|
||||||
gtx0 = self.gt_drtio.gtxs[0]
|
gtx0 = self.gt_drtio.gtxs[0]
|
||||||
platform.add_false_path_constraints(
|
platform.add_false_path_constraints(
|
||||||
|
|
|
@ -226,7 +226,6 @@ class _MasterBase(SoCCore):
|
||||||
self.csr_devices.append("gt_drtio")
|
self.csr_devices.append("gt_drtio")
|
||||||
|
|
||||||
self.submodules.rtio_tsc = rtio.TSC(glbl_fine_ts_width=3)
|
self.submodules.rtio_tsc = rtio.TSC(glbl_fine_ts_width=3)
|
||||||
ext_async_rst = Signal()
|
|
||||||
txout_buf = Signal()
|
txout_buf = Signal()
|
||||||
gtx0 = self.gt_drtio.gtxs[0]
|
gtx0 = self.gt_drtio.gtxs[0]
|
||||||
self.specials += Instance("BUFG", i_I=gtx0.txoutclk, o_O=txout_buf)
|
self.specials += Instance("BUFG", i_I=gtx0.txoutclk, o_O=txout_buf)
|
||||||
|
@ -235,17 +234,12 @@ class _MasterBase(SoCCore):
|
||||||
self.platform,
|
self.platform,
|
||||||
self.ps7,
|
self.ps7,
|
||||||
txout_buf,
|
txout_buf,
|
||||||
clk_sw=self.gt_drtio.stable_clkin.storage,
|
clk_sw=gtx0.tx_init.done,
|
||||||
clk_sw_status=gtx0.tx_init.done,
|
|
||||||
ext_async_rst=ext_async_rst,
|
|
||||||
freq=clk_freq)
|
freq=clk_freq)
|
||||||
platform.add_false_path_constraints(
|
platform.add_false_path_constraints(
|
||||||
self.bootstrap.cd_bootstrap.clk, self.sys_crg.cd_sys.clk)
|
self.bootstrap.cd_bootstrap.clk, self.sys_crg.cd_sys.clk)
|
||||||
self.csr_devices.append("sys_crg")
|
self.csr_devices.append("sys_crg")
|
||||||
|
|
||||||
self.comb += ext_async_rst.eq(self.sys_crg.clk_sw_fsm.o_clk_sw & ~gtx0.tx_init.done)
|
|
||||||
self.specials += MultiReg(self.sys_crg.clk_sw_fsm.o_clk_sw & self.sys_crg.mmcm_locked, self.gt_drtio.clk_path_ready, odomain="bootstrap")
|
|
||||||
|
|
||||||
drtio_csr_group = []
|
drtio_csr_group = []
|
||||||
drtioaux_csr_group = []
|
drtioaux_csr_group = []
|
||||||
drtioaux_memory_group = []
|
drtioaux_memory_group = []
|
||||||
|
@ -367,7 +361,6 @@ class _SatelliteBase(SoCCore):
|
||||||
clk_freq=clk_freq)
|
clk_freq=clk_freq)
|
||||||
self.csr_devices.append("gt_drtio")
|
self.csr_devices.append("gt_drtio")
|
||||||
|
|
||||||
ext_async_rst = Signal()
|
|
||||||
txout_buf = Signal()
|
txout_buf = Signal()
|
||||||
txout_buf.attr.add("keep")
|
txout_buf.attr.add("keep")
|
||||||
gtx0 = self.gt_drtio.gtxs[0]
|
gtx0 = self.gt_drtio.gtxs[0]
|
||||||
|
@ -380,17 +373,12 @@ class _SatelliteBase(SoCCore):
|
||||||
self.platform,
|
self.platform,
|
||||||
self.ps7,
|
self.ps7,
|
||||||
txout_buf,
|
txout_buf,
|
||||||
clk_sw=self.gt_drtio.stable_clkin.storage,
|
clk_sw=gtx0.tx_init.done,
|
||||||
clk_sw_status=gtx0.tx_init.done,
|
|
||||||
ext_async_rst=ext_async_rst,
|
|
||||||
freq=clk_freq)
|
freq=clk_freq)
|
||||||
platform.add_false_path_constraints(
|
platform.add_false_path_constraints(
|
||||||
self.bootstrap.cd_bootstrap.clk, self.sys_crg.cd_sys.clk)
|
self.bootstrap.cd_bootstrap.clk, self.sys_crg.cd_sys.clk)
|
||||||
self.csr_devices.append("sys_crg")
|
self.csr_devices.append("sys_crg")
|
||||||
|
|
||||||
self.comb += ext_async_rst.eq(self.sys_crg.clk_sw_fsm.o_clk_sw & ~gtx0.tx_init.done)
|
|
||||||
self.specials += MultiReg(self.sys_crg.clk_sw_fsm.o_clk_sw & self.sys_crg.mmcm_locked, self.gt_drtio.clk_path_ready, odomain="bootstrap")
|
|
||||||
|
|
||||||
drtioaux_csr_group = []
|
drtioaux_csr_group = []
|
||||||
drtioaux_memory_group = []
|
drtioaux_memory_group = []
|
||||||
drtiorep_csr_group = []
|
drtiorep_csr_group = []
|
||||||
|
@ -487,10 +475,6 @@ class _SatelliteBase(SoCCore):
|
||||||
self.csr_devices.append("rtio_dma")
|
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.comb += [
|
|
||||||
self.drtiosat.async_errors.eq(self.local_io.async_errors),
|
|
||||||
self.local_io.sed_spread_enable.eq(self.drtiosat.sed_spread_enable.storage)
|
|
||||||
]
|
|
||||||
self.submodules.cri_con = rtio.CRIInterconnectShared(
|
self.submodules.cri_con = rtio.CRIInterconnectShared(
|
||||||
[self.drtiosat.cri, self.rtio_dma.cri, self.rtio.cri],
|
[self.drtiosat.cri, self.rtio_dma.cri, self.rtio.cri],
|
||||||
[self.local_io.cri] + self.drtio_cri,
|
[self.local_io.cri] + self.drtio_cri,
|
||||||
|
|
|
@ -65,7 +65,7 @@ class ClockSwitchFSM(Module):
|
||||||
|
|
||||||
|
|
||||||
class SYSCRG(Module, AutoCSR):
|
class SYSCRG(Module, AutoCSR):
|
||||||
def __init__(self, platform, ps7, main_clk, clk_sw=None, clk_sw_status=None, freq=125e6, ext_async_rst=None, ):
|
def __init__(self, platform, ps7, main_clk, clk_sw=None, freq=125e6):
|
||||||
# assumes bootstrap clock is same freq as main and sys output
|
# assumes bootstrap clock is same freq as main and sys output
|
||||||
self.clock_domains.cd_sys = ClockDomain()
|
self.clock_domains.cd_sys = ClockDomain()
|
||||||
self.clock_domains.cd_sys4x = ClockDomain(reset_less=True)
|
self.clock_domains.cd_sys4x = ClockDomain(reset_less=True)
|
||||||
|
@ -88,7 +88,7 @@ class SYSCRG(Module, AutoCSR):
|
||||||
else:
|
else:
|
||||||
self.comb += self.clk_sw_fsm.i_clk_sw.eq(clk_sw)
|
self.comb += self.clk_sw_fsm.i_clk_sw.eq(clk_sw)
|
||||||
|
|
||||||
self.mmcm_locked = Signal()
|
mmcm_locked = Signal()
|
||||||
mmcm_sys = Signal()
|
mmcm_sys = Signal()
|
||||||
mmcm_sys4x = Signal()
|
mmcm_sys4x = Signal()
|
||||||
mmcm_sys5x = Signal()
|
mmcm_sys5x = Signal()
|
||||||
|
@ -96,7 +96,7 @@ class SYSCRG(Module, AutoCSR):
|
||||||
mmcm_fb_clk = Signal()
|
mmcm_fb_clk = Signal()
|
||||||
self.specials += [
|
self.specials += [
|
||||||
Instance("MMCME2_ADV",
|
Instance("MMCME2_ADV",
|
||||||
p_STARTUP_WAIT="FALSE", o_LOCKED=self.mmcm_locked,
|
p_STARTUP_WAIT="FALSE", o_LOCKED=mmcm_locked,
|
||||||
p_BANDWIDTH="HIGH",
|
p_BANDWIDTH="HIGH",
|
||||||
p_REF_JITTER1=0.001,
|
p_REF_JITTER1=0.001,
|
||||||
p_CLKIN1_PERIOD=period, i_CLKIN1=main_clk,
|
p_CLKIN1_PERIOD=period, i_CLKIN1=main_clk,
|
||||||
|
@ -125,19 +125,10 @@ class SYSCRG(Module, AutoCSR):
|
||||||
Instance("BUFG", i_I=mmcm_sys, o_O=self.cd_sys.clk),
|
Instance("BUFG", i_I=mmcm_sys, o_O=self.cd_sys.clk),
|
||||||
Instance("BUFG", i_I=mmcm_sys4x, o_O=self.cd_sys4x.clk),
|
Instance("BUFG", i_I=mmcm_sys4x, o_O=self.cd_sys4x.clk),
|
||||||
Instance("BUFG", i_I=mmcm_clk208, o_O=self.cd_clk200.clk),
|
Instance("BUFG", i_I=mmcm_clk208, o_O=self.cd_clk200.clk),
|
||||||
|
AsyncResetSynchronizer(self.cd_sys, ~mmcm_locked),
|
||||||
|
AsyncResetSynchronizer(self.cd_clk200, ~mmcm_locked),
|
||||||
]
|
]
|
||||||
|
|
||||||
if ext_async_rst is not None:
|
|
||||||
self.specials += [
|
|
||||||
AsyncResetSynchronizer(self.cd_sys, ~self.mmcm_locked | ext_async_rst),
|
|
||||||
AsyncResetSynchronizer(self.cd_clk200, ~self.mmcm_locked | ext_async_rst),
|
|
||||||
]
|
|
||||||
else:
|
|
||||||
self.specials += [
|
|
||||||
AsyncResetSynchronizer(self.cd_sys, ~self.mmcm_locked),
|
|
||||||
AsyncResetSynchronizer(self.cd_clk200, ~self.mmcm_locked),
|
|
||||||
]
|
|
||||||
|
|
||||||
reset_counter = Signal(4, reset=15)
|
reset_counter = Signal(4, reset=15)
|
||||||
ic_reset = Signal(reset=1)
|
ic_reset = Signal(reset=1)
|
||||||
self.sync.clk200 += \
|
self.sync.clk200 += \
|
||||||
|
@ -148,7 +139,4 @@ class SYSCRG(Module, AutoCSR):
|
||||||
)
|
)
|
||||||
self.specials += Instance("IDELAYCTRL", i_REFCLK=ClockSignal("clk200"), i_RST=ic_reset)
|
self.specials += Instance("IDELAYCTRL", i_REFCLK=ClockSignal("clk200"), i_RST=ic_reset)
|
||||||
|
|
||||||
if clk_sw_status is None:
|
self.comb += self.current_clock.status.eq(self.clk_sw_fsm.o_clk_sw)
|
||||||
self.comb += self.current_clock.status.eq(self.clk_sw_fsm.o_clk_sw)
|
|
||||||
else:
|
|
||||||
self.comb += self.current_clock.status.eq(clk_sw_status)
|
|
||||||
|
|
|
@ -10,7 +10,6 @@ name = "libboard_artiq"
|
||||||
[features]
|
[features]
|
||||||
target_zc706 = ["libboard_zynq/target_zc706", "libconfig/target_zc706"]
|
target_zc706 = ["libboard_zynq/target_zc706", "libconfig/target_zc706"]
|
||||||
target_kasli_soc = ["libboard_zynq/target_kasli_soc", "libconfig/target_kasli_soc"]
|
target_kasli_soc = ["libboard_zynq/target_kasli_soc", "libconfig/target_kasli_soc"]
|
||||||
calibrate_wrpll_skew = []
|
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
build_zynq = { path = "../libbuild_zynq" }
|
build_zynq = { path = "../libbuild_zynq" }
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
use core::slice;
|
|
||||||
|
|
||||||
use core_io::{Error as IoError, ErrorKind as IoErrorKind};
|
use core_io::{Error as IoError, ErrorKind as IoErrorKind};
|
||||||
use crc;
|
use crc;
|
||||||
use io::{proto::{ProtoRead, ProtoWrite},
|
use io::{proto::{ProtoRead, ProtoWrite},
|
||||||
Cursor};
|
Cursor};
|
||||||
use libboard_zynq::{time::Milliseconds, timer::GlobalTimer};
|
use libboard_zynq::{time::Milliseconds, timer::GlobalTimer};
|
||||||
|
use libcortex_a9::asm::dmb;
|
||||||
|
|
||||||
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};
|
use crate::{drtioaux_proto::Error as ProtocolError, mem::mem::DRTIOAUX_MEM, pl::csr::DRTIOAUX};
|
||||||
|
@ -57,14 +56,30 @@ pub fn has_rx_error(linkno: u8) -> bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn copy_work_buffer(src: *mut u32, dst: *mut u32, len: isize) {
|
||||||
|
// AXI writes must be 4-byte aligned (drtio proto doesn't care for that),
|
||||||
|
// and AXI burst reads/writes are not implemented yet in gateware
|
||||||
|
// thus the need for a work buffer for transmitting and copying it over
|
||||||
|
unsafe {
|
||||||
|
for i in 0..(len / 4) {
|
||||||
|
*dst.offset(i) = *src.offset(i);
|
||||||
|
//data memory barrier to prevent bursts
|
||||||
|
dmb();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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 {
|
||||||
let read_ptr = (DRTIOAUX[linkidx].aux_read_pointer_read)() as usize;
|
let ptr = (DRTIOAUX_MEM[linkidx].base + DRTIOAUX_MEM[linkidx].size / 2) as *mut u32;
|
||||||
let ptr = (DRTIOAUX_MEM[linkidx].base + DRTIOAUX_MEM[linkidx].size / 2 + read_ptr * 0x400) as *mut u32;
|
let len = (DRTIOAUX[linkidx].aux_rx_length_read)() as usize;
|
||||||
let result = f(slice::from_raw_parts(ptr as *mut u8, 0x400 as usize));
|
// work buffer to accomodate axi burst reads
|
||||||
|
let mut buf: [u8; 1024] = [0; 1024];
|
||||||
|
copy_work_buffer(ptr, buf.as_mut_ptr() as *mut u32, len as isize);
|
||||||
|
let result = f(&buf[0..len]);
|
||||||
(DRTIOAUX[linkidx].aux_rx_present_write)(1);
|
(DRTIOAUX[linkidx].aux_rx_present_write)(1);
|
||||||
Ok(Some(result?))
|
Ok(Some(result?))
|
||||||
} else {
|
} else {
|
||||||
|
@ -85,15 +100,15 @@ pub fn recv(linkno: u8) -> Result<Option<Packet>, Error> {
|
||||||
|
|
||||||
let mut reader = Cursor::new(buffer);
|
let mut reader = Cursor::new(buffer);
|
||||||
|
|
||||||
let packet = Packet::read_from(&mut reader)?;
|
let checksum_at = buffer.len() - 4;
|
||||||
let padding = (12 - (reader.position() % 8)) % 8;
|
|
||||||
let checksum_at = reader.position() + padding;
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
Ok(packet)
|
reader.set_position(0);
|
||||||
|
|
||||||
|
Ok(Packet::read_from(&mut reader)?)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,7 +130,11 @@ where F: FnOnce(&mut [u8]) -> Result<usize, Error> {
|
||||||
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 = f(slice::from_raw_parts_mut(ptr as *mut u8, 0x400 as usize))?;
|
let len = DRTIOAUX_MEM[linkno].size / 2;
|
||||||
|
// work buffer, works with unaligned mem access
|
||||||
|
let mut buf: [u8; 1024] = [0; 1024];
|
||||||
|
let len = f(&mut buf[0..len])?;
|
||||||
|
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);
|
||||||
(DRTIOAUX[linkno].aux_tx_write)(1);
|
(DRTIOAUX[linkno].aux_tx_write)(1);
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
use core::slice;
|
|
||||||
|
|
||||||
use core_io::{Error as IoError, ErrorKind as IoErrorKind};
|
use core_io::{Error as IoError, ErrorKind as IoErrorKind};
|
||||||
use crc;
|
use crc;
|
||||||
use io::{proto::{ProtoRead, ProtoWrite},
|
use io::{proto::{ProtoRead, ProtoWrite},
|
||||||
|
@ -10,7 +8,7 @@ use nb;
|
||||||
use void::Void;
|
use void::Void;
|
||||||
|
|
||||||
pub use crate::drtioaux_proto::Packet;
|
pub use crate::drtioaux_proto::Packet;
|
||||||
use crate::{drtioaux::{has_rx_error, Error},
|
use crate::{drtioaux::{copy_work_buffer, has_rx_error, Error},
|
||||||
mem::mem::DRTIOAUX_MEM,
|
mem::mem::DRTIOAUX_MEM,
|
||||||
pl::csr::DRTIOAUX};
|
pl::csr::DRTIOAUX};
|
||||||
|
|
||||||
|
@ -40,9 +38,12 @@ 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 {
|
||||||
let read_ptr = (DRTIOAUX[linkidx].aux_read_pointer_read)() as usize;
|
let ptr = (DRTIOAUX_MEM[linkidx].base + DRTIOAUX_MEM[linkidx].size / 2) as *mut u32;
|
||||||
let ptr = (DRTIOAUX_MEM[linkidx].base + DRTIOAUX_MEM[linkidx].size / 2 + read_ptr * 0x400) as *mut u32;
|
let len = (DRTIOAUX[linkidx].aux_rx_length_read)() as usize;
|
||||||
let result = f(slice::from_raw_parts(ptr as *mut u8, 0x400 as usize));
|
// work buffer to accomodate axi burst reads
|
||||||
|
let mut buf: [u8; 1024] = [0; 1024];
|
||||||
|
copy_work_buffer(ptr, buf.as_mut_ptr() as *mut u32, len as isize);
|
||||||
|
let result = f(&buf[0..len]);
|
||||||
(DRTIOAUX[linkidx].aux_rx_present_write)(1);
|
(DRTIOAUX[linkidx].aux_rx_present_write)(1);
|
||||||
Ok(Some(result?))
|
Ok(Some(result?))
|
||||||
} else {
|
} else {
|
||||||
|
@ -63,15 +64,15 @@ pub async fn recv(linkno: u8) -> Result<Option<Packet>, Error> {
|
||||||
|
|
||||||
let mut reader = Cursor::new(buffer);
|
let mut reader = Cursor::new(buffer);
|
||||||
|
|
||||||
let packet = Packet::read_from(&mut reader)?;
|
let checksum_at = buffer.len() - 4;
|
||||||
let padding = (12 - (reader.position() % 8)) % 8;
|
|
||||||
let checksum_at = reader.position() + padding;
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
Ok(packet)
|
reader.set_position(0);
|
||||||
|
|
||||||
|
Ok(Packet::read_from(&mut reader)?)
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
@ -102,7 +103,11 @@ where F: FnOnce(&mut [u8]) -> Result<usize, Error> {
|
||||||
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 = f(slice::from_raw_parts_mut(ptr as *mut u8, 0x400 as usize))?;
|
let len = DRTIOAUX_MEM[linkno].size / 2;
|
||||||
|
// work buffer, works with unaligned mem access
|
||||||
|
let mut buf: [u8; 1024] = [0; 1024];
|
||||||
|
let len = f(&mut buf[0..len])?;
|
||||||
|
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);
|
||||||
(DRTIOAUX[linkno].aux_tx_write)(1);
|
(DRTIOAUX[linkno].aux_tx_write)(1);
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -1,13 +1,11 @@
|
||||||
use core_io::{Error as IoError, Read, Write};
|
use core_io::{Error as IoError, Read, Write};
|
||||||
use io::proto::{ProtoRead, ProtoWrite};
|
use io::proto::{ProtoRead, ProtoWrite};
|
||||||
|
|
||||||
const MAX_PACKET: usize = 1024;
|
|
||||||
|
|
||||||
// maximum size of arbitrary payloads
|
// maximum size of arbitrary payloads
|
||||||
// used by satellite -> master analyzer, subkernel exceptions
|
// used by satellite -> master analyzer, subkernel exceptions
|
||||||
pub const SAT_PAYLOAD_MAX_SIZE: usize = /*max size*/MAX_PACKET - /*CRC*/4 - /*packet ID*/1 - /*last*/1 - /*length*/2;
|
pub const SAT_PAYLOAD_MAX_SIZE: usize = /*max size*/512 - /*CRC*/4 - /*packet ID*/1 - /*last*/1 - /*length*/2;
|
||||||
// used by DDMA, subkernel program data (need to provide extra ID and destination)
|
// used by DDMA, subkernel program data (need to provide extra ID and destination)
|
||||||
pub const MASTER_PAYLOAD_MAX_SIZE: usize = SAT_PAYLOAD_MAX_SIZE - /*source*/1 - /*destination*/1 - /*ID*/4;
|
pub const MASTER_PAYLOAD_MAX_SIZE: usize = SAT_PAYLOAD_MAX_SIZE - /*destination*/1 - /*ID*/4;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
|
@ -21,46 +19,6 @@ impl From<IoError> for Error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Clone, Copy, Debug)]
|
|
||||||
#[repr(u8)]
|
|
||||||
pub enum PayloadStatus {
|
|
||||||
Middle = 0,
|
|
||||||
First = 1,
|
|
||||||
Last = 2,
|
|
||||||
FirstAndLast = 3,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<u8> for PayloadStatus {
|
|
||||||
fn from(value: u8) -> PayloadStatus {
|
|
||||||
match value {
|
|
||||||
0 => PayloadStatus::Middle,
|
|
||||||
1 => PayloadStatus::First,
|
|
||||||
2 => PayloadStatus::Last,
|
|
||||||
3 => PayloadStatus::FirstAndLast,
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PayloadStatus {
|
|
||||||
pub fn is_first(self) -> bool {
|
|
||||||
self == PayloadStatus::First || self == PayloadStatus::FirstAndLast
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_last(self) -> bool {
|
|
||||||
self == PayloadStatus::Last || self == PayloadStatus::FirstAndLast
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn from_status(first: bool, last: bool) -> PayloadStatus {
|
|
||||||
match (first, last) {
|
|
||||||
(true, true) => PayloadStatus::FirstAndLast,
|
|
||||||
(true, false) => PayloadStatus::First,
|
|
||||||
(false, true) => PayloadStatus::Last,
|
|
||||||
(false, false) => PayloadStatus::Middle,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(PartialEq, Debug)]
|
#[derive(PartialEq, Debug)]
|
||||||
pub enum Packet {
|
pub enum Packet {
|
||||||
EchoRequest,
|
EchoRequest,
|
||||||
|
@ -199,40 +157,31 @@ pub enum Packet {
|
||||||
},
|
},
|
||||||
|
|
||||||
DmaAddTraceRequest {
|
DmaAddTraceRequest {
|
||||||
source: u8,
|
|
||||||
destination: u8,
|
destination: u8,
|
||||||
id: u32,
|
id: u32,
|
||||||
status: PayloadStatus,
|
last: bool,
|
||||||
length: u16,
|
length: u16,
|
||||||
trace: [u8; MASTER_PAYLOAD_MAX_SIZE],
|
trace: [u8; MASTER_PAYLOAD_MAX_SIZE],
|
||||||
},
|
},
|
||||||
DmaAddTraceReply {
|
DmaAddTraceReply {
|
||||||
source: u8,
|
|
||||||
destination: u8,
|
|
||||||
id: u32,
|
|
||||||
succeeded: bool,
|
succeeded: bool,
|
||||||
},
|
},
|
||||||
DmaRemoveTraceRequest {
|
DmaRemoveTraceRequest {
|
||||||
source: u8,
|
|
||||||
destination: u8,
|
destination: u8,
|
||||||
id: u32,
|
id: u32,
|
||||||
},
|
},
|
||||||
DmaRemoveTraceReply {
|
DmaRemoveTraceReply {
|
||||||
destination: u8,
|
|
||||||
succeeded: bool,
|
succeeded: bool,
|
||||||
},
|
},
|
||||||
DmaPlaybackRequest {
|
DmaPlaybackRequest {
|
||||||
source: u8,
|
|
||||||
destination: u8,
|
destination: u8,
|
||||||
id: u32,
|
id: u32,
|
||||||
timestamp: u64,
|
timestamp: u64,
|
||||||
},
|
},
|
||||||
DmaPlaybackReply {
|
DmaPlaybackReply {
|
||||||
destination: u8,
|
|
||||||
succeeded: bool,
|
succeeded: bool,
|
||||||
},
|
},
|
||||||
DmaPlaybackStatus {
|
DmaPlaybackStatus {
|
||||||
source: u8,
|
|
||||||
destination: u8,
|
destination: u8,
|
||||||
id: u32,
|
id: u32,
|
||||||
error: u8,
|
error: u8,
|
||||||
|
@ -243,7 +192,7 @@ pub enum Packet {
|
||||||
SubkernelAddDataRequest {
|
SubkernelAddDataRequest {
|
||||||
destination: u8,
|
destination: u8,
|
||||||
id: u32,
|
id: u32,
|
||||||
status: PayloadStatus,
|
last: bool,
|
||||||
length: u16,
|
length: u16,
|
||||||
data: [u8; MASTER_PAYLOAD_MAX_SIZE],
|
data: [u8; MASTER_PAYLOAD_MAX_SIZE],
|
||||||
},
|
},
|
||||||
|
@ -251,36 +200,35 @@ pub enum Packet {
|
||||||
succeeded: bool,
|
succeeded: bool,
|
||||||
},
|
},
|
||||||
SubkernelLoadRunRequest {
|
SubkernelLoadRunRequest {
|
||||||
source: u8,
|
|
||||||
destination: u8,
|
destination: u8,
|
||||||
id: u32,
|
id: u32,
|
||||||
run: bool,
|
run: bool,
|
||||||
},
|
},
|
||||||
SubkernelLoadRunReply {
|
SubkernelLoadRunReply {
|
||||||
|
succeeded: bool,
|
||||||
|
},
|
||||||
|
SubkernelStopRequest {
|
||||||
destination: u8,
|
destination: u8,
|
||||||
|
},
|
||||||
|
SubkernelStopReply {
|
||||||
succeeded: bool,
|
succeeded: bool,
|
||||||
},
|
},
|
||||||
SubkernelFinished {
|
SubkernelFinished {
|
||||||
destination: u8,
|
|
||||||
id: u32,
|
id: u32,
|
||||||
with_exception: bool,
|
with_exception: bool,
|
||||||
exception_src: u8,
|
|
||||||
},
|
},
|
||||||
SubkernelExceptionRequest {
|
SubkernelExceptionRequest {
|
||||||
source: u8,
|
|
||||||
destination: u8,
|
destination: u8,
|
||||||
},
|
},
|
||||||
SubkernelException {
|
SubkernelException {
|
||||||
destination: u8,
|
|
||||||
last: bool,
|
last: bool,
|
||||||
length: u16,
|
length: u16,
|
||||||
data: [u8; MASTER_PAYLOAD_MAX_SIZE],
|
data: [u8; SAT_PAYLOAD_MAX_SIZE],
|
||||||
},
|
},
|
||||||
SubkernelMessage {
|
SubkernelMessage {
|
||||||
source: u8,
|
|
||||||
destination: u8,
|
destination: u8,
|
||||||
id: u32,
|
id: u32,
|
||||||
status: PayloadStatus,
|
last: bool,
|
||||||
length: u16,
|
length: u16,
|
||||||
data: [u8; MASTER_PAYLOAD_MAX_SIZE],
|
data: [u8; MASTER_PAYLOAD_MAX_SIZE],
|
||||||
},
|
},
|
||||||
|
@ -441,49 +389,39 @@ impl Packet {
|
||||||
}
|
}
|
||||||
|
|
||||||
0xb0 => {
|
0xb0 => {
|
||||||
let source = reader.read_u8()?;
|
|
||||||
let destination = reader.read_u8()?;
|
let destination = reader.read_u8()?;
|
||||||
let id = reader.read_u32()?;
|
let id = reader.read_u32()?;
|
||||||
let status = reader.read_u8()?;
|
let last = reader.read_bool()?;
|
||||||
let length = reader.read_u16()?;
|
let length = reader.read_u16()?;
|
||||||
let mut trace: [u8; MASTER_PAYLOAD_MAX_SIZE] = [0; MASTER_PAYLOAD_MAX_SIZE];
|
let mut trace: [u8; MASTER_PAYLOAD_MAX_SIZE] = [0; MASTER_PAYLOAD_MAX_SIZE];
|
||||||
reader.read_exact(&mut trace[0..length as usize])?;
|
reader.read_exact(&mut trace[0..length as usize])?;
|
||||||
Packet::DmaAddTraceRequest {
|
Packet::DmaAddTraceRequest {
|
||||||
source: source,
|
|
||||||
destination: destination,
|
destination: destination,
|
||||||
id: id,
|
id: id,
|
||||||
status: PayloadStatus::from(status),
|
last: last,
|
||||||
length: length as u16,
|
length: length as u16,
|
||||||
trace: trace,
|
trace: trace,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
0xb1 => Packet::DmaAddTraceReply {
|
0xb1 => Packet::DmaAddTraceReply {
|
||||||
source: reader.read_u8()?,
|
|
||||||
destination: reader.read_u8()?,
|
|
||||||
id: reader.read_u32()?,
|
|
||||||
succeeded: reader.read_bool()?,
|
succeeded: reader.read_bool()?,
|
||||||
},
|
},
|
||||||
0xb2 => Packet::DmaRemoveTraceRequest {
|
0xb2 => Packet::DmaRemoveTraceRequest {
|
||||||
source: reader.read_u8()?,
|
|
||||||
destination: reader.read_u8()?,
|
destination: reader.read_u8()?,
|
||||||
id: reader.read_u32()?,
|
id: reader.read_u32()?,
|
||||||
},
|
},
|
||||||
0xb3 => Packet::DmaRemoveTraceReply {
|
0xb3 => Packet::DmaRemoveTraceReply {
|
||||||
destination: reader.read_u8()?,
|
|
||||||
succeeded: reader.read_bool()?,
|
succeeded: reader.read_bool()?,
|
||||||
},
|
},
|
||||||
0xb4 => Packet::DmaPlaybackRequest {
|
0xb4 => Packet::DmaPlaybackRequest {
|
||||||
source: reader.read_u8()?,
|
|
||||||
destination: reader.read_u8()?,
|
destination: reader.read_u8()?,
|
||||||
id: reader.read_u32()?,
|
id: reader.read_u32()?,
|
||||||
timestamp: reader.read_u64()?,
|
timestamp: reader.read_u64()?,
|
||||||
},
|
},
|
||||||
0xb5 => Packet::DmaPlaybackReply {
|
0xb5 => Packet::DmaPlaybackReply {
|
||||||
destination: reader.read_u8()?,
|
|
||||||
succeeded: reader.read_bool()?,
|
succeeded: reader.read_bool()?,
|
||||||
},
|
},
|
||||||
0xb6 => Packet::DmaPlaybackStatus {
|
0xb6 => Packet::DmaPlaybackStatus {
|
||||||
source: reader.read_u8()?,
|
|
||||||
destination: reader.read_u8()?,
|
destination: reader.read_u8()?,
|
||||||
id: reader.read_u32()?,
|
id: reader.read_u32()?,
|
||||||
error: reader.read_u8()?,
|
error: reader.read_u8()?,
|
||||||
|
@ -494,14 +432,14 @@ impl Packet {
|
||||||
0xc0 => {
|
0xc0 => {
|
||||||
let destination = reader.read_u8()?;
|
let destination = reader.read_u8()?;
|
||||||
let id = reader.read_u32()?;
|
let id = reader.read_u32()?;
|
||||||
let status = PayloadStatus::from(reader.read_u8()?);
|
let last = reader.read_bool()?;
|
||||||
let length = reader.read_u16()?;
|
let length = reader.read_u16()?;
|
||||||
let mut data: [u8; MASTER_PAYLOAD_MAX_SIZE] = [0; MASTER_PAYLOAD_MAX_SIZE];
|
let mut data: [u8; MASTER_PAYLOAD_MAX_SIZE] = [0; MASTER_PAYLOAD_MAX_SIZE];
|
||||||
reader.read_exact(&mut data[0..length as usize])?;
|
reader.read_exact(&mut data[0..length as usize])?;
|
||||||
Packet::SubkernelAddDataRequest {
|
Packet::SubkernelAddDataRequest {
|
||||||
destination: destination,
|
destination: destination,
|
||||||
id: id,
|
id: id,
|
||||||
status: status,
|
last: last,
|
||||||
length: length as u16,
|
length: length as u16,
|
||||||
data: data,
|
data: data,
|
||||||
}
|
}
|
||||||
|
@ -510,51 +448,48 @@ impl Packet {
|
||||||
succeeded: reader.read_bool()?,
|
succeeded: reader.read_bool()?,
|
||||||
},
|
},
|
||||||
0xc4 => Packet::SubkernelLoadRunRequest {
|
0xc4 => Packet::SubkernelLoadRunRequest {
|
||||||
source: reader.read_u8()?,
|
|
||||||
destination: reader.read_u8()?,
|
destination: reader.read_u8()?,
|
||||||
id: reader.read_u32()?,
|
id: reader.read_u32()?,
|
||||||
run: reader.read_bool()?,
|
run: reader.read_bool()?,
|
||||||
},
|
},
|
||||||
0xc5 => Packet::SubkernelLoadRunReply {
|
0xc5 => Packet::SubkernelLoadRunReply {
|
||||||
|
succeeded: reader.read_bool()?,
|
||||||
|
},
|
||||||
|
0xc6 => Packet::SubkernelStopRequest {
|
||||||
destination: reader.read_u8()?,
|
destination: reader.read_u8()?,
|
||||||
|
},
|
||||||
|
0xc7 => Packet::SubkernelStopReply {
|
||||||
succeeded: reader.read_bool()?,
|
succeeded: reader.read_bool()?,
|
||||||
},
|
},
|
||||||
0xc8 => Packet::SubkernelFinished {
|
0xc8 => Packet::SubkernelFinished {
|
||||||
destination: reader.read_u8()?,
|
|
||||||
id: reader.read_u32()?,
|
id: reader.read_u32()?,
|
||||||
with_exception: reader.read_bool()?,
|
with_exception: reader.read_bool()?,
|
||||||
exception_src: reader.read_u8()?,
|
|
||||||
},
|
},
|
||||||
0xc9 => Packet::SubkernelExceptionRequest {
|
0xc9 => Packet::SubkernelExceptionRequest {
|
||||||
source: reader.read_u8()?,
|
|
||||||
destination: reader.read_u8()?,
|
destination: reader.read_u8()?,
|
||||||
},
|
},
|
||||||
0xca => {
|
0xca => {
|
||||||
let destination = reader.read_u8()?;
|
|
||||||
let last = reader.read_bool()?;
|
let last = reader.read_bool()?;
|
||||||
let length = reader.read_u16()?;
|
let length = reader.read_u16()?;
|
||||||
let mut data: [u8; MASTER_PAYLOAD_MAX_SIZE] = [0; MASTER_PAYLOAD_MAX_SIZE];
|
let mut data: [u8; SAT_PAYLOAD_MAX_SIZE] = [0; SAT_PAYLOAD_MAX_SIZE];
|
||||||
reader.read_exact(&mut data[0..length as usize])?;
|
reader.read_exact(&mut data[0..length as usize])?;
|
||||||
Packet::SubkernelException {
|
Packet::SubkernelException {
|
||||||
destination: destination,
|
|
||||||
last: last,
|
last: last,
|
||||||
length: length,
|
length: length,
|
||||||
data: data,
|
data: data,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
0xcb => {
|
0xcb => {
|
||||||
let source = reader.read_u8()?;
|
|
||||||
let destination = reader.read_u8()?;
|
let destination = reader.read_u8()?;
|
||||||
let id = reader.read_u32()?;
|
let id = reader.read_u32()?;
|
||||||
let status = reader.read_u8()?;
|
let last = reader.read_bool()?;
|
||||||
let length = reader.read_u16()?;
|
let length = reader.read_u16()?;
|
||||||
let mut data: [u8; MASTER_PAYLOAD_MAX_SIZE] = [0; MASTER_PAYLOAD_MAX_SIZE];
|
let mut data: [u8; MASTER_PAYLOAD_MAX_SIZE] = [0; MASTER_PAYLOAD_MAX_SIZE];
|
||||||
reader.read_exact(&mut data[0..length as usize])?;
|
reader.read_exact(&mut data[0..length as usize])?;
|
||||||
Packet::SubkernelMessage {
|
Packet::SubkernelMessage {
|
||||||
source: source,
|
|
||||||
destination: destination,
|
destination: destination,
|
||||||
id: id,
|
id: id,
|
||||||
status: PayloadStatus::from(status),
|
last: last,
|
||||||
length: length as u16,
|
length: length as u16,
|
||||||
data: data,
|
data: data,
|
||||||
}
|
}
|
||||||
|
@ -776,69 +711,49 @@ impl Packet {
|
||||||
}
|
}
|
||||||
|
|
||||||
Packet::DmaAddTraceRequest {
|
Packet::DmaAddTraceRequest {
|
||||||
source,
|
|
||||||
destination,
|
destination,
|
||||||
id,
|
id,
|
||||||
status,
|
last,
|
||||||
trace,
|
trace,
|
||||||
length,
|
length,
|
||||||
} => {
|
} => {
|
||||||
writer.write_u8(0xb0)?;
|
writer.write_u8(0xb0)?;
|
||||||
writer.write_u8(source)?;
|
|
||||||
writer.write_u8(destination)?;
|
writer.write_u8(destination)?;
|
||||||
writer.write_u32(id)?;
|
writer.write_u32(id)?;
|
||||||
writer.write_u8(status as u8)?;
|
writer.write_bool(last)?;
|
||||||
// trace may be broken down to fit within drtio aux memory limit
|
// trace may be broken down to fit within drtio aux memory limit
|
||||||
// will be reconstructed by satellite
|
// will be reconstructed by satellite
|
||||||
writer.write_u16(length)?;
|
writer.write_u16(length)?;
|
||||||
writer.write_all(&trace[0..length as usize])?;
|
writer.write_all(&trace[0..length as usize])?;
|
||||||
}
|
}
|
||||||
Packet::DmaAddTraceReply {
|
Packet::DmaAddTraceReply { succeeded } => {
|
||||||
source,
|
|
||||||
destination,
|
|
||||||
id,
|
|
||||||
succeeded,
|
|
||||||
} => {
|
|
||||||
writer.write_u8(0xb1)?;
|
writer.write_u8(0xb1)?;
|
||||||
writer.write_u8(source)?;
|
|
||||||
writer.write_u8(destination)?;
|
|
||||||
writer.write_u32(id)?;
|
|
||||||
writer.write_bool(succeeded)?;
|
writer.write_bool(succeeded)?;
|
||||||
}
|
}
|
||||||
Packet::DmaRemoveTraceRequest {
|
Packet::DmaRemoveTraceRequest { destination, id } => {
|
||||||
source,
|
|
||||||
destination,
|
|
||||||
id,
|
|
||||||
} => {
|
|
||||||
writer.write_u8(0xb2)?;
|
writer.write_u8(0xb2)?;
|
||||||
writer.write_u8(source)?;
|
|
||||||
writer.write_u8(destination)?;
|
writer.write_u8(destination)?;
|
||||||
writer.write_u32(id)?;
|
writer.write_u32(id)?;
|
||||||
}
|
}
|
||||||
Packet::DmaRemoveTraceReply { destination, succeeded } => {
|
Packet::DmaRemoveTraceReply { succeeded } => {
|
||||||
writer.write_u8(0xb3)?;
|
writer.write_u8(0xb3)?;
|
||||||
writer.write_u8(destination)?;
|
|
||||||
writer.write_bool(succeeded)?;
|
writer.write_bool(succeeded)?;
|
||||||
}
|
}
|
||||||
Packet::DmaPlaybackRequest {
|
Packet::DmaPlaybackRequest {
|
||||||
source,
|
|
||||||
destination,
|
destination,
|
||||||
id,
|
id,
|
||||||
timestamp,
|
timestamp,
|
||||||
} => {
|
} => {
|
||||||
writer.write_u8(0xb4)?;
|
writer.write_u8(0xb4)?;
|
||||||
writer.write_u8(source)?;
|
|
||||||
writer.write_u8(destination)?;
|
writer.write_u8(destination)?;
|
||||||
writer.write_u32(id)?;
|
writer.write_u32(id)?;
|
||||||
writer.write_u64(timestamp)?;
|
writer.write_u64(timestamp)?;
|
||||||
}
|
}
|
||||||
Packet::DmaPlaybackReply { destination, succeeded } => {
|
Packet::DmaPlaybackReply { succeeded } => {
|
||||||
writer.write_u8(0xb5)?;
|
writer.write_u8(0xb5)?;
|
||||||
writer.write_u8(destination)?;
|
|
||||||
writer.write_bool(succeeded)?;
|
writer.write_bool(succeeded)?;
|
||||||
}
|
}
|
||||||
Packet::DmaPlaybackStatus {
|
Packet::DmaPlaybackStatus {
|
||||||
source,
|
|
||||||
destination,
|
destination,
|
||||||
id,
|
id,
|
||||||
error,
|
error,
|
||||||
|
@ -846,7 +761,6 @@ impl Packet {
|
||||||
timestamp,
|
timestamp,
|
||||||
} => {
|
} => {
|
||||||
writer.write_u8(0xb6)?;
|
writer.write_u8(0xb6)?;
|
||||||
writer.write_u8(source)?;
|
|
||||||
writer.write_u8(destination)?;
|
writer.write_u8(destination)?;
|
||||||
writer.write_u32(id)?;
|
writer.write_u32(id)?;
|
||||||
writer.write_u8(error)?;
|
writer.write_u8(error)?;
|
||||||
|
@ -857,14 +771,14 @@ impl Packet {
|
||||||
Packet::SubkernelAddDataRequest {
|
Packet::SubkernelAddDataRequest {
|
||||||
destination,
|
destination,
|
||||||
id,
|
id,
|
||||||
status,
|
last,
|
||||||
data,
|
data,
|
||||||
length,
|
length,
|
||||||
} => {
|
} => {
|
||||||
writer.write_u8(0xc0)?;
|
writer.write_u8(0xc0)?;
|
||||||
writer.write_u8(destination)?;
|
writer.write_u8(destination)?;
|
||||||
writer.write_u32(id)?;
|
writer.write_u32(id)?;
|
||||||
writer.write_u8(status as u8)?;
|
writer.write_bool(last)?;
|
||||||
writer.write_u16(length)?;
|
writer.write_u16(length)?;
|
||||||
writer.write_all(&data[0..length as usize])?;
|
writer.write_all(&data[0..length as usize])?;
|
||||||
}
|
}
|
||||||
|
@ -872,65 +786,50 @@ impl Packet {
|
||||||
writer.write_u8(0xc1)?;
|
writer.write_u8(0xc1)?;
|
||||||
writer.write_bool(succeeded)?;
|
writer.write_bool(succeeded)?;
|
||||||
}
|
}
|
||||||
Packet::SubkernelLoadRunRequest {
|
Packet::SubkernelLoadRunRequest { destination, id, run } => {
|
||||||
source,
|
|
||||||
destination,
|
|
||||||
id,
|
|
||||||
run,
|
|
||||||
} => {
|
|
||||||
writer.write_u8(0xc4)?;
|
writer.write_u8(0xc4)?;
|
||||||
writer.write_u8(source)?;
|
|
||||||
writer.write_u8(destination)?;
|
writer.write_u8(destination)?;
|
||||||
writer.write_u32(id)?;
|
writer.write_u32(id)?;
|
||||||
writer.write_bool(run)?;
|
writer.write_bool(run)?;
|
||||||
}
|
}
|
||||||
Packet::SubkernelLoadRunReply { destination, succeeded } => {
|
Packet::SubkernelLoadRunReply { succeeded } => {
|
||||||
writer.write_u8(0xc5)?;
|
writer.write_u8(0xc5)?;
|
||||||
writer.write_u8(destination)?;
|
|
||||||
writer.write_bool(succeeded)?;
|
writer.write_bool(succeeded)?;
|
||||||
}
|
}
|
||||||
Packet::SubkernelFinished {
|
Packet::SubkernelStopRequest { destination } => {
|
||||||
destination,
|
writer.write_u8(0xc6)?;
|
||||||
id,
|
|
||||||
with_exception,
|
|
||||||
exception_src,
|
|
||||||
} => {
|
|
||||||
writer.write_u8(0xc8)?;
|
|
||||||
writer.write_u8(destination)?;
|
writer.write_u8(destination)?;
|
||||||
|
}
|
||||||
|
Packet::SubkernelStopReply { succeeded } => {
|
||||||
|
writer.write_u8(0xc7)?;
|
||||||
|
writer.write_bool(succeeded)?;
|
||||||
|
}
|
||||||
|
Packet::SubkernelFinished { id, with_exception } => {
|
||||||
|
writer.write_u8(0xc8)?;
|
||||||
writer.write_u32(id)?;
|
writer.write_u32(id)?;
|
||||||
writer.write_bool(with_exception)?;
|
writer.write_bool(with_exception)?;
|
||||||
writer.write_u8(exception_src)?;
|
|
||||||
}
|
}
|
||||||
Packet::SubkernelExceptionRequest { source, destination } => {
|
Packet::SubkernelExceptionRequest { destination } => {
|
||||||
writer.write_u8(0xc9)?;
|
writer.write_u8(0xc9)?;
|
||||||
writer.write_u8(source)?;
|
|
||||||
writer.write_u8(destination)?;
|
writer.write_u8(destination)?;
|
||||||
}
|
}
|
||||||
Packet::SubkernelException {
|
Packet::SubkernelException { last, length, data } => {
|
||||||
destination,
|
|
||||||
last,
|
|
||||||
length,
|
|
||||||
data,
|
|
||||||
} => {
|
|
||||||
writer.write_u8(0xca)?;
|
writer.write_u8(0xca)?;
|
||||||
writer.write_u8(destination)?;
|
|
||||||
writer.write_bool(last)?;
|
writer.write_bool(last)?;
|
||||||
writer.write_u16(length)?;
|
writer.write_u16(length)?;
|
||||||
writer.write_all(&data[0..length as usize])?;
|
writer.write_all(&data[0..length as usize])?;
|
||||||
}
|
}
|
||||||
Packet::SubkernelMessage {
|
Packet::SubkernelMessage {
|
||||||
source,
|
|
||||||
destination,
|
destination,
|
||||||
id,
|
id,
|
||||||
status,
|
last,
|
||||||
data,
|
data,
|
||||||
length,
|
length,
|
||||||
} => {
|
} => {
|
||||||
writer.write_u8(0xcb)?;
|
writer.write_u8(0xcb)?;
|
||||||
writer.write_u8(source)?;
|
|
||||||
writer.write_u8(destination)?;
|
writer.write_u8(destination)?;
|
||||||
writer.write_u32(id)?;
|
writer.write_u32(id)?;
|
||||||
writer.write_u8(status as u8)?;
|
writer.write_bool(last)?;
|
||||||
writer.write_u16(length)?;
|
writer.write_u16(length)?;
|
||||||
writer.write_all(&data[0..length as usize])?;
|
writer.write_all(&data[0..length as usize])?;
|
||||||
}
|
}
|
||||||
|
@ -941,41 +840,4 @@ impl Packet {
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn routable_destination(&self) -> Option<u8> {
|
|
||||||
// only for packets that could be re-routed, not only forwarded
|
|
||||||
match self {
|
|
||||||
Packet::DmaAddTraceRequest { destination, .. } => Some(*destination),
|
|
||||||
Packet::DmaAddTraceReply { destination, .. } => Some(*destination),
|
|
||||||
Packet::DmaRemoveTraceRequest { destination, .. } => Some(*destination),
|
|
||||||
Packet::DmaRemoveTraceReply { destination, .. } => Some(*destination),
|
|
||||||
Packet::DmaPlaybackRequest { destination, .. } => Some(*destination),
|
|
||||||
Packet::DmaPlaybackReply { destination, .. } => Some(*destination),
|
|
||||||
Packet::SubkernelLoadRunRequest { destination, .. } => Some(*destination),
|
|
||||||
Packet::SubkernelLoadRunReply { destination, .. } => Some(*destination),
|
|
||||||
Packet::SubkernelMessage { destination, .. } => Some(*destination),
|
|
||||||
Packet::SubkernelMessageAck { destination } => Some(*destination),
|
|
||||||
Packet::SubkernelExceptionRequest { destination, .. } => Some(*destination),
|
|
||||||
Packet::SubkernelException { destination, .. } => Some(*destination),
|
|
||||||
Packet::DmaPlaybackStatus { destination, .. } => Some(*destination),
|
|
||||||
Packet::SubkernelFinished { destination, .. } => Some(*destination),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn expects_response(&self) -> bool {
|
|
||||||
// returns true if the routable packet should elicit a response
|
|
||||||
// e.g. reply, ACK packets end a conversation,
|
|
||||||
// and firmware should not wait for response
|
|
||||||
match self {
|
|
||||||
Packet::DmaAddTraceReply { .. }
|
|
||||||
| Packet::DmaRemoveTraceReply { .. }
|
|
||||||
| Packet::DmaPlaybackReply { .. }
|
|
||||||
| Packet::SubkernelLoadRunReply { .. }
|
|
||||||
| Packet::SubkernelMessageAck { .. }
|
|
||||||
| Packet::DmaPlaybackStatus { .. }
|
|
||||||
| Packet::SubkernelFinished { .. } => false,
|
|
||||||
_ => true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,22 +0,0 @@
|
||||||
use libboard_zynq::{println, stdio};
|
|
||||||
use libcortex_a9::{interrupt_handler, regs::MPIDR};
|
|
||||||
use libregister::RegisterR;
|
|
||||||
|
|
||||||
#[cfg(has_si549)]
|
|
||||||
use crate::si549;
|
|
||||||
|
|
||||||
interrupt_handler!(FIQ, fiq, __irq_stack0_start, __irq_stack1_start, {
|
|
||||||
match MPIDR.read().cpu_id() {
|
|
||||||
0 => {
|
|
||||||
// nFIQ is driven directly and bypass GIC
|
|
||||||
#[cfg(has_si549)]
|
|
||||||
si549::wrpll::interrupt_handler();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
};
|
|
||||||
|
|
||||||
stdio::drop_uart();
|
|
||||||
println!("FIQ");
|
|
||||||
loop {}
|
|
||||||
});
|
|
|
@ -1,7 +1,6 @@
|
||||||
use libboard_zynq::i2c;
|
use libboard_zynq::i2c;
|
||||||
use log::info;
|
use log::info;
|
||||||
|
|
||||||
#[cfg(has_virtual_leds)]
|
|
||||||
use crate::pl::csr;
|
use crate::pl::csr;
|
||||||
|
|
||||||
// Only the bare minimum registers. Bits/IO connections equivalent between IC types.
|
// Only the bare minimum registers. Bits/IO connections equivalent between IC types.
|
||||||
|
@ -20,15 +19,11 @@ const IODIR_OUT_SFP_LED: u8 = 0x40;
|
||||||
const IODIR_OUT_SFP0_LED: u8 = 0x40;
|
const IODIR_OUT_SFP0_LED: u8 = 0x40;
|
||||||
#[cfg(hw_rev = "v1.1")]
|
#[cfg(hw_rev = "v1.1")]
|
||||||
const IODIR_OUT_SFP0_LED: u8 = 0x80;
|
const IODIR_OUT_SFP0_LED: u8 = 0x80;
|
||||||
#[cfg(has_si549)]
|
|
||||||
const IODIR_CLK_SEL: u8 = 0x80; // out
|
|
||||||
#[cfg(has_si5324)]
|
|
||||||
const IODIR_CLK_SEL: u8 = 0x00; // in
|
|
||||||
|
|
||||||
//IO expander port direction
|
//IO expander port direction
|
||||||
const IODIR0: [u8; 2] = [
|
const IODIR0: [u8; 2] = [
|
||||||
0xFF & !IODIR_OUT_SFP_TX_DISABLE & !IODIR_OUT_SFP0_LED,
|
0xFF & !IODIR_OUT_SFP_TX_DISABLE & !IODIR_OUT_SFP0_LED,
|
||||||
0xFF & !IODIR_OUT_SFP_TX_DISABLE & !IODIR_OUT_SFP_LED & !IODIR_CLK_SEL,
|
0xFF & !IODIR_OUT_SFP_TX_DISABLE & !IODIR_OUT_SFP_LED,
|
||||||
];
|
];
|
||||||
|
|
||||||
const IODIR1: [u8; 2] = [
|
const IODIR1: [u8; 2] = [
|
||||||
|
@ -38,7 +33,6 @@ const IODIR1: [u8; 2] = [
|
||||||
|
|
||||||
pub struct IoExpander {
|
pub struct IoExpander {
|
||||||
address: u8,
|
address: u8,
|
||||||
#[cfg(has_virtual_leds)]
|
|
||||||
virtual_led_mapping: &'static [(u8, u8, u8)],
|
virtual_led_mapping: &'static [(u8, u8, u8)],
|
||||||
iodir: [u8; 2],
|
iodir: [u8; 2],
|
||||||
out_current: [u8; 2],
|
out_current: [u8; 2],
|
||||||
|
@ -48,18 +42,17 @@ pub struct IoExpander {
|
||||||
|
|
||||||
impl IoExpander {
|
impl IoExpander {
|
||||||
pub fn new(i2c: &mut i2c::I2c, index: u8) -> Result<Self, &'static str> {
|
pub fn new(i2c: &mut i2c::I2c, index: u8) -> Result<Self, &'static str> {
|
||||||
#[cfg(all(hw_rev = "v1.0", has_virtual_leds))]
|
#[cfg(hw_rev = "v1.0")]
|
||||||
const VIRTUAL_LED_MAPPING0: [(u8, u8, u8); 2] = [(0, 0, 6), (1, 1, 6)];
|
const VIRTUAL_LED_MAPPING0: [(u8, u8, u8); 2] = [(0, 0, 6), (1, 1, 6)];
|
||||||
#[cfg(all(hw_rev = "v1.1", has_virtual_leds))]
|
#[cfg(hw_rev = "v1.1")]
|
||||||
const VIRTUAL_LED_MAPPING0: [(u8, u8, u8); 2] = [(0, 0, 7), (1, 1, 6)];
|
const VIRTUAL_LED_MAPPING0: [(u8, u8, u8); 2] = [(0, 0, 7), (1, 1, 6)];
|
||||||
#[cfg(has_virtual_leds)]
|
|
||||||
const VIRTUAL_LED_MAPPING1: [(u8, u8, u8); 2] = [(2, 0, 6), (3, 1, 6)];
|
const VIRTUAL_LED_MAPPING1: [(u8, u8, u8); 2] = [(2, 0, 6), (3, 1, 6)];
|
||||||
|
|
||||||
// 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 {
|
||||||
address: 0x40,
|
address: 0x40,
|
||||||
#[cfg(has_virtual_leds)]
|
|
||||||
virtual_led_mapping: &VIRTUAL_LED_MAPPING0,
|
virtual_led_mapping: &VIRTUAL_LED_MAPPING0,
|
||||||
iodir: IODIR0,
|
iodir: IODIR0,
|
||||||
out_current: [0; 2],
|
out_current: [0; 2],
|
||||||
|
@ -73,7 +66,6 @@ impl IoExpander {
|
||||||
},
|
},
|
||||||
1 => IoExpander {
|
1 => IoExpander {
|
||||||
address: 0x42,
|
address: 0x42,
|
||||||
#[cfg(has_virtual_leds)]
|
|
||||||
virtual_led_mapping: &VIRTUAL_LED_MAPPING1,
|
virtual_led_mapping: &VIRTUAL_LED_MAPPING1,
|
||||||
iodir: IODIR1,
|
iodir: IODIR1,
|
||||||
out_current: [0; 2],
|
out_current: [0; 2],
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![feature(never_type)]
|
#![feature(never_type)]
|
||||||
#![feature(naked_functions)]
|
|
||||||
#![feature(asm)]
|
|
||||||
|
|
||||||
extern crate core_io;
|
extern crate core_io;
|
||||||
extern crate crc;
|
extern crate crc;
|
||||||
|
@ -21,7 +19,6 @@ pub mod drtioaux;
|
||||||
#[cfg(has_drtio)]
|
#[cfg(has_drtio)]
|
||||||
pub mod drtioaux_async;
|
pub mod drtioaux_async;
|
||||||
pub mod drtioaux_proto;
|
pub mod drtioaux_proto;
|
||||||
pub mod fiq;
|
|
||||||
#[cfg(feature = "target_kasli_soc")]
|
#[cfg(feature = "target_kasli_soc")]
|
||||||
pub mod io_expander;
|
pub mod io_expander;
|
||||||
pub mod logger;
|
pub mod logger;
|
||||||
|
@ -38,8 +35,7 @@ pub mod drtio_eem;
|
||||||
pub mod grabber;
|
pub mod grabber;
|
||||||
#[cfg(has_si5324)]
|
#[cfg(has_si5324)]
|
||||||
pub mod si5324;
|
pub mod si5324;
|
||||||
#[cfg(has_si549)]
|
|
||||||
pub mod si549;
|
|
||||||
use core::{cmp, str};
|
use core::{cmp, str};
|
||||||
|
|
||||||
pub fn identifier_read(buf: &mut [u8]) -> &str {
|
pub fn identifier_read(buf: &mut [u8]) -> &str {
|
||||||
|
|
|
@ -1,854 +0,0 @@
|
||||||
use embedded_hal::prelude::_embedded_hal_blocking_delay_DelayUs;
|
|
||||||
use libboard_zynq::timer::GlobalTimer;
|
|
||||||
use log::info;
|
|
||||||
|
|
||||||
use crate::pl::csr;
|
|
||||||
|
|
||||||
#[cfg(feature = "target_kasli_soc")]
|
|
||||||
const ADDRESS: u8 = 0x67;
|
|
||||||
|
|
||||||
const ADPLL_MAX: i32 = (950.0 / 0.0001164) as i32;
|
|
||||||
|
|
||||||
pub struct DividerConfig {
|
|
||||||
pub hsdiv: u16,
|
|
||||||
pub lsdiv: u8,
|
|
||||||
pub fbdiv: u64,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct FrequencySetting {
|
|
||||||
pub main: DividerConfig,
|
|
||||||
pub helper: DividerConfig,
|
|
||||||
}
|
|
||||||
|
|
||||||
mod i2c {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
pub enum DCXO {
|
|
||||||
Main,
|
|
||||||
Helper,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn half_period(timer: &mut GlobalTimer) {
|
|
||||||
timer.delay_us(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn sda_i(dcxo: DCXO) -> bool {
|
|
||||||
match dcxo {
|
|
||||||
DCXO::Main => unsafe { csr::wrpll::main_dcxo_sda_in_read() == 1 },
|
|
||||||
DCXO::Helper => unsafe { csr::wrpll::helper_dcxo_sda_in_read() == 1 },
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn sda_oe(dcxo: DCXO, oe: bool) {
|
|
||||||
let val = if oe { 1 } else { 0 };
|
|
||||||
match dcxo {
|
|
||||||
DCXO::Main => unsafe { csr::wrpll::main_dcxo_sda_oe_write(val) },
|
|
||||||
DCXO::Helper => unsafe { csr::wrpll::helper_dcxo_sda_oe_write(val) },
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
fn sda_o(dcxo: DCXO, o: bool) {
|
|
||||||
let val = if o { 1 } else { 0 };
|
|
||||||
match dcxo {
|
|
||||||
DCXO::Main => unsafe { csr::wrpll::main_dcxo_sda_out_write(val) },
|
|
||||||
DCXO::Helper => unsafe { csr::wrpll::helper_dcxo_sda_out_write(val) },
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
fn scl_oe(dcxo: DCXO, oe: bool) {
|
|
||||||
let val = if oe { 1 } else { 0 };
|
|
||||||
match dcxo {
|
|
||||||
DCXO::Main => unsafe { csr::wrpll::main_dcxo_scl_oe_write(val) },
|
|
||||||
DCXO::Helper => unsafe { csr::wrpll::helper_dcxo_scl_oe_write(val) },
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
fn scl_o(dcxo: DCXO, o: bool) {
|
|
||||||
let val = if o { 1 } else { 0 };
|
|
||||||
match dcxo {
|
|
||||||
DCXO::Main => unsafe { csr::wrpll::main_dcxo_scl_out_write(val) },
|
|
||||||
DCXO::Helper => unsafe { csr::wrpll::helper_dcxo_scl_out_write(val) },
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn init(dcxo: DCXO, timer: &mut GlobalTimer) -> Result<(), &'static str> {
|
|
||||||
// Set SCL as output, and high level
|
|
||||||
scl_o(dcxo, true);
|
|
||||||
scl_oe(dcxo, true);
|
|
||||||
// Prepare a zero level on SDA so that sda_oe pulls it down
|
|
||||||
sda_o(dcxo, false);
|
|
||||||
// Release SDA
|
|
||||||
sda_oe(dcxo, false);
|
|
||||||
|
|
||||||
// Check the I2C bus is ready
|
|
||||||
half_period(timer);
|
|
||||||
half_period(timer);
|
|
||||||
if !sda_i(dcxo) {
|
|
||||||
// Try toggling SCL a few times
|
|
||||||
for _bit in 0..8 {
|
|
||||||
scl_o(dcxo, false);
|
|
||||||
half_period(timer);
|
|
||||||
scl_o(dcxo, true);
|
|
||||||
half_period(timer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !sda_i(dcxo) {
|
|
||||||
return Err("SDA is stuck low and doesn't get unstuck");
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn start(dcxo: DCXO, timer: &mut GlobalTimer) {
|
|
||||||
// Set SCL high then SDA low
|
|
||||||
scl_o(dcxo, true);
|
|
||||||
half_period(timer);
|
|
||||||
sda_oe(dcxo, true);
|
|
||||||
half_period(timer);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn stop(dcxo: DCXO, timer: &mut GlobalTimer) {
|
|
||||||
// First, make sure SCL is low, so that the target releases the SDA line
|
|
||||||
scl_o(dcxo, false);
|
|
||||||
half_period(timer);
|
|
||||||
// Set SCL high then SDA high
|
|
||||||
sda_oe(dcxo, true);
|
|
||||||
scl_o(dcxo, true);
|
|
||||||
half_period(timer);
|
|
||||||
sda_oe(dcxo, false);
|
|
||||||
half_period(timer);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn write(dcxo: DCXO, data: u8, timer: &mut GlobalTimer) -> bool {
|
|
||||||
// MSB first
|
|
||||||
for bit in (0..8).rev() {
|
|
||||||
// Set SCL low and set our bit on SDA
|
|
||||||
scl_o(dcxo, false);
|
|
||||||
sda_oe(dcxo, data & (1 << bit) == 0);
|
|
||||||
half_period(timer);
|
|
||||||
// Set SCL high ; data is shifted on the rising edge of SCL
|
|
||||||
scl_o(dcxo, true);
|
|
||||||
half_period(timer);
|
|
||||||
}
|
|
||||||
// Check ack
|
|
||||||
// Set SCL low, then release SDA so that the I2C target can respond
|
|
||||||
scl_o(dcxo, false);
|
|
||||||
half_period(timer);
|
|
||||||
sda_oe(dcxo, false);
|
|
||||||
// Set SCL high and check for ack
|
|
||||||
scl_o(dcxo, true);
|
|
||||||
half_period(timer);
|
|
||||||
// returns true if acked (I2C target pulled SDA low)
|
|
||||||
!sda_i(dcxo)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn read(dcxo: DCXO, ack: bool, timer: &mut GlobalTimer) -> u8 {
|
|
||||||
// Set SCL low first, otherwise setting SDA as input may cause a transition
|
|
||||||
// on SDA with SCL high which will be interpreted as START/STOP condition.
|
|
||||||
scl_o(dcxo, false);
|
|
||||||
half_period(timer); // make sure SCL has settled low
|
|
||||||
sda_oe(dcxo, false);
|
|
||||||
|
|
||||||
let mut data: u8 = 0;
|
|
||||||
|
|
||||||
// MSB first
|
|
||||||
for bit in (0..8).rev() {
|
|
||||||
scl_o(dcxo, false);
|
|
||||||
half_period(timer);
|
|
||||||
// Set SCL high and shift data
|
|
||||||
scl_o(dcxo, true);
|
|
||||||
half_period(timer);
|
|
||||||
if sda_i(dcxo) {
|
|
||||||
data |= 1 << bit
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Send ack
|
|
||||||
// Set SCL low and pull SDA low when acking
|
|
||||||
scl_o(dcxo, false);
|
|
||||||
if ack {
|
|
||||||
sda_oe(dcxo, true)
|
|
||||||
}
|
|
||||||
half_period(timer);
|
|
||||||
// then set SCL high
|
|
||||||
scl_o(dcxo, true);
|
|
||||||
half_period(timer);
|
|
||||||
|
|
||||||
data
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write(dcxo: i2c::DCXO, reg: u8, val: u8, timer: &mut GlobalTimer) -> Result<(), &'static str> {
|
|
||||||
i2c::start(dcxo, timer);
|
|
||||||
if !i2c::write(dcxo, ADDRESS << 1, timer) {
|
|
||||||
return Err("Si549 failed to ack write address");
|
|
||||||
}
|
|
||||||
if !i2c::write(dcxo, reg, timer) {
|
|
||||||
return Err("Si549 failed to ack register");
|
|
||||||
}
|
|
||||||
if !i2c::write(dcxo, val, timer) {
|
|
||||||
return Err("Si549 failed to ack value");
|
|
||||||
}
|
|
||||||
i2c::stop(dcxo, timer);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read(dcxo: i2c::DCXO, reg: u8, timer: &mut GlobalTimer) -> Result<u8, &'static str> {
|
|
||||||
i2c::start(dcxo, timer);
|
|
||||||
if !i2c::write(dcxo, ADDRESS << 1, timer) {
|
|
||||||
return Err("Si549 failed to ack write address");
|
|
||||||
}
|
|
||||||
if !i2c::write(dcxo, reg, timer) {
|
|
||||||
return Err("Si549 failed to ack register");
|
|
||||||
}
|
|
||||||
i2c::stop(dcxo, timer);
|
|
||||||
|
|
||||||
i2c::start(dcxo, timer);
|
|
||||||
if !i2c::write(dcxo, (ADDRESS << 1) | 1, timer) {
|
|
||||||
return Err("Si549 failed to ack read address");
|
|
||||||
}
|
|
||||||
let val = i2c::read(dcxo, false, timer);
|
|
||||||
i2c::stop(dcxo, timer);
|
|
||||||
Ok(val)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn setup(dcxo: i2c::DCXO, config: &DividerConfig, timer: &mut GlobalTimer) -> Result<(), &'static str> {
|
|
||||||
i2c::init(dcxo, timer)?;
|
|
||||||
|
|
||||||
write(dcxo, 255, 0x00, timer)?; // PAGE
|
|
||||||
write(dcxo, 69, 0x00, timer)?; // Disable FCAL override.
|
|
||||||
write(dcxo, 17, 0x00, timer)?; // Synchronously disable output
|
|
||||||
|
|
||||||
// The Si549 has no ID register, so we check that it responds correctly
|
|
||||||
// by writing values to a RAM-like register and reading them back.
|
|
||||||
for test_value in 0..255 {
|
|
||||||
write(dcxo, 23, test_value, timer)?;
|
|
||||||
let readback = read(dcxo, 23, timer)?;
|
|
||||||
if readback != test_value {
|
|
||||||
return Err("Si549 detection failed");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
write(dcxo, 23, config.hsdiv as u8, timer)?;
|
|
||||||
write(dcxo, 24, (config.hsdiv >> 8) as u8 | (config.lsdiv << 4), timer)?;
|
|
||||||
write(dcxo, 26, config.fbdiv as u8, timer)?;
|
|
||||||
write(dcxo, 27, (config.fbdiv >> 8) as u8, timer)?;
|
|
||||||
write(dcxo, 28, (config.fbdiv >> 16) as u8, timer)?;
|
|
||||||
write(dcxo, 29, (config.fbdiv >> 24) as u8, timer)?;
|
|
||||||
write(dcxo, 30, (config.fbdiv >> 32) as u8, timer)?;
|
|
||||||
write(dcxo, 31, (config.fbdiv >> 40) as u8, timer)?;
|
|
||||||
|
|
||||||
write(dcxo, 7, 0x08, timer)?; // Start FCAL
|
|
||||||
timer.delay_us(30_000); // Internal FCAL VCO calibration
|
|
||||||
write(dcxo, 17, 0x01, timer)?; // Synchronously enable output
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn main_setup(timer: &mut GlobalTimer, settings: &FrequencySetting) -> Result<(), &'static str> {
|
|
||||||
unsafe {
|
|
||||||
csr::wrpll::main_dcxo_bitbang_enable_write(1);
|
|
||||||
csr::wrpll::main_dcxo_i2c_address_write(ADDRESS);
|
|
||||||
}
|
|
||||||
|
|
||||||
setup(i2c::DCXO::Main, &settings.main, timer)?;
|
|
||||||
|
|
||||||
// Si549 maximum settling time for large frequency change.
|
|
||||||
timer.delay_us(40_000);
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
csr::wrpll::main_dcxo_bitbang_enable_write(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
info!("Main Si549 started");
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn helper_setup(timer: &mut GlobalTimer, settings: &FrequencySetting) -> Result<(), &'static str> {
|
|
||||||
unsafe {
|
|
||||||
csr::wrpll::helper_reset_write(1);
|
|
||||||
csr::wrpll::helper_dcxo_bitbang_enable_write(1);
|
|
||||||
csr::wrpll::helper_dcxo_i2c_address_write(ADDRESS);
|
|
||||||
}
|
|
||||||
|
|
||||||
setup(i2c::DCXO::Helper, &settings.helper, timer)?;
|
|
||||||
|
|
||||||
// Si549 maximum settling time for large frequency change.
|
|
||||||
timer.delay_us(40_000);
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
csr::wrpll::helper_reset_write(0);
|
|
||||||
csr::wrpll::helper_dcxo_bitbang_enable_write(0);
|
|
||||||
}
|
|
||||||
info!("Helper Si549 started");
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_adpll(dcxo: i2c::DCXO, adpll: i32) -> Result<(), &'static str> {
|
|
||||||
if adpll.abs() > ADPLL_MAX {
|
|
||||||
return Err("adpll is too large");
|
|
||||||
}
|
|
||||||
|
|
||||||
match dcxo {
|
|
||||||
i2c::DCXO::Main => unsafe {
|
|
||||||
if csr::wrpll::main_dcxo_bitbang_enable_read() == 1 {
|
|
||||||
return Err("Main si549 bitbang mode is active when using gateware i2c");
|
|
||||||
}
|
|
||||||
|
|
||||||
while csr::wrpll::main_dcxo_adpll_busy_read() == 1 {}
|
|
||||||
if csr::wrpll::main_dcxo_nack_read() == 1 {
|
|
||||||
return Err("Main si549 failed to ack adpll write");
|
|
||||||
}
|
|
||||||
|
|
||||||
csr::wrpll::main_dcxo_i2c_address_write(ADDRESS);
|
|
||||||
csr::wrpll::main_dcxo_adpll_write(adpll as u32);
|
|
||||||
|
|
||||||
csr::wrpll::main_dcxo_adpll_stb_write(1);
|
|
||||||
},
|
|
||||||
i2c::DCXO::Helper => unsafe {
|
|
||||||
if csr::wrpll::helper_dcxo_bitbang_enable_read() == 1 {
|
|
||||||
return Err("Helper si549 bitbang mode is active when using gateware i2c");
|
|
||||||
}
|
|
||||||
|
|
||||||
while csr::wrpll::helper_dcxo_adpll_busy_read() == 1 {}
|
|
||||||
if csr::wrpll::helper_dcxo_nack_read() == 1 {
|
|
||||||
return Err("Helper si549 failed to ack adpll write");
|
|
||||||
}
|
|
||||||
|
|
||||||
csr::wrpll::helper_dcxo_i2c_address_write(ADDRESS);
|
|
||||||
csr::wrpll::helper_dcxo_adpll_write(adpll as u32);
|
|
||||||
|
|
||||||
csr::wrpll::helper_dcxo_adpll_stb_write(1);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(has_wrpll)]
|
|
||||||
pub mod wrpll {
|
|
||||||
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
const BEATING_PERIOD: i32 = 0x8000;
|
|
||||||
const BEATING_HALFPERIOD: i32 = 0x4000;
|
|
||||||
const COUNTER_WIDTH: u32 = 24;
|
|
||||||
const DIV_WIDTH: u32 = 2;
|
|
||||||
|
|
||||||
// y[n] = b0*x[n] + b1*x[n-1] + b2*x[n-2] - a1*y[n-1] - a2*y[n-2]
|
|
||||||
struct FilterParameters {
|
|
||||||
pub b0: f64,
|
|
||||||
pub b1: f64,
|
|
||||||
pub b2: f64,
|
|
||||||
pub a1: f64,
|
|
||||||
pub a2: f64,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(rtio_frequency = "100.0")]
|
|
||||||
const LPF: FilterParameters = FilterParameters {
|
|
||||||
b0: 0.03967479060647884,
|
|
||||||
b1: 0.07934958121295768,
|
|
||||||
b2: 0.03967479060647884,
|
|
||||||
a1: -1.3865593741228928,
|
|
||||||
a2: 0.5452585365488082,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[cfg(rtio_frequency = "125.0")]
|
|
||||||
const LPF: FilterParameters = FilterParameters {
|
|
||||||
b0: 0.07209205036273991,
|
|
||||||
b1: 0.14418410072547982,
|
|
||||||
b2: 0.07209205036273991,
|
|
||||||
a1: -0.6114078511562919,
|
|
||||||
a2: -0.10022394739274834,
|
|
||||||
};
|
|
||||||
|
|
||||||
static mut H_ADPLL1: i32 = 0;
|
|
||||||
static mut H_ADPLL2: i32 = 0;
|
|
||||||
static mut PERIOD_ERR1: i32 = 0;
|
|
||||||
static mut PERIOD_ERR2: i32 = 0;
|
|
||||||
|
|
||||||
static mut M_ADPLL1: i32 = 0;
|
|
||||||
static mut M_ADPLL2: i32 = 0;
|
|
||||||
static mut PHASE_ERR1: i32 = 0;
|
|
||||||
static mut PHASE_ERR2: i32 = 0;
|
|
||||||
|
|
||||||
static mut BASE_ADPLL: i32 = 0;
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
pub enum ISR {
|
|
||||||
RefTag,
|
|
||||||
MainTag,
|
|
||||||
}
|
|
||||||
|
|
||||||
mod tag_collector {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[cfg(wrpll_ref_clk = "GT_CDR")]
|
|
||||||
static mut TAG_OFFSET: u32 = 8382;
|
|
||||||
#[cfg(wrpll_ref_clk = "SMA_CLKIN")]
|
|
||||||
static mut TAG_OFFSET: u32 = 0;
|
|
||||||
static mut REF_TAG: u32 = 0;
|
|
||||||
static mut REF_TAG_READY: bool = false;
|
|
||||||
static mut MAIN_TAG: u32 = 0;
|
|
||||||
static mut MAIN_TAG_READY: bool = false;
|
|
||||||
|
|
||||||
pub fn reset() {
|
|
||||||
clear_phase_diff_ready();
|
|
||||||
unsafe {
|
|
||||||
REF_TAG = 0;
|
|
||||||
MAIN_TAG = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn clear_phase_diff_ready() {
|
|
||||||
unsafe {
|
|
||||||
REF_TAG_READY = false;
|
|
||||||
MAIN_TAG_READY = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn collect_tags(interrupt: ISR) {
|
|
||||||
match interrupt {
|
|
||||||
ISR::RefTag => unsafe {
|
|
||||||
REF_TAG = csr::wrpll::ref_tag_read();
|
|
||||||
REF_TAG_READY = true;
|
|
||||||
},
|
|
||||||
ISR::MainTag => unsafe {
|
|
||||||
MAIN_TAG = csr::wrpll::main_tag_read();
|
|
||||||
MAIN_TAG_READY = true;
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn phase_diff_ready() -> bool {
|
|
||||||
unsafe { REF_TAG_READY && MAIN_TAG_READY }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "calibrate_wrpll_skew")]
|
|
||||||
pub fn set_tag_offset(offset: u32) {
|
|
||||||
unsafe {
|
|
||||||
TAG_OFFSET = offset;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "calibrate_wrpll_skew")]
|
|
||||||
pub fn get_tag_offset() -> u32 {
|
|
||||||
unsafe { TAG_OFFSET }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_period_error() -> i32 {
|
|
||||||
// n * BEATING_PERIOD - REF_TAG(n) mod BEATING_PERIOD
|
|
||||||
let mut period_error = unsafe { REF_TAG.overflowing_neg().0.rem_euclid(BEATING_PERIOD as u32) as i32 };
|
|
||||||
// mapping tags from [0, 2π] -> [-π, π]
|
|
||||||
if period_error > BEATING_HALFPERIOD {
|
|
||||||
period_error -= BEATING_PERIOD
|
|
||||||
}
|
|
||||||
period_error
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_phase_error() -> i32 {
|
|
||||||
// MAIN_TAG(n) - REF_TAG(n) - TAG_OFFSET mod BEATING_PERIOD
|
|
||||||
let mut phase_error = unsafe {
|
|
||||||
MAIN_TAG
|
|
||||||
.overflowing_sub(REF_TAG + TAG_OFFSET)
|
|
||||||
.0
|
|
||||||
.rem_euclid(BEATING_PERIOD as u32) as i32
|
|
||||||
};
|
|
||||||
|
|
||||||
// mapping tags from [0, 2π] -> [-π, π]
|
|
||||||
if phase_error > BEATING_HALFPERIOD {
|
|
||||||
phase_error -= BEATING_PERIOD
|
|
||||||
}
|
|
||||||
phase_error
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_isr(en: bool) {
|
|
||||||
let val = if en { 1 } else { 0 };
|
|
||||||
unsafe {
|
|
||||||
csr::wrpll::ref_tag_ev_enable_write(val);
|
|
||||||
csr::wrpll::main_tag_ev_enable_write(val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_base_adpll() -> Result<(), &'static str> {
|
|
||||||
let count2adpll =
|
|
||||||
|error: i32| ((error as f64 * 1e6) / (0.0001164 * (1 << (COUNTER_WIDTH - DIV_WIDTH)) as f64)) as i32;
|
|
||||||
|
|
||||||
let (ref_count, main_count) = get_freq_counts();
|
|
||||||
unsafe {
|
|
||||||
BASE_ADPLL = count2adpll(ref_count as i32 - main_count as i32);
|
|
||||||
set_adpll(i2c::DCXO::Main, BASE_ADPLL)?;
|
|
||||||
set_adpll(i2c::DCXO::Helper, BASE_ADPLL)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_freq_counts() -> (u32, u32) {
|
|
||||||
unsafe {
|
|
||||||
csr::wrpll::frequency_counter_update_write(1);
|
|
||||||
while csr::wrpll::frequency_counter_busy_read() == 1 {}
|
|
||||||
#[cfg(wrpll_ref_clk = "GT_CDR")]
|
|
||||||
let ref_count = csr::wrpll::frequency_counter_counter_rtio_rx0_read();
|
|
||||||
#[cfg(wrpll_ref_clk = "SMA_CLKIN")]
|
|
||||||
let ref_count = csr::wrpll::frequency_counter_counter_ref_read();
|
|
||||||
let main_count = csr::wrpll::frequency_counter_counter_sys_read();
|
|
||||||
|
|
||||||
(ref_count, main_count)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn reset_plls(timer: &mut GlobalTimer) -> Result<(), &'static str> {
|
|
||||||
unsafe {
|
|
||||||
H_ADPLL1 = 0;
|
|
||||||
H_ADPLL2 = 0;
|
|
||||||
PERIOD_ERR1 = 0;
|
|
||||||
PERIOD_ERR2 = 0;
|
|
||||||
M_ADPLL1 = 0;
|
|
||||||
M_ADPLL2 = 0;
|
|
||||||
PHASE_ERR1 = 0;
|
|
||||||
PHASE_ERR2 = 0;
|
|
||||||
}
|
|
||||||
set_adpll(i2c::DCXO::Main, 0)?;
|
|
||||||
set_adpll(i2c::DCXO::Helper, 0)?;
|
|
||||||
// wait for adpll to transfer and DCXO to settle
|
|
||||||
timer.delay_us(200);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn clear_pending(interrupt: ISR) {
|
|
||||||
match interrupt {
|
|
||||||
ISR::RefTag => unsafe { csr::wrpll::ref_tag_ev_pending_write(1) },
|
|
||||||
ISR::MainTag => unsafe { csr::wrpll::main_tag_ev_pending_write(1) },
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_pending(interrupt: ISR) -> bool {
|
|
||||||
match interrupt {
|
|
||||||
ISR::RefTag => unsafe { csr::wrpll::ref_tag_ev_pending_read() == 1 },
|
|
||||||
ISR::MainTag => unsafe { csr::wrpll::main_tag_ev_pending_read() == 1 },
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn interrupt_handler() {
|
|
||||||
if is_pending(ISR::RefTag) {
|
|
||||||
tag_collector::collect_tags(ISR::RefTag);
|
|
||||||
clear_pending(ISR::RefTag);
|
|
||||||
helper_pll().expect("failed to run helper DCXO PLL");
|
|
||||||
}
|
|
||||||
|
|
||||||
if is_pending(ISR::MainTag) {
|
|
||||||
tag_collector::collect_tags(ISR::MainTag);
|
|
||||||
clear_pending(ISR::MainTag);
|
|
||||||
}
|
|
||||||
|
|
||||||
if tag_collector::phase_diff_ready() {
|
|
||||||
main_pll().expect("failed to run main DCXO PLL");
|
|
||||||
tag_collector::clear_phase_diff_ready();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn helper_pll() -> Result<(), &'static str> {
|
|
||||||
let period_err = tag_collector::get_period_error();
|
|
||||||
unsafe {
|
|
||||||
let adpll = ((LPF.b0 * period_err as f64) + (LPF.b1 * PERIOD_ERR1 as f64) + (LPF.b2 * PERIOD_ERR2 as f64)
|
|
||||||
- (LPF.a1 * H_ADPLL1 as f64)
|
|
||||||
- (LPF.a2 * H_ADPLL2 as f64)) as i32;
|
|
||||||
set_adpll(i2c::DCXO::Helper, BASE_ADPLL + adpll)?;
|
|
||||||
H_ADPLL2 = H_ADPLL1;
|
|
||||||
PERIOD_ERR2 = PERIOD_ERR1;
|
|
||||||
H_ADPLL1 = adpll;
|
|
||||||
PERIOD_ERR1 = period_err;
|
|
||||||
};
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main_pll() -> Result<(), &'static str> {
|
|
||||||
let phase_err = tag_collector::get_phase_error();
|
|
||||||
unsafe {
|
|
||||||
let adpll = ((LPF.b0 * phase_err as f64) + (LPF.b1 * PHASE_ERR1 as f64) + (LPF.b2 * PHASE_ERR2 as f64)
|
|
||||||
- (LPF.a1 * M_ADPLL1 as f64)
|
|
||||||
- (LPF.a2 * M_ADPLL2 as f64)) as i32;
|
|
||||||
set_adpll(i2c::DCXO::Main, BASE_ADPLL + adpll)?;
|
|
||||||
M_ADPLL2 = M_ADPLL1;
|
|
||||||
PHASE_ERR2 = PHASE_ERR1;
|
|
||||||
M_ADPLL1 = adpll;
|
|
||||||
PHASE_ERR1 = phase_err;
|
|
||||||
};
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(wrpll_ref_clk = "GT_CDR")]
|
|
||||||
fn test_skew(timer: &mut GlobalTimer) -> Result<(), &'static str> {
|
|
||||||
// wait for PLL to stabilize
|
|
||||||
timer.delay_us(20_000);
|
|
||||||
|
|
||||||
info!("testing the skew of SYS CLK...");
|
|
||||||
if has_timing_error(timer) {
|
|
||||||
return Err("the skew cannot satisfy setup/hold time constraint of RX synchronizer");
|
|
||||||
}
|
|
||||||
info!("the skew of SYS CLK met the timing constraint");
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(wrpll_ref_clk = "GT_CDR")]
|
|
||||||
fn has_timing_error(timer: &mut GlobalTimer) -> bool {
|
|
||||||
unsafe {
|
|
||||||
csr::wrpll_skewtester::error_write(1);
|
|
||||||
}
|
|
||||||
timer.delay_us(5_000);
|
|
||||||
unsafe { csr::wrpll_skewtester::error_read() == 1 }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "calibrate_wrpll_skew")]
|
|
||||||
fn find_edge(target: bool, timer: &mut GlobalTimer) -> Result<u32, &'static str> {
|
|
||||||
const STEP: u32 = 8;
|
|
||||||
const STABLE_THRESHOLD: u32 = 10;
|
|
||||||
|
|
||||||
enum FSM {
|
|
||||||
Init,
|
|
||||||
WaitEdge,
|
|
||||||
GotEdge,
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut state: FSM = FSM::Init;
|
|
||||||
let mut offset: u32 = tag_collector::get_tag_offset();
|
|
||||||
let mut median_edge: u32 = 0;
|
|
||||||
let mut stable_counter: u32 = 0;
|
|
||||||
|
|
||||||
for _ in 0..(BEATING_PERIOD as u32 / STEP) as usize {
|
|
||||||
tag_collector::set_tag_offset(offset);
|
|
||||||
offset += STEP;
|
|
||||||
// wait for PLL to stabilize
|
|
||||||
timer.delay_us(20_000);
|
|
||||||
|
|
||||||
let error = has_timing_error(timer);
|
|
||||||
// A median edge deglitcher
|
|
||||||
match state {
|
|
||||||
FSM::Init => {
|
|
||||||
if error != target {
|
|
||||||
stable_counter += 1;
|
|
||||||
} else {
|
|
||||||
stable_counter = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if stable_counter >= STABLE_THRESHOLD {
|
|
||||||
state = FSM::WaitEdge;
|
|
||||||
stable_counter = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
FSM::WaitEdge => {
|
|
||||||
if error == target {
|
|
||||||
state = FSM::GotEdge;
|
|
||||||
median_edge = offset;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
FSM::GotEdge => {
|
|
||||||
if error != target {
|
|
||||||
median_edge += STEP;
|
|
||||||
stable_counter = 0;
|
|
||||||
} else {
|
|
||||||
stable_counter += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if stable_counter >= STABLE_THRESHOLD {
|
|
||||||
return Ok(median_edge);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Err("failed to find timing error edge");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "calibrate_wrpll_skew")]
|
|
||||||
fn calibrate_skew(timer: &mut GlobalTimer) -> Result<(), &'static str> {
|
|
||||||
info!("calibrating skew to meet timing constraint...");
|
|
||||||
|
|
||||||
// clear calibrated value
|
|
||||||
tag_collector::set_tag_offset(0);
|
|
||||||
let rising = find_edge(true, timer)? as i32;
|
|
||||||
let falling = find_edge(false, timer)? as i32;
|
|
||||||
|
|
||||||
let width = BEATING_PERIOD - (falling - rising);
|
|
||||||
let result = falling + width / 2;
|
|
||||||
tag_collector::set_tag_offset(result as u32);
|
|
||||||
|
|
||||||
info!(
|
|
||||||
"calibration successful, error zone: {} -> {}, width: {} ({}deg), middle of working region: {}",
|
|
||||||
rising,
|
|
||||||
falling,
|
|
||||||
width,
|
|
||||||
360 * width / BEATING_PERIOD,
|
|
||||||
result,
|
|
||||||
);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn select_recovered_clock(rc: bool, timer: &mut GlobalTimer) {
|
|
||||||
set_isr(false);
|
|
||||||
|
|
||||||
if rc {
|
|
||||||
tag_collector::reset();
|
|
||||||
reset_plls(timer).expect("failed to reset main and helper PLL");
|
|
||||||
|
|
||||||
// get within capture range
|
|
||||||
set_base_adpll().expect("failed to set base adpll");
|
|
||||||
|
|
||||||
// clear gateware pending flag
|
|
||||||
clear_pending(ISR::RefTag);
|
|
||||||
clear_pending(ISR::MainTag);
|
|
||||||
|
|
||||||
// use nFIQ to avoid IRQ being disabled by mutex lock and mess up PLL
|
|
||||||
set_isr(true);
|
|
||||||
info!("WRPLL interrupt enabled");
|
|
||||||
|
|
||||||
#[cfg(feature = "calibrate_wrpll_skew")]
|
|
||||||
calibrate_skew(timer).expect("failed to set the correct skew");
|
|
||||||
|
|
||||||
#[cfg(wrpll_ref_clk = "GT_CDR")]
|
|
||||||
test_skew(timer).expect("skew test failed");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(has_wrpll_refclk)]
|
|
||||||
pub mod wrpll_refclk {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
pub struct MmcmSetting {
|
|
||||||
pub clkout0_reg1: u16, //0x08
|
|
||||||
pub clkout0_reg2: u16, //0x09
|
|
||||||
pub clkfbout_reg1: u16, //0x14
|
|
||||||
pub clkfbout_reg2: u16, //0x15
|
|
||||||
pub div_reg: u16, //0x16
|
|
||||||
pub lock_reg1: u16, //0x18
|
|
||||||
pub lock_reg2: u16, //0x19
|
|
||||||
pub lock_reg3: u16, //0x1A
|
|
||||||
pub power_reg: u16, //0x28
|
|
||||||
pub filt_reg1: u16, //0x4E
|
|
||||||
pub filt_reg2: u16, //0x4F
|
|
||||||
}
|
|
||||||
|
|
||||||
fn one_clock_cycle() {
|
|
||||||
unsafe {
|
|
||||||
csr::wrpll_refclk::mmcm_dclk_write(1);
|
|
||||||
csr::wrpll_refclk::mmcm_dclk_write(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_addr(address: u8) {
|
|
||||||
unsafe {
|
|
||||||
csr::wrpll_refclk::mmcm_daddr_write(address);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_data(value: u16) {
|
|
||||||
unsafe {
|
|
||||||
csr::wrpll_refclk::mmcm_din_write(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_enable(en: bool) {
|
|
||||||
unsafe {
|
|
||||||
let val = if en { 1 } else { 0 };
|
|
||||||
csr::wrpll_refclk::mmcm_den_write(val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_write_enable(en: bool) {
|
|
||||||
unsafe {
|
|
||||||
let val = if en { 1 } else { 0 };
|
|
||||||
csr::wrpll_refclk::mmcm_dwen_write(val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_data() -> u16 {
|
|
||||||
unsafe { csr::wrpll_refclk::mmcm_dout_read() }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn drp_ready() -> bool {
|
|
||||||
unsafe { csr::wrpll_refclk::mmcm_dready_read() == 1 }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
fn read(address: u8) -> u16 {
|
|
||||||
set_addr(address);
|
|
||||||
set_enable(true);
|
|
||||||
// Set DADDR on the mmcm and assert DEN for one clock cycle
|
|
||||||
one_clock_cycle();
|
|
||||||
|
|
||||||
set_enable(false);
|
|
||||||
while !drp_ready() {
|
|
||||||
// keep the clock signal until data is ready
|
|
||||||
one_clock_cycle();
|
|
||||||
}
|
|
||||||
get_data()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write(address: u8, value: u16) {
|
|
||||||
set_addr(address);
|
|
||||||
set_data(value);
|
|
||||||
set_write_enable(true);
|
|
||||||
set_enable(true);
|
|
||||||
// Set DADDR, DI on the mmcm and assert DWE, DEN for one clock cycle
|
|
||||||
one_clock_cycle();
|
|
||||||
|
|
||||||
set_write_enable(false);
|
|
||||||
set_enable(false);
|
|
||||||
while !drp_ready() {
|
|
||||||
// keep the clock signal until write is finished
|
|
||||||
one_clock_cycle();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn reset(rst: bool) {
|
|
||||||
unsafe {
|
|
||||||
let val = if rst { 1 } else { 0 };
|
|
||||||
csr::wrpll_refclk::mmcm_reset_write(val)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn setup(timer: &mut GlobalTimer, settings: MmcmSetting, mmcm_bypass: bool) -> Result<(), &'static str> {
|
|
||||||
unsafe {
|
|
||||||
csr::wrpll_refclk::refclk_reset_write(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if mmcm_bypass {
|
|
||||||
info!("Bypassing mmcm");
|
|
||||||
unsafe {
|
|
||||||
csr::wrpll_refclk::mmcm_bypass_write(1);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Based on "DRP State Machine" from XAPP888
|
|
||||||
// hold reset HIGH during mmcm config
|
|
||||||
reset(true);
|
|
||||||
write(0x08, settings.clkout0_reg1);
|
|
||||||
write(0x09, settings.clkout0_reg2);
|
|
||||||
write(0x14, settings.clkfbout_reg1);
|
|
||||||
write(0x15, settings.clkfbout_reg2);
|
|
||||||
write(0x16, settings.div_reg);
|
|
||||||
write(0x18, settings.lock_reg1);
|
|
||||||
write(0x19, settings.lock_reg2);
|
|
||||||
write(0x1A, settings.lock_reg3);
|
|
||||||
write(0x28, settings.power_reg);
|
|
||||||
write(0x4E, settings.filt_reg1);
|
|
||||||
write(0x4F, settings.filt_reg2);
|
|
||||||
reset(false);
|
|
||||||
|
|
||||||
// wait for the mmcm to lock
|
|
||||||
timer.delay_us(100);
|
|
||||||
|
|
||||||
let locked = unsafe { csr::wrpll_refclk::mmcm_locked_read() == 1 };
|
|
||||||
if !locked {
|
|
||||||
return Err("mmcm failed to generate 125MHz ref clock from SMA CLKIN");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
csr::wrpll_refclk::refclk_reset_write(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -10,9 +10,7 @@ SECTIONS
|
||||||
__text_start = .;
|
__text_start = .;
|
||||||
.text :
|
.text :
|
||||||
{
|
{
|
||||||
__exceptions_start = .;
|
|
||||||
KEEP(*(.text.exceptions));
|
KEEP(*(.text.exceptions));
|
||||||
__exceptions_end = .;
|
|
||||||
*(.text.boot);
|
*(.text.boot);
|
||||||
*(.text .text.*);
|
*(.text .text.*);
|
||||||
} > SDRAM
|
} > SDRAM
|
||||||
|
|
|
@ -45,10 +45,7 @@ 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());
|
||||||
// ``copy_from_slice`` generates AXI bursts, use a regular loop instead
|
buf[..len].copy_from_slice(&data[..len]);
|
||||||
for i in 0..len {
|
|
||||||
buf[i] = data[i];
|
|
||||||
}
|
|
||||||
self.pos += len;
|
self.pos += len;
|
||||||
Ok(len)
|
Ok(len)
|
||||||
}
|
}
|
||||||
|
@ -58,9 +55,7 @@ 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());
|
||||||
for i in 0..len {
|
data[..len].copy_from_slice(&buf[..len]);
|
||||||
data[i] = buf[i];
|
|
||||||
}
|
|
||||||
self.pos += len;
|
self.pos += len;
|
||||||
Ok(len)
|
Ok(len)
|
||||||
}
|
}
|
||||||
|
@ -73,6 +68,7 @@ impl Write for Cursor<&mut [u8]> {
|
||||||
|
|
||||||
#[cfg(feature = "alloc")]
|
#[cfg(feature = "alloc")]
|
||||||
impl Write for Cursor<Vec<u8>> {
|
impl Write for Cursor<Vec<u8>> {
|
||||||
|
#[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);
|
||||||
Ok(buf.len())
|
Ok(buf.len())
|
||||||
|
|
|
@ -32,9 +32,3 @@ unwind = { path = "../libunwind" }
|
||||||
libc = { path = "../libc" }
|
libc = { path = "../libc" }
|
||||||
io = { path = "../libio" }
|
io = { path = "../libio" }
|
||||||
libboard_artiq = { path = "../libboard_artiq" }
|
libboard_artiq = { path = "../libboard_artiq" }
|
||||||
|
|
||||||
[dependencies.nalgebra]
|
|
||||||
git = "https://git.m-labs.hk/M-Labs/nalgebra.git"
|
|
||||||
rev = "dd00f9b"
|
|
||||||
default-features = false
|
|
||||||
features = ["libm", "alloc"]
|
|
||||||
|
|
|
@ -14,10 +14,8 @@
|
||||||
|
|
||||||
use core::mem;
|
use core::mem;
|
||||||
|
|
||||||
use core_io::Error as ReadError;
|
|
||||||
use cslice::CSlice;
|
use cslice::CSlice;
|
||||||
use dwarf::eh::{self, EHAction, EHContext};
|
use dwarf::eh::{self, EHAction, EHContext};
|
||||||
use io::{Cursor, ProtoRead};
|
|
||||||
use libc::{c_int, c_void, uintptr_t};
|
use libc::{c_int, c_void, uintptr_t};
|
||||||
use log::{error, trace};
|
use log::{error, trace};
|
||||||
use unwind as uw;
|
use unwind as uw;
|
||||||
|
@ -297,60 +295,6 @@ pub unsafe extern "C" fn raise(exception: *const Exception) -> ! {
|
||||||
unreachable!();
|
unreachable!();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_exception_string<'a>(reader: &mut Cursor<&[u8]>) -> Result<CSlice<'a, u8>, ReadError> {
|
|
||||||
let len = reader.read_u32()? as usize;
|
|
||||||
if len == usize::MAX {
|
|
||||||
let data = reader.read_u32()?;
|
|
||||||
Ok(unsafe { CSlice::new(data as *const u8, len) })
|
|
||||||
} else {
|
|
||||||
let pos = reader.position();
|
|
||||||
let slice = unsafe {
|
|
||||||
let ptr = reader.get_ref().as_ptr().offset(pos as isize);
|
|
||||||
CSlice::new(ptr, len)
|
|
||||||
};
|
|
||||||
reader.set_position(pos + len);
|
|
||||||
Ok(slice)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read_exception(raw_exception: &[u8]) -> Result<Exception, ReadError> {
|
|
||||||
let mut reader = Cursor::new(raw_exception);
|
|
||||||
|
|
||||||
let mut byte = reader.read_u8()?;
|
|
||||||
// to sync
|
|
||||||
while byte != 0x5a {
|
|
||||||
byte = reader.read_u8()?;
|
|
||||||
}
|
|
||||||
// skip sync bytes, 0x09 indicates exception
|
|
||||||
while byte != 0x09 {
|
|
||||||
byte = reader.read_u8()?;
|
|
||||||
}
|
|
||||||
let _len = reader.read_u32()?;
|
|
||||||
// ignore the remaining exceptions, stack traces etc. - unwinding from another device would be unwise anyway
|
|
||||||
Ok(Exception {
|
|
||||||
id: reader.read_u32()?,
|
|
||||||
message: read_exception_string(&mut reader)?,
|
|
||||||
param: [
|
|
||||||
reader.read_u64()? as i64,
|
|
||||||
reader.read_u64()? as i64,
|
|
||||||
reader.read_u64()? as i64,
|
|
||||||
],
|
|
||||||
file: read_exception_string(&mut reader)?,
|
|
||||||
line: reader.read_u32()?,
|
|
||||||
column: reader.read_u32()?,
|
|
||||||
function: read_exception_string(&mut reader)?,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn raise_raw(raw_exception: &[u8]) -> ! {
|
|
||||||
use crate::artiq_raise;
|
|
||||||
if let Ok(exception) = read_exception(raw_exception) {
|
|
||||||
unsafe { raise(&exception) };
|
|
||||||
} else {
|
|
||||||
artiq_raise!("SubkernelError", "Error passing exception");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub unsafe extern "C" fn resume() -> ! {
|
pub unsafe extern "C" fn resume() -> ! {
|
||||||
trace!("resume");
|
trace!("resume");
|
||||||
assert!(EXCEPTION_BUFFER.exception_count != 0);
|
assert!(EXCEPTION_BUFFER.exception_count != 0);
|
||||||
|
|
|
@ -9,7 +9,7 @@ use log::{info, warn};
|
||||||
use super::subkernel;
|
use super::subkernel;
|
||||||
use super::{cache,
|
use super::{cache,
|
||||||
core1::rtio_get_destination_status,
|
core1::rtio_get_destination_status,
|
||||||
dma, linalg,
|
dma,
|
||||||
rpc::{rpc_recv, rpc_send, rpc_send_async}};
|
rpc::{rpc_recv, rpc_send, rpc_send_async}};
|
||||||
use crate::{eh_artiq, i2c, rtio};
|
use crate::{eh_artiq, i2c, rtio};
|
||||||
|
|
||||||
|
@ -303,7 +303,6 @@ pub fn resolve(required: &[u8]) -> Option<u32> {
|
||||||
api_libm_f64f64f64!(nextafter),
|
api_libm_f64f64f64!(nextafter),
|
||||||
api_libm_f64f64f64!(pow),
|
api_libm_f64f64f64!(pow),
|
||||||
api_libm_f64f64!(round),
|
api_libm_f64f64!(round),
|
||||||
api_libm_f64f64!(rint),
|
|
||||||
api_libm_f64f64!(sin),
|
api_libm_f64f64!(sin),
|
||||||
api_libm_f64f64!(sinh),
|
api_libm_f64f64!(sinh),
|
||||||
api_libm_f64f64!(sqrt),
|
api_libm_f64f64!(sqrt),
|
||||||
|
@ -319,19 +318,6 @@ pub fn resolve(required: &[u8]) -> Option<u32> {
|
||||||
}
|
}
|
||||||
api!(yn = yn)
|
api!(yn = yn)
|
||||||
},
|
},
|
||||||
|
|
||||||
// linalg
|
|
||||||
api!(np_linalg_cholesky = linalg::np_linalg_cholesky),
|
|
||||||
api!(np_linalg_qr = linalg::np_linalg_qr),
|
|
||||||
api!(np_linalg_svd = linalg::np_linalg_svd),
|
|
||||||
api!(np_linalg_inv = linalg::np_linalg_inv),
|
|
||||||
api!(np_linalg_pinv = linalg::np_linalg_pinv),
|
|
||||||
api!(np_linalg_matrix_power = linalg::np_linalg_matrix_power),
|
|
||||||
api!(np_linalg_det = linalg::np_linalg_det),
|
|
||||||
api!(sp_linalg_lu = linalg::sp_linalg_lu),
|
|
||||||
api!(sp_linalg_schur = linalg::sp_linalg_schur),
|
|
||||||
api!(sp_linalg_hessenberg = linalg::sp_linalg_hessenberg),
|
|
||||||
|
|
||||||
];
|
];
|
||||||
api.iter()
|
api.iter()
|
||||||
.find(|&&(exported, _)| exported.as_bytes() == required)
|
.find(|&&(exported, _)| exported.as_bytes() == required)
|
||||||
|
|
|
@ -170,7 +170,6 @@ pub extern "C" fn dma_playback(timestamp: i64, ptr: i32, _uses_ddma: bool) {
|
||||||
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);
|
||||||
|
|
||||||
let old_cri_master = csr::cri_con::selected_read();
|
|
||||||
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)]
|
#[cfg(has_drtio)]
|
||||||
|
@ -184,7 +183,7 @@ pub extern "C" fn dma_playback(timestamp: i64, ptr: i32, _uses_ddma: bool) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
while csr::rtio_dma::enable_read() != 0 {}
|
while csr::rtio_dma::enable_read() != 0 {}
|
||||||
csr::cri_con::selected_write(old_cri_master);
|
csr::cri_con::selected_write(0);
|
||||||
|
|
||||||
let error = csr::rtio_dma::error_read();
|
let error = csr::rtio_dma::error_read();
|
||||||
if error != 0 {
|
if error != 0 {
|
||||||
|
|
|
@ -1,440 +0,0 @@
|
||||||
// Uses `nalgebra` crate to invoke `np_linalg` and `sp_linalg` functions
|
|
||||||
// When converting between `nalgebra::Matrix` and `NDArray` following considerations are necessary
|
|
||||||
//
|
|
||||||
// * Both `nalgebra::Matrix` and `NDArray` require their content to be stored in row-major order
|
|
||||||
// * `NDArray` data pointer can be directly read and converted to `nalgebra::Matrix` (row and column number must be known)
|
|
||||||
// * `nalgebra::Matrix::as_slice` returns the content of matrix in column-major order and initial data needs to be transposed before storing it in `NDArray` data pointer
|
|
||||||
|
|
||||||
use alloc::vec::Vec;
|
|
||||||
use core::slice;
|
|
||||||
|
|
||||||
use nalgebra::DMatrix;
|
|
||||||
|
|
||||||
use crate::artiq_raise;
|
|
||||||
|
|
||||||
pub struct InputMatrix {
|
|
||||||
pub ndims: usize,
|
|
||||||
pub dims: *const usize,
|
|
||||||
pub data: *mut f64,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl InputMatrix {
|
|
||||||
fn get_dims(&mut self) -> Vec<usize> {
|
|
||||||
let dims = unsafe { slice::from_raw_parts(self.dims, self.ndims) };
|
|
||||||
dims.to_vec()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// # Safety
|
|
||||||
///
|
|
||||||
/// `mat1` should point to a valid 2DArray of `f64` floats in row-major order
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe extern "C" fn np_linalg_cholesky(mat1: *mut InputMatrix, out: *mut InputMatrix) {
|
|
||||||
let mat1 = mat1.as_mut().unwrap();
|
|
||||||
let out = out.as_mut().unwrap();
|
|
||||||
|
|
||||||
if mat1.ndims != 2 {
|
|
||||||
artiq_raise!(
|
|
||||||
"ValueError",
|
|
||||||
"expected 2D Vector Input, but received {1}D input)",
|
|
||||||
0,
|
|
||||||
mat1.ndims as i64,
|
|
||||||
0
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let dim1 = (*mat1).get_dims();
|
|
||||||
if dim1[0] != dim1[1] {
|
|
||||||
artiq_raise!(
|
|
||||||
"ValueError",
|
|
||||||
"last 2 dimensions of the array must be square: {1} != {2}",
|
|
||||||
0,
|
|
||||||
dim1[0] as i64,
|
|
||||||
dim1[1] as i64
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let outdim = out.get_dims();
|
|
||||||
let out_slice = unsafe { slice::from_raw_parts_mut(out.data, outdim[0] * outdim[1]) };
|
|
||||||
let data_slice1 = unsafe { slice::from_raw_parts_mut(mat1.data, dim1[0] * dim1[1]) };
|
|
||||||
|
|
||||||
let matrix1 = DMatrix::from_row_slice(dim1[0], dim1[1], data_slice1);
|
|
||||||
let result = matrix1.cholesky();
|
|
||||||
match result {
|
|
||||||
Some(res) => {
|
|
||||||
out_slice.copy_from_slice(res.unpack().transpose().as_slice());
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
artiq_raise!("LinAlgError", "Matrix is not positive definite");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// # Safety
|
|
||||||
///
|
|
||||||
/// `mat1` should point to a valid 2DArray of `f64` floats in row-major order
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe extern "C" fn np_linalg_qr(mat1: *mut InputMatrix, out_q: *mut InputMatrix, out_r: *mut InputMatrix) {
|
|
||||||
let mat1 = mat1.as_mut().unwrap();
|
|
||||||
let out_q = out_q.as_mut().unwrap();
|
|
||||||
let out_r = out_r.as_mut().unwrap();
|
|
||||||
|
|
||||||
if mat1.ndims != 2 {
|
|
||||||
artiq_raise!(
|
|
||||||
"ValueError",
|
|
||||||
"expected 2D Vector Input, but received {1}D input)",
|
|
||||||
0,
|
|
||||||
mat1.ndims as i64,
|
|
||||||
0
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let dim1 = (*mat1).get_dims();
|
|
||||||
let outq_dim = (*out_q).get_dims();
|
|
||||||
let outr_dim = (*out_r).get_dims();
|
|
||||||
|
|
||||||
let data_slice1 = unsafe { slice::from_raw_parts_mut(mat1.data, dim1[0] * dim1[1]) };
|
|
||||||
let out_q_slice = unsafe { slice::from_raw_parts_mut(out_q.data, outq_dim[0] * outq_dim[1]) };
|
|
||||||
let out_r_slice = unsafe { slice::from_raw_parts_mut(out_r.data, outr_dim[0] * outr_dim[1]) };
|
|
||||||
|
|
||||||
// Refer to https://github.com/dimforge/nalgebra/issues/735
|
|
||||||
let matrix1 = DMatrix::from_row_slice(dim1[0], dim1[1], data_slice1);
|
|
||||||
|
|
||||||
let res = matrix1.qr();
|
|
||||||
let (q, r) = res.unpack();
|
|
||||||
|
|
||||||
// Uses different algo need to match numpy
|
|
||||||
out_q_slice.copy_from_slice(q.transpose().as_slice());
|
|
||||||
out_r_slice.copy_from_slice(r.transpose().as_slice());
|
|
||||||
}
|
|
||||||
|
|
||||||
/// # Safety
|
|
||||||
///
|
|
||||||
/// `mat1` should point to a valid 2DArray of `f64` floats in row-major order
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe extern "C" fn np_linalg_svd(
|
|
||||||
mat1: *mut InputMatrix,
|
|
||||||
outu: *mut InputMatrix,
|
|
||||||
outs: *mut InputMatrix,
|
|
||||||
outvh: *mut InputMatrix,
|
|
||||||
) {
|
|
||||||
let mat1 = mat1.as_mut().unwrap();
|
|
||||||
let outu = outu.as_mut().unwrap();
|
|
||||||
let outs = outs.as_mut().unwrap();
|
|
||||||
let outvh = outvh.as_mut().unwrap();
|
|
||||||
|
|
||||||
if mat1.ndims != 2 {
|
|
||||||
artiq_raise!(
|
|
||||||
"ValueError",
|
|
||||||
"expected 2D Vector Input, but received {1}D input)",
|
|
||||||
0,
|
|
||||||
mat1.ndims as i64,
|
|
||||||
0
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let dim1 = (*mat1).get_dims();
|
|
||||||
let outu_dim = (*outu).get_dims();
|
|
||||||
let outs_dim = (*outs).get_dims();
|
|
||||||
let outvh_dim = (*outvh).get_dims();
|
|
||||||
|
|
||||||
let data_slice1 = unsafe { slice::from_raw_parts_mut(mat1.data, dim1[0] * dim1[1]) };
|
|
||||||
let out_u_slice = unsafe { slice::from_raw_parts_mut(outu.data, outu_dim[0] * outu_dim[1]) };
|
|
||||||
let out_s_slice = unsafe { slice::from_raw_parts_mut(outs.data, outs_dim[0]) };
|
|
||||||
let out_vh_slice = unsafe { slice::from_raw_parts_mut(outvh.data, outvh_dim[0] * outvh_dim[1]) };
|
|
||||||
|
|
||||||
let matrix = DMatrix::from_row_slice(dim1[0], dim1[1], data_slice1);
|
|
||||||
let result = matrix.svd(true, true);
|
|
||||||
out_u_slice.copy_from_slice(result.u.unwrap().transpose().as_slice());
|
|
||||||
out_s_slice.copy_from_slice(result.singular_values.as_slice());
|
|
||||||
out_vh_slice.copy_from_slice(result.v_t.unwrap().transpose().as_slice());
|
|
||||||
}
|
|
||||||
|
|
||||||
/// # Safety
|
|
||||||
///
|
|
||||||
/// `mat1` should point to a valid 2DArray of `f64` floats in row-major order
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe extern "C" fn np_linalg_inv(mat1: *mut InputMatrix, out: *mut InputMatrix) {
|
|
||||||
let mat1 = mat1.as_mut().unwrap();
|
|
||||||
let out = out.as_mut().unwrap();
|
|
||||||
|
|
||||||
if mat1.ndims != 2 {
|
|
||||||
artiq_raise!(
|
|
||||||
"ValueError",
|
|
||||||
"expected 2D Vector Input, but received {1}D input)",
|
|
||||||
0,
|
|
||||||
mat1.ndims as i64,
|
|
||||||
0
|
|
||||||
);
|
|
||||||
}
|
|
||||||
let dim1 = (*mat1).get_dims();
|
|
||||||
|
|
||||||
if dim1[0] != dim1[1] {
|
|
||||||
artiq_raise!(
|
|
||||||
"ValueError",
|
|
||||||
"last 2 dimensions of the array must be square: {1} != {2}",
|
|
||||||
0,
|
|
||||||
dim1[0] as i64,
|
|
||||||
dim1[1] as i64
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let outdim = out.get_dims();
|
|
||||||
let out_slice = unsafe { slice::from_raw_parts_mut(out.data, outdim[0] * outdim[1]) };
|
|
||||||
let data_slice1 = unsafe { slice::from_raw_parts_mut(mat1.data, dim1[0] * dim1[1]) };
|
|
||||||
|
|
||||||
let matrix = DMatrix::from_row_slice(dim1[0], dim1[1], data_slice1);
|
|
||||||
if !matrix.is_invertible() {
|
|
||||||
artiq_raise!("LinAlgError", "no inverse for Singular Matrix");
|
|
||||||
}
|
|
||||||
let inv = matrix.try_inverse().unwrap();
|
|
||||||
out_slice.copy_from_slice(inv.transpose().as_slice());
|
|
||||||
}
|
|
||||||
|
|
||||||
/// # Safety
|
|
||||||
///
|
|
||||||
/// `mat1` should point to a valid 2DArray of `f64` floats in row-major order
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe extern "C" fn np_linalg_pinv(mat1: *mut InputMatrix, out: *mut InputMatrix) {
|
|
||||||
let mat1 = mat1.as_mut().unwrap();
|
|
||||||
let out = out.as_mut().unwrap();
|
|
||||||
|
|
||||||
if mat1.ndims != 2 {
|
|
||||||
artiq_raise!(
|
|
||||||
"ValueError",
|
|
||||||
"expected 2D Vector Input, but received {1}D input)",
|
|
||||||
0,
|
|
||||||
mat1.ndims as i64,
|
|
||||||
0
|
|
||||||
);
|
|
||||||
}
|
|
||||||
let dim1 = (*mat1).get_dims();
|
|
||||||
let outdim = out.get_dims();
|
|
||||||
let out_slice = unsafe { slice::from_raw_parts_mut(out.data, outdim[0] * outdim[1]) };
|
|
||||||
let data_slice1 = unsafe { slice::from_raw_parts_mut(mat1.data, dim1[0] * dim1[1]) };
|
|
||||||
|
|
||||||
let matrix = DMatrix::from_row_slice(dim1[0], dim1[1], data_slice1);
|
|
||||||
let svd = matrix.svd(true, true);
|
|
||||||
let inv = svd.pseudo_inverse(1e-15);
|
|
||||||
|
|
||||||
match inv {
|
|
||||||
Ok(m) => {
|
|
||||||
out_slice.copy_from_slice(m.transpose().as_slice());
|
|
||||||
}
|
|
||||||
Err(_) => {
|
|
||||||
artiq_raise!("LinAlgError", "SVD computation does not converge");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// # Safety
|
|
||||||
///
|
|
||||||
/// `mat1` should point to a valid 2DArray of `f64` floats in row-major order
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe extern "C" fn np_linalg_matrix_power(mat1: *mut InputMatrix, mat2: *mut InputMatrix, out: *mut InputMatrix) {
|
|
||||||
let mat1 = mat1.as_mut().unwrap();
|
|
||||||
let mat2 = mat2.as_mut().unwrap();
|
|
||||||
let out = out.as_mut().unwrap();
|
|
||||||
|
|
||||||
if mat1.ndims != 2 {
|
|
||||||
artiq_raise!(
|
|
||||||
"ValueError",
|
|
||||||
"expected 2D Vector Input, but received {1}D input)",
|
|
||||||
0,
|
|
||||||
mat1.ndims as i64,
|
|
||||||
0
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let dim1 = (*mat1).get_dims();
|
|
||||||
let power = unsafe { slice::from_raw_parts_mut(mat2.data, 1) };
|
|
||||||
let power = power[0];
|
|
||||||
let outdim = out.get_dims();
|
|
||||||
let out_slice = unsafe { slice::from_raw_parts_mut(out.data, outdim[0] * outdim[1]) };
|
|
||||||
let data_slice1 = unsafe { slice::from_raw_parts_mut(mat1.data, dim1[0] * dim1[1]) };
|
|
||||||
let mut abs_power = power;
|
|
||||||
if abs_power < 0.0 {
|
|
||||||
abs_power = abs_power * -1.0;
|
|
||||||
}
|
|
||||||
let matrix1 = DMatrix::from_row_slice(dim1[0], dim1[1], data_slice1);
|
|
||||||
if !matrix1.is_square() {
|
|
||||||
artiq_raise!(
|
|
||||||
"ValueError",
|
|
||||||
"last 2 dimensions of the array must be square: {1} != {2}",
|
|
||||||
0,
|
|
||||||
dim1[0] as i64,
|
|
||||||
dim1[1] as i64
|
|
||||||
);
|
|
||||||
}
|
|
||||||
let mut result = matrix1.pow(abs_power as u32);
|
|
||||||
|
|
||||||
if power < 0.0 {
|
|
||||||
if !matrix1.is_invertible() {
|
|
||||||
artiq_raise!("LinAlgError", "no inverse for Singular Matrix");
|
|
||||||
}
|
|
||||||
result = result.try_inverse().unwrap();
|
|
||||||
}
|
|
||||||
out_slice.copy_from_slice(result.transpose().as_slice());
|
|
||||||
}
|
|
||||||
|
|
||||||
/// # Safety
|
|
||||||
///
|
|
||||||
/// `mat1` should point to a valid 2DArray of `f64` floats in row-major order
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe extern "C" fn np_linalg_det(mat1: *mut InputMatrix, out: *mut InputMatrix) {
|
|
||||||
let mat1 = mat1.as_mut().unwrap();
|
|
||||||
let out = out.as_mut().unwrap();
|
|
||||||
|
|
||||||
if mat1.ndims != 2 {
|
|
||||||
artiq_raise!(
|
|
||||||
"ValueError",
|
|
||||||
"expected 2D Vector Input, but received {1}D input)",
|
|
||||||
0,
|
|
||||||
mat1.ndims as i64,
|
|
||||||
0
|
|
||||||
);
|
|
||||||
}
|
|
||||||
let dim1 = (*mat1).get_dims();
|
|
||||||
let out_slice = unsafe { slice::from_raw_parts_mut(out.data, 1) };
|
|
||||||
let data_slice1 = unsafe { slice::from_raw_parts_mut(mat1.data, dim1[0] * dim1[1]) };
|
|
||||||
|
|
||||||
let matrix = DMatrix::from_row_slice(dim1[0], dim1[1], data_slice1);
|
|
||||||
if !matrix.is_square() {
|
|
||||||
artiq_raise!(
|
|
||||||
"ValueError",
|
|
||||||
"last 2 dimensions of the array must be square: {1} != {2}",
|
|
||||||
0,
|
|
||||||
dim1[0] as i64,
|
|
||||||
dim1[1] as i64
|
|
||||||
);
|
|
||||||
}
|
|
||||||
out_slice[0] = matrix.determinant();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// # Safety
|
|
||||||
///
|
|
||||||
/// `mat1` should point to a valid 2DArray of `f64` floats in row-major order
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe extern "C" fn sp_linalg_lu(mat1: *mut InputMatrix, out_l: *mut InputMatrix, out_u: *mut InputMatrix) {
|
|
||||||
let mat1 = mat1.as_mut().unwrap();
|
|
||||||
let out_l = out_l.as_mut().unwrap();
|
|
||||||
let out_u = out_u.as_mut().unwrap();
|
|
||||||
|
|
||||||
if mat1.ndims != 2 {
|
|
||||||
artiq_raise!(
|
|
||||||
"ValueError",
|
|
||||||
"expected 2D Vector Input, but received {1}D input)",
|
|
||||||
0,
|
|
||||||
mat1.ndims as i64,
|
|
||||||
0
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let dim1 = (*mat1).get_dims();
|
|
||||||
let outl_dim = (*out_l).get_dims();
|
|
||||||
let outu_dim = (*out_u).get_dims();
|
|
||||||
|
|
||||||
let data_slice1 = unsafe { slice::from_raw_parts_mut(mat1.data, dim1[0] * dim1[1]) };
|
|
||||||
let out_l_slice = unsafe { slice::from_raw_parts_mut(out_l.data, outl_dim[0] * outl_dim[1]) };
|
|
||||||
let out_u_slice = unsafe { slice::from_raw_parts_mut(out_u.data, outu_dim[0] * outu_dim[1]) };
|
|
||||||
|
|
||||||
let matrix = DMatrix::from_row_slice(dim1[0], dim1[1], data_slice1);
|
|
||||||
let (_, l, u) = matrix.lu().unpack();
|
|
||||||
|
|
||||||
out_l_slice.copy_from_slice(l.transpose().as_slice());
|
|
||||||
out_u_slice.copy_from_slice(u.transpose().as_slice());
|
|
||||||
}
|
|
||||||
|
|
||||||
/// # Safety
|
|
||||||
///
|
|
||||||
/// `mat1` should point to a valid 2DArray of `f64` floats in row-major order
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe extern "C" fn sp_linalg_schur(mat1: *mut InputMatrix, out_t: *mut InputMatrix, out_z: *mut InputMatrix) {
|
|
||||||
let mat1 = mat1.as_mut().unwrap();
|
|
||||||
let out_t = out_t.as_mut().unwrap();
|
|
||||||
let out_z = out_z.as_mut().unwrap();
|
|
||||||
|
|
||||||
if mat1.ndims != 2 {
|
|
||||||
artiq_raise!(
|
|
||||||
"ValueError",
|
|
||||||
"expected 2D Vector Input, but received {1}D input)",
|
|
||||||
0,
|
|
||||||
mat1.ndims as i64,
|
|
||||||
0
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let dim1 = (*mat1).get_dims();
|
|
||||||
|
|
||||||
if dim1[0] != dim1[1] {
|
|
||||||
artiq_raise!(
|
|
||||||
"ValueError",
|
|
||||||
"last 2 dimensions of the array must be square: {1} != {2}",
|
|
||||||
0,
|
|
||||||
dim1[0] as i64,
|
|
||||||
dim1[1] as i64
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let out_t_dim = (*out_t).get_dims();
|
|
||||||
let out_z_dim = (*out_z).get_dims();
|
|
||||||
|
|
||||||
let data_slice1 = unsafe { slice::from_raw_parts_mut(mat1.data, dim1[0] * dim1[1]) };
|
|
||||||
let out_t_slice = unsafe { slice::from_raw_parts_mut(out_t.data, out_t_dim[0] * out_t_dim[1]) };
|
|
||||||
let out_z_slice = unsafe { slice::from_raw_parts_mut(out_z.data, out_z_dim[0] * out_z_dim[1]) };
|
|
||||||
|
|
||||||
let matrix = DMatrix::from_row_slice(dim1[0], dim1[1], data_slice1);
|
|
||||||
let (z, t) = matrix.schur().unpack();
|
|
||||||
|
|
||||||
out_t_slice.copy_from_slice(t.transpose().as_slice());
|
|
||||||
out_z_slice.copy_from_slice(z.transpose().as_slice());
|
|
||||||
}
|
|
||||||
|
|
||||||
/// # Safety
|
|
||||||
///
|
|
||||||
/// `mat1` should point to a valid 2DArray of `f64` floats in row-major order
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe extern "C" fn sp_linalg_hessenberg(
|
|
||||||
mat1: *mut InputMatrix,
|
|
||||||
out_h: *mut InputMatrix,
|
|
||||||
out_q: *mut InputMatrix,
|
|
||||||
) {
|
|
||||||
let mat1 = mat1.as_mut().unwrap();
|
|
||||||
let out_h = out_h.as_mut().unwrap();
|
|
||||||
let out_q = out_q.as_mut().unwrap();
|
|
||||||
|
|
||||||
if mat1.ndims != 2 {
|
|
||||||
artiq_raise!(
|
|
||||||
"ValueError",
|
|
||||||
"expected 2D Vector Input, but received {1}D input)",
|
|
||||||
0,
|
|
||||||
mat1.ndims as i64,
|
|
||||||
0
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let dim1 = (*mat1).get_dims();
|
|
||||||
|
|
||||||
if dim1[0] != dim1[1] {
|
|
||||||
artiq_raise!(
|
|
||||||
"ValueError",
|
|
||||||
"last 2 dimensions of the array must be square: {1} != {2}",
|
|
||||||
0,
|
|
||||||
dim1[0] as i64,
|
|
||||||
dim1[1] as i64
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let out_h_dim = (*out_h).get_dims();
|
|
||||||
let out_q_dim = (*out_q).get_dims();
|
|
||||||
|
|
||||||
let data_slice1 = unsafe { slice::from_raw_parts_mut(mat1.data, dim1[0] * dim1[1]) };
|
|
||||||
let out_h_slice = unsafe { slice::from_raw_parts_mut(out_h.data, out_h_dim[0] * out_h_dim[1]) };
|
|
||||||
let out_q_slice = unsafe { slice::from_raw_parts_mut(out_q.data, out_q_dim[0] * out_q_dim[1]) };
|
|
||||||
|
|
||||||
let matrix = DMatrix::from_row_slice(dim1[0], dim1[1], data_slice1);
|
|
||||||
let (q, h) = matrix.hessenberg().unpack();
|
|
||||||
|
|
||||||
out_h_slice.copy_from_slice(h.transpose().as_slice());
|
|
||||||
out_q_slice.copy_from_slice(q.transpose().as_slice());
|
|
||||||
}
|
|
|
@ -13,7 +13,6 @@ mod dma;
|
||||||
mod rpc;
|
mod rpc;
|
||||||
pub use dma::DmaRecorder;
|
pub use dma::DmaRecorder;
|
||||||
mod cache;
|
mod cache;
|
||||||
mod linalg;
|
|
||||||
#[cfg(has_drtio)]
|
#[cfg(has_drtio)]
|
||||||
mod subkernel;
|
mod subkernel;
|
||||||
|
|
||||||
|
@ -24,7 +23,6 @@ pub enum SubkernelStatus {
|
||||||
Timeout,
|
Timeout,
|
||||||
IncorrectState,
|
IncorrectState,
|
||||||
CommLost,
|
CommLost,
|
||||||
Exception(Vec<u8>),
|
|
||||||
OtherError,
|
OtherError,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,7 +77,6 @@ pub enum Message {
|
||||||
#[cfg(has_drtio)]
|
#[cfg(has_drtio)]
|
||||||
SubkernelLoadRunRequest {
|
SubkernelLoadRunRequest {
|
||||||
id: u32,
|
id: u32,
|
||||||
destination: u8,
|
|
||||||
run: bool,
|
run: bool,
|
||||||
},
|
},
|
||||||
#[cfg(has_drtio)]
|
#[cfg(has_drtio)]
|
||||||
|
@ -89,30 +86,30 @@ pub enum Message {
|
||||||
#[cfg(has_drtio)]
|
#[cfg(has_drtio)]
|
||||||
SubkernelAwaitFinishRequest {
|
SubkernelAwaitFinishRequest {
|
||||||
id: u32,
|
id: u32,
|
||||||
timeout: i64,
|
timeout: u64,
|
||||||
},
|
},
|
||||||
#[cfg(has_drtio)]
|
#[cfg(has_drtio)]
|
||||||
SubkernelAwaitFinishReply,
|
SubkernelAwaitFinishReply {
|
||||||
|
status: SubkernelStatus,
|
||||||
|
},
|
||||||
#[cfg(has_drtio)]
|
#[cfg(has_drtio)]
|
||||||
SubkernelMsgSend {
|
SubkernelMsgSend {
|
||||||
id: u32,
|
id: u32,
|
||||||
destination: Option<u8>,
|
|
||||||
data: Vec<u8>,
|
data: Vec<u8>,
|
||||||
},
|
},
|
||||||
#[cfg(has_drtio)]
|
#[cfg(has_drtio)]
|
||||||
SubkernelMsgSent,
|
SubkernelMsgSent,
|
||||||
#[cfg(has_drtio)]
|
#[cfg(has_drtio)]
|
||||||
SubkernelMsgRecvRequest {
|
SubkernelMsgRecvRequest {
|
||||||
id: i32,
|
id: u32,
|
||||||
timeout: i64,
|
timeout: u64,
|
||||||
tags: Vec<u8>,
|
tags: Vec<u8>,
|
||||||
},
|
},
|
||||||
#[cfg(has_drtio)]
|
#[cfg(has_drtio)]
|
||||||
SubkernelMsgRecvReply {
|
SubkernelMsgRecvReply {
|
||||||
|
status: SubkernelStatus,
|
||||||
count: u8,
|
count: u8,
|
||||||
},
|
},
|
||||||
#[cfg(has_drtio)]
|
|
||||||
SubkernelError(SubkernelStatus),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static CHANNEL_0TO1: Mutex<Option<sync_channel::Sender<'static, Message>>> = Mutex::new(None);
|
static CHANNEL_0TO1: Mutex<Option<sync_channel::Sender<'static, Message>>> = Mutex::new(None);
|
||||||
|
|
|
@ -3,18 +3,14 @@ use alloc::vec::Vec;
|
||||||
use cslice::CSlice;
|
use cslice::CSlice;
|
||||||
|
|
||||||
use super::{Message, SubkernelStatus, KERNEL_CHANNEL_0TO1, KERNEL_CHANNEL_1TO0};
|
use super::{Message, SubkernelStatus, KERNEL_CHANNEL_0TO1, KERNEL_CHANNEL_1TO0};
|
||||||
use crate::{artiq_raise, eh_artiq, rpc::send_args};
|
use crate::{artiq_raise, rpc::send_args};
|
||||||
|
|
||||||
pub extern "C" fn load_run(id: u32, destination: u8, run: bool) {
|
pub extern "C" fn load_run(id: u32, run: bool) {
|
||||||
unsafe {
|
unsafe {
|
||||||
KERNEL_CHANNEL_1TO0
|
KERNEL_CHANNEL_1TO0
|
||||||
.as_mut()
|
.as_mut()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.send(Message::SubkernelLoadRunRequest {
|
.send(Message::SubkernelLoadRunRequest { id: id, run: run });
|
||||||
id: id,
|
|
||||||
destination: destination,
|
|
||||||
run: run,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
match unsafe { KERNEL_CHANNEL_0TO1.as_mut().unwrap() }.recv() {
|
match unsafe { KERNEL_CHANNEL_0TO1.as_mut().unwrap() }.recv() {
|
||||||
Message::SubkernelLoadRunReply { succeeded: true } => (),
|
Message::SubkernelLoadRunReply { succeeded: true } => (),
|
||||||
|
@ -25,7 +21,7 @@ pub extern "C" fn load_run(id: u32, destination: u8, run: bool) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub extern "C" fn await_finish(id: u32, timeout: i64) {
|
pub extern "C" fn await_finish(id: u32, timeout: u64) {
|
||||||
unsafe {
|
unsafe {
|
||||||
KERNEL_CHANNEL_1TO0
|
KERNEL_CHANNEL_1TO0
|
||||||
.as_mut()
|
.as_mut()
|
||||||
|
@ -36,30 +32,26 @@ pub extern "C" fn await_finish(id: u32, timeout: i64) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
match unsafe { KERNEL_CHANNEL_0TO1.as_mut().unwrap() }.recv() {
|
match unsafe { KERNEL_CHANNEL_0TO1.as_mut().unwrap() }.recv() {
|
||||||
Message::SubkernelAwaitFinishReply => (),
|
Message::SubkernelAwaitFinishReply {
|
||||||
Message::SubkernelError(SubkernelStatus::IncorrectState) => {
|
status: SubkernelStatus::NoError,
|
||||||
artiq_raise!("SubkernelError", "Subkernel not running")
|
} => (),
|
||||||
}
|
Message::SubkernelAwaitFinishReply {
|
||||||
Message::SubkernelError(SubkernelStatus::Timeout) => artiq_raise!("SubkernelError", "Subkernel timed out"),
|
status: SubkernelStatus::IncorrectState,
|
||||||
Message::SubkernelError(SubkernelStatus::CommLost) => {
|
} => artiq_raise!("SubkernelError", "Subkernel not running"),
|
||||||
artiq_raise!("SubkernelError", "Lost communication with satellite")
|
Message::SubkernelAwaitFinishReply {
|
||||||
}
|
status: SubkernelStatus::Timeout,
|
||||||
Message::SubkernelError(SubkernelStatus::OtherError) => {
|
} => artiq_raise!("SubkernelError", "Subkernel timed out"),
|
||||||
artiq_raise!("SubkernelError", "An error occurred during subkernel operation")
|
Message::SubkernelAwaitFinishReply {
|
||||||
}
|
status: SubkernelStatus::CommLost,
|
||||||
Message::SubkernelError(SubkernelStatus::Exception(raw_exception)) => eh_artiq::raise_raw(&raw_exception),
|
} => artiq_raise!("SubkernelError", "Lost communication with satellite"),
|
||||||
|
Message::SubkernelAwaitFinishReply {
|
||||||
|
status: SubkernelStatus::OtherError,
|
||||||
|
} => artiq_raise!("SubkernelError", "An error occurred during subkernel operation"),
|
||||||
_ => panic!("expected SubkernelAwaitFinishReply after SubkernelAwaitFinishRequest"),
|
_ => panic!("expected SubkernelAwaitFinishReply after SubkernelAwaitFinishRequest"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub extern "C" fn send_message(
|
pub extern "C" fn send_message(id: u32, count: u8, tag: &CSlice<u8>, data: *const *const ()) {
|
||||||
id: u32,
|
|
||||||
is_return: bool,
|
|
||||||
destination: u8,
|
|
||||||
count: u8,
|
|
||||||
tag: &CSlice<u8>,
|
|
||||||
data: *const *const (),
|
|
||||||
) {
|
|
||||||
let mut buffer = Vec::<u8>::new();
|
let mut buffer = Vec::<u8>::new();
|
||||||
send_args(&mut buffer, 0, tag.as_ref(), data, false).expect("RPC encoding failed");
|
send_args(&mut buffer, 0, tag.as_ref(), data, false).expect("RPC encoding failed");
|
||||||
// overwrite service tag, include how many tags are in the message
|
// overwrite service tag, include how many tags are in the message
|
||||||
|
@ -67,7 +59,6 @@ pub extern "C" fn send_message(
|
||||||
unsafe {
|
unsafe {
|
||||||
KERNEL_CHANNEL_1TO0.as_mut().unwrap().send(Message::SubkernelMsgSend {
|
KERNEL_CHANNEL_1TO0.as_mut().unwrap().send(Message::SubkernelMsgSend {
|
||||||
id: id,
|
id: id,
|
||||||
destination: if is_return { None } else { Some(destination) },
|
|
||||||
data: buffer[3..].to_vec(),
|
data: buffer[3..].to_vec(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -77,7 +68,7 @@ pub extern "C" fn send_message(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub extern "C" fn await_message(id: i32, timeout: i64, tags: &CSlice<u8>, min: u8, max: u8) {
|
pub extern "C" fn await_message(id: u32, timeout: u64, tags: &CSlice<u8>, min: u8, max: u8) {
|
||||||
unsafe {
|
unsafe {
|
||||||
KERNEL_CHANNEL_1TO0
|
KERNEL_CHANNEL_1TO0
|
||||||
.as_mut()
|
.as_mut()
|
||||||
|
@ -89,22 +80,30 @@ pub extern "C" fn await_message(id: i32, timeout: i64, tags: &CSlice<u8>, min: u
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
match unsafe { KERNEL_CHANNEL_0TO1.as_mut().unwrap() }.recv() {
|
match unsafe { KERNEL_CHANNEL_0TO1.as_mut().unwrap() }.recv() {
|
||||||
Message::SubkernelMsgRecvReply { count } => {
|
Message::SubkernelMsgRecvReply {
|
||||||
|
status: SubkernelStatus::NoError,
|
||||||
|
count,
|
||||||
|
} => {
|
||||||
if min > count || count > max {
|
if min > count || count > max {
|
||||||
artiq_raise!("SubkernelError", "Received more or less arguments than required")
|
artiq_raise!("SubkernelError", "Received more or less arguments than required")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Message::SubkernelError(SubkernelStatus::IncorrectState) => {
|
Message::SubkernelMsgRecvReply {
|
||||||
artiq_raise!("SubkernelError", "Subkernel not running")
|
status: SubkernelStatus::IncorrectState,
|
||||||
}
|
..
|
||||||
Message::SubkernelError(SubkernelStatus::Timeout) => artiq_raise!("SubkernelError", "Subkernel timed out"),
|
} => artiq_raise!("SubkernelError", "Subkernel not running"),
|
||||||
Message::SubkernelError(SubkernelStatus::CommLost) => {
|
Message::SubkernelMsgRecvReply {
|
||||||
artiq_raise!("SubkernelError", "Lost communication with satellite")
|
status: SubkernelStatus::Timeout,
|
||||||
}
|
..
|
||||||
Message::SubkernelError(SubkernelStatus::OtherError) => {
|
} => artiq_raise!("SubkernelError", "Subkernel timed out"),
|
||||||
artiq_raise!("SubkernelError", "An error occurred during subkernel operation")
|
Message::SubkernelMsgRecvReply {
|
||||||
}
|
status: SubkernelStatus::CommLost,
|
||||||
Message::SubkernelError(SubkernelStatus::Exception(raw_exception)) => eh_artiq::raise_raw(&raw_exception),
|
..
|
||||||
|
} => artiq_raise!("SubkernelError", "Lost communication with satellite"),
|
||||||
|
Message::SubkernelMsgRecvReply {
|
||||||
|
status: SubkernelStatus::OtherError,
|
||||||
|
..
|
||||||
|
} => artiq_raise!("SubkernelError", "An error occurred during subkernel operation"),
|
||||||
_ => panic!("expected SubkernelMsgRecvReply after SubkernelMsgRecvRequest"),
|
_ => panic!("expected SubkernelMsgRecvReply after SubkernelMsgRecvRequest"),
|
||||||
}
|
}
|
||||||
// RpcRecvRequest should be called after this to receive message data
|
// RpcRecvRequest should be called after this to receive message data
|
||||||
|
|
|
@ -41,7 +41,3 @@ libc = { path = "../libc" }
|
||||||
io = { path = "../libio", features = ["alloc"] }
|
io = { path = "../libio", features = ["alloc"] }
|
||||||
ksupport = { path = "../libksupport" }
|
ksupport = { path = "../libksupport" }
|
||||||
libboard_artiq = { path = "../libboard_artiq" }
|
libboard_artiq = { path = "../libboard_artiq" }
|
||||||
|
|
||||||
[dependencies.tar-no-std]
|
|
||||||
git = "https://git.m-labs.hk/M-Labs/tar-no-std"
|
|
||||||
rev = "2ab6dc5"
|
|
|
@ -60,7 +60,7 @@ pub mod remote_analyzer {
|
||||||
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,
|
||||||
) -> Result<RemoteBuffer, drtio::Error> {
|
) -> Result<RemoteBuffer, &'static str> {
|
||||||
// gets data from satellites and returns consolidated data
|
// gets data from satellites and returns consolidated data
|
||||||
let mut remote_data: Vec<u8> = Vec::new();
|
let mut remote_data: Vec<u8> = Vec::new();
|
||||||
let mut remote_error = false;
|
let mut remote_error = false;
|
||||||
|
|
|
@ -3,22 +3,17 @@ use core::{cell::RefCell, fmt, slice, str};
|
||||||
|
|
||||||
use core_io::Error as IoError;
|
use core_io::Error as IoError;
|
||||||
use cslice::CSlice;
|
use cslice::CSlice;
|
||||||
use dyld::elf;
|
|
||||||
use futures::{future::FutureExt, select_biased};
|
use futures::{future::FutureExt, select_biased};
|
||||||
#[cfg(has_drtio)]
|
#[cfg(has_drtio)]
|
||||||
use io::Cursor;
|
use io::Cursor;
|
||||||
#[cfg(has_drtio)]
|
#[cfg(has_drtio)]
|
||||||
use ksupport::rpc;
|
use ksupport::rpc;
|
||||||
use ksupport::{kernel, resolve_channel_name};
|
use ksupport::{kernel, resolve_channel_name};
|
||||||
#[cfg(has_drtio)]
|
|
||||||
use libasync::delay;
|
|
||||||
use libasync::{smoltcp::{Sockets, TcpStream},
|
use libasync::{smoltcp::{Sockets, TcpStream},
|
||||||
task};
|
task};
|
||||||
use libboard_artiq::drtio_routing;
|
use libboard_artiq::drtio_routing;
|
||||||
#[cfg(feature = "target_kasli_soc")]
|
#[cfg(feature = "target_kasli_soc")]
|
||||||
use libboard_zynq::error_led::ErrorLED;
|
use libboard_zynq::error_led::ErrorLED;
|
||||||
#[cfg(has_drtio)]
|
|
||||||
use libboard_zynq::time::Milliseconds;
|
|
||||||
use libboard_zynq::{self as zynq,
|
use libboard_zynq::{self as zynq,
|
||||||
smoltcp::{self,
|
smoltcp::{self,
|
||||||
iface::{EthernetInterfaceBuilder, NeighborCache},
|
iface::{EthernetInterfaceBuilder, NeighborCache},
|
||||||
|
@ -32,8 +27,6 @@ use libcortex_a9::{mutex::Mutex,
|
||||||
use log::{error, info, warn};
|
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};
|
||||||
#[cfg(has_drtio)]
|
|
||||||
use tar_no_std::TarArchiveRef;
|
|
||||||
|
|
||||||
#[cfg(has_drtio)]
|
#[cfg(has_drtio)]
|
||||||
use crate::pl;
|
use crate::pl;
|
||||||
|
@ -50,8 +43,6 @@ pub enum Error {
|
||||||
BufferExhausted,
|
BufferExhausted,
|
||||||
#[cfg(has_drtio)]
|
#[cfg(has_drtio)]
|
||||||
SubkernelError(subkernel::Error),
|
SubkernelError(subkernel::Error),
|
||||||
#[cfg(has_drtio)]
|
|
||||||
DestinationDown,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type Result<T> = core::result::Result<T, Error>;
|
pub type Result<T> = core::result::Result<T, Error>;
|
||||||
|
@ -66,8 +57,6 @@ impl fmt::Display for Error {
|
||||||
Error::BufferExhausted => write!(f, "buffer exhausted"),
|
Error::BufferExhausted => write!(f, "buffer exhausted"),
|
||||||
#[cfg(has_drtio)]
|
#[cfg(has_drtio)]
|
||||||
Error::SubkernelError(error) => write!(f, "subkernel error: {:?}", error),
|
Error::SubkernelError(error) => write!(f, "subkernel error: {:?}", error),
|
||||||
#[cfg(has_drtio)]
|
|
||||||
Error::DestinationDown => write!(f, "subkernel destination down"),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -401,11 +390,7 @@ async fn handle_run_kernel(
|
||||||
control.borrow_mut().tx.async_send(reply).await;
|
control.borrow_mut().tx.async_send(reply).await;
|
||||||
}
|
}
|
||||||
#[cfg(has_drtio)]
|
#[cfg(has_drtio)]
|
||||||
kernel::Message::SubkernelLoadRunRequest {
|
kernel::Message::SubkernelLoadRunRequest { id, run } => {
|
||||||
id,
|
|
||||||
destination: _,
|
|
||||||
run,
|
|
||||||
} => {
|
|
||||||
let succeeded = match subkernel::load(aux_mutex, routing_table, timer, id, run).await {
|
let succeeded = match subkernel::load(aux_mutex, routing_table, timer, id, run).await {
|
||||||
Ok(()) => true,
|
Ok(()) => true,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
@ -422,28 +407,37 @@ async fn handle_run_kernel(
|
||||||
#[cfg(has_drtio)]
|
#[cfg(has_drtio)]
|
||||||
kernel::Message::SubkernelAwaitFinishRequest { id, timeout } => {
|
kernel::Message::SubkernelAwaitFinishRequest { id, timeout } => {
|
||||||
let res = subkernel::await_finish(aux_mutex, routing_table, timer, id, timeout).await;
|
let res = subkernel::await_finish(aux_mutex, routing_table, timer, id, timeout).await;
|
||||||
let response = match res {
|
let status = match res {
|
||||||
Ok(res) => {
|
Ok(ref res) => {
|
||||||
if res.status == subkernel::FinishStatus::CommLost {
|
if res.status == subkernel::FinishStatus::CommLost {
|
||||||
kernel::Message::SubkernelError(kernel::SubkernelStatus::CommLost)
|
kernel::SubkernelStatus::CommLost
|
||||||
} else if let Some(exception) = res.exception {
|
} else if let Some(exception) = &res.exception {
|
||||||
kernel::Message::SubkernelError(kernel::SubkernelStatus::Exception(exception))
|
error!("Exception in subkernel");
|
||||||
|
match stream {
|
||||||
|
None => (),
|
||||||
|
Some(stream) => {
|
||||||
|
write_chunk(stream, exception).await?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// will not be called after exception is served
|
||||||
|
kernel::SubkernelStatus::OtherError
|
||||||
} else {
|
} else {
|
||||||
kernel::Message::SubkernelAwaitFinishReply
|
kernel::SubkernelStatus::NoError
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(SubkernelError::Timeout) => kernel::Message::SubkernelError(kernel::SubkernelStatus::Timeout),
|
Err(SubkernelError::Timeout) => kernel::SubkernelStatus::Timeout,
|
||||||
Err(SubkernelError::IncorrectState) => {
|
Err(SubkernelError::IncorrectState) => kernel::SubkernelStatus::IncorrectState,
|
||||||
kernel::Message::SubkernelError(kernel::SubkernelStatus::IncorrectState)
|
Err(_) => kernel::SubkernelStatus::OtherError,
|
||||||
}
|
|
||||||
Err(_) => kernel::Message::SubkernelError(kernel::SubkernelStatus::OtherError),
|
|
||||||
};
|
};
|
||||||
control.borrow_mut().tx.async_send(response).await;
|
control
|
||||||
|
.borrow_mut()
|
||||||
|
.tx
|
||||||
|
.async_send(kernel::Message::SubkernelAwaitFinishReply { status: status })
|
||||||
|
.await;
|
||||||
}
|
}
|
||||||
#[cfg(has_drtio)]
|
#[cfg(has_drtio)]
|
||||||
kernel::Message::SubkernelMsgSend { id, destination, data } => {
|
kernel::Message::SubkernelMsgSend { id, data } => {
|
||||||
let res =
|
let res = subkernel::message_send(aux_mutex, routing_table, timer, id, data).await;
|
||||||
subkernel::message_send(aux_mutex, routing_table, timer, id, destination.unwrap(), data).await;
|
|
||||||
match res {
|
match res {
|
||||||
Ok(_) => (),
|
Ok(_) => (),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
@ -458,24 +452,22 @@ async fn handle_run_kernel(
|
||||||
}
|
}
|
||||||
#[cfg(has_drtio)]
|
#[cfg(has_drtio)]
|
||||||
kernel::Message::SubkernelMsgRecvRequest { id, timeout, tags } => {
|
kernel::Message::SubkernelMsgRecvRequest { id, timeout, tags } => {
|
||||||
let message_received = subkernel::message_await(id as u32, timeout, timer).await;
|
let message_received = subkernel::message_await(id, timeout, timer).await;
|
||||||
let response = match message_received {
|
let (status, count) = match message_received {
|
||||||
Ok(ref message) => kernel::Message::SubkernelMsgRecvReply { count: message.count },
|
Ok(ref message) => (kernel::SubkernelStatus::NoError, message.count),
|
||||||
Err(SubkernelError::Timeout) => kernel::Message::SubkernelError(kernel::SubkernelStatus::Timeout),
|
Err(SubkernelError::Timeout) => (kernel::SubkernelStatus::Timeout, 0),
|
||||||
Err(SubkernelError::IncorrectState) => {
|
Err(SubkernelError::IncorrectState) => (kernel::SubkernelStatus::IncorrectState, 0),
|
||||||
kernel::Message::SubkernelError(kernel::SubkernelStatus::IncorrectState)
|
Err(SubkernelError::CommLost) => (kernel::SubkernelStatus::CommLost, 0),
|
||||||
}
|
Err(_) => (kernel::SubkernelStatus::OtherError, 0),
|
||||||
Err(SubkernelError::CommLost) => kernel::Message::SubkernelError(kernel::SubkernelStatus::CommLost),
|
|
||||||
Err(SubkernelError::SubkernelException) => {
|
|
||||||
// just retrieve the exception
|
|
||||||
let status = subkernel::await_finish(aux_mutex, routing_table, timer, id as u32, timeout)
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
kernel::Message::SubkernelError(kernel::SubkernelStatus::Exception(status.exception.unwrap()))
|
|
||||||
}
|
|
||||||
Err(_) => kernel::Message::SubkernelError(kernel::SubkernelStatus::OtherError),
|
|
||||||
};
|
};
|
||||||
control.borrow_mut().tx.async_send(response).await;
|
control
|
||||||
|
.borrow_mut()
|
||||||
|
.tx
|
||||||
|
.async_send(kernel::Message::SubkernelMsgRecvReply {
|
||||||
|
status: status,
|
||||||
|
count: count,
|
||||||
|
})
|
||||||
|
.await;
|
||||||
if let Ok(message) = message_received {
|
if let Ok(message) = message_received {
|
||||||
// receive code almost identical to RPC recv, except we are not reading from a stream
|
// receive code almost identical to RPC recv, except we are not reading from a stream
|
||||||
let mut reader = Cursor::new(message.data);
|
let mut reader = Cursor::new(message.data);
|
||||||
|
@ -507,7 +499,7 @@ async fn handle_run_kernel(
|
||||||
.async_send(kernel::Message::RpcRecvReply(Ok(0)))
|
.async_send(kernel::Message::RpcRecvReply(Ok(0)))
|
||||||
.await;
|
.await;
|
||||||
i += 1;
|
i += 1;
|
||||||
if i < message.count {
|
if i < count {
|
||||||
current_tags = remaining_tags;
|
current_tags = remaining_tags;
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
|
@ -532,56 +524,6 @@ async fn handle_run_kernel(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_flash_kernel(
|
|
||||||
buffer: &Vec<u8>,
|
|
||||||
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<()> {
|
|
||||||
if buffer[0] == elf::ELFMAG0 && buffer[1] == elf::ELFMAG1 && buffer[2] == elf::ELFMAG2 && buffer[3] == elf::ELFMAG3
|
|
||||||
{
|
|
||||||
// assume ELF file, proceed as before
|
|
||||||
load_kernel(buffer, control, None).await
|
|
||||||
} else {
|
|
||||||
#[cfg(has_drtio)]
|
|
||||||
{
|
|
||||||
let archive = TarArchiveRef::new(buffer.as_ref());
|
|
||||||
let entries = archive.entries();
|
|
||||||
let mut main_lib: Vec<u8> = Vec::new();
|
|
||||||
for entry in entries {
|
|
||||||
if entry.filename().as_str() == "main.elf" {
|
|
||||||
main_lib = entry.data().to_vec();
|
|
||||||
} else {
|
|
||||||
// subkernel filename must be in format:
|
|
||||||
// "<subkernel id> <destination>.elf"
|
|
||||||
let filename = entry.filename();
|
|
||||||
let mut iter = filename.as_str().split_whitespace();
|
|
||||||
let sid: u32 = iter.next().unwrap().parse().unwrap();
|
|
||||||
let dest: u8 = iter.next().unwrap().strip_suffix(".elf").unwrap().parse().unwrap();
|
|
||||||
let up = _up_destinations.borrow()[dest as usize];
|
|
||||||
if up {
|
|
||||||
let subkernel_lib = entry.data().to_vec();
|
|
||||||
subkernel::add_subkernel(sid, dest, subkernel_lib).await;
|
|
||||||
match subkernel::upload(_aux_mutex, _routing_table, _timer, sid).await {
|
|
||||||
Ok(_) => (),
|
|
||||||
Err(_) => return Err(Error::UnexpectedPattern),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return Err(Error::DestinationDown);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
load_kernel(&main_lib, control, None).await
|
|
||||||
}
|
|
||||||
#[cfg(not(has_drtio))]
|
|
||||||
{
|
|
||||||
panic!("multi-kernel libraries are not supported in standalone systems");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn load_kernel(
|
async fn load_kernel(
|
||||||
buffer: &Vec<u8>,
|
buffer: &Vec<u8>,
|
||||||
control: &Rc<RefCell<kernel::Control>>,
|
control: &Rc<RefCell<kernel::Control>>,
|
||||||
|
@ -696,27 +638,6 @@ async fn handle_connection(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn load_and_run_idle_kernel(
|
|
||||||
buffer: &Vec<u8>,
|
|
||||||
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,
|
|
||||||
) {
|
|
||||||
info!("Loading idle kernel");
|
|
||||||
let res = handle_flash_kernel(buffer, control, up_destinations, aux_mutex, routing_table, timer).await;
|
|
||||||
match res {
|
|
||||||
Err(_) => warn!("error loading idle kernel"),
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
info!("Running idle kernel");
|
|
||||||
let _ = handle_run_kernel(None, control, up_destinations, aux_mutex, routing_table, timer)
|
|
||||||
.await
|
|
||||||
.map_err(|_| warn!("error running idle kernel"));
|
|
||||||
info!("Idle kernel terminated");
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn main(timer: GlobalTimer, cfg: Config) {
|
pub fn main(timer: GlobalTimer, cfg: Config) {
|
||||||
let net_addresses = net_settings::get_addresses(&cfg);
|
let net_addresses = net_settings::get_addresses(&cfg);
|
||||||
info!("network addresses: {}", net_addresses);
|
info!("network addresses: {}", net_addresses);
|
||||||
|
@ -758,6 +679,7 @@ pub fn main(timer: GlobalTimer, cfg: Config) {
|
||||||
|
|
||||||
Sockets::init(32);
|
Sockets::init(32);
|
||||||
|
|
||||||
|
// 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(drtio_routing::config_routing_table(
|
||||||
|
@ -770,7 +692,7 @@ pub fn main(timer: GlobalTimer, cfg: Config) {
|
||||||
#[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, &cfg, timer);
|
rtio_mgt::startup(&aux_mutex, &drtio_routing_table, &up_destinations, timer);
|
||||||
ksupport::setup_device_map(&cfg);
|
ksupport::setup_device_map(&cfg);
|
||||||
|
|
||||||
analyzer::start(&aux_mutex, &drtio_routing_table, &up_destinations, timer);
|
analyzer::start(&aux_mutex, &drtio_routing_table, &up_destinations, timer);
|
||||||
|
@ -780,16 +702,9 @@ pub fn main(timer: GlobalTimer, cfg: Config) {
|
||||||
let idle_kernel = Rc::new(cfg.read("idle_kernel").ok());
|
let idle_kernel = Rc::new(cfg.read("idle_kernel").ok());
|
||||||
if let Ok(buffer) = cfg.read("startup_kernel") {
|
if let Ok(buffer) = cfg.read("startup_kernel") {
|
||||||
info!("Loading startup kernel...");
|
info!("Loading startup kernel...");
|
||||||
let routing_table = drtio_routing_table.borrow();
|
if let Ok(()) = task::block_on(load_kernel(&buffer, &control, None)) {
|
||||||
if let Ok(()) = task::block_on(handle_flash_kernel(
|
|
||||||
&buffer,
|
|
||||||
&control,
|
|
||||||
&up_destinations,
|
|
||||||
&aux_mutex,
|
|
||||||
&routing_table,
|
|
||||||
timer,
|
|
||||||
)) {
|
|
||||||
info!("Starting startup kernel...");
|
info!("Starting startup kernel...");
|
||||||
|
let routing_table = drtio_routing_table.borrow();
|
||||||
let _ = task::block_on(handle_run_kernel(
|
let _ = task::block_on(handle_run_kernel(
|
||||||
None,
|
None,
|
||||||
&control,
|
&control,
|
||||||
|
@ -807,30 +722,8 @@ pub fn main(timer: GlobalTimer, cfg: Config) {
|
||||||
mgmt::start(cfg);
|
mgmt::start(cfg);
|
||||||
|
|
||||||
task::spawn(async move {
|
task::spawn(async move {
|
||||||
let connection = Rc::new(Semaphore::new(0, 1));
|
let connection = Rc::new(Semaphore::new(1, 1));
|
||||||
let terminate = Rc::new(Semaphore::new(0, 1));
|
let terminate = Rc::new(Semaphore::new(0, 1));
|
||||||
{
|
|
||||||
let control = control.clone();
|
|
||||||
let idle_kernel = idle_kernel.clone();
|
|
||||||
let connection = connection.clone();
|
|
||||||
let terminate = terminate.clone();
|
|
||||||
let up_destinations = up_destinations.clone();
|
|
||||||
let aux_mutex = aux_mutex.clone();
|
|
||||||
let routing_table = drtio_routing_table.clone();
|
|
||||||
task::spawn(async move {
|
|
||||||
let routing_table = routing_table.borrow();
|
|
||||||
select_biased! {
|
|
||||||
_ = (async {
|
|
||||||
if let Some(buffer) = &*idle_kernel {
|
|
||||||
load_and_run_idle_kernel(&buffer, &control, &up_destinations, &aux_mutex, &routing_table, timer).await;
|
|
||||||
}
|
|
||||||
}).fuse() => (),
|
|
||||||
_ = terminate.async_wait().fuse() => ()
|
|
||||||
}
|
|
||||||
connection.signal();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let mut stream = TcpStream::accept(1381, 0x10_000, 0x10_000).await.unwrap();
|
let mut stream = TcpStream::accept(1381, 0x10_000, 0x10_000).await.unwrap();
|
||||||
|
|
||||||
|
@ -858,7 +751,13 @@ pub fn main(timer: GlobalTimer, cfg: Config) {
|
||||||
.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 {
|
||||||
load_and_run_idle_kernel(&buffer, &control, &up_destinations, &aux_mutex, &routing_table, timer).await;
|
info!("Loading idle kernel");
|
||||||
|
let _ = load_kernel(&buffer, &control, None)
|
||||||
|
.await.map_err(|_| warn!("error loading idle kernel"));
|
||||||
|
info!("Running idle kernel");
|
||||||
|
let _ = handle_run_kernel(None, &control, &up_destinations, &aux_mutex, &routing_table, timer)
|
||||||
|
.await.map_err(|_| warn!("error running idle kernel"));
|
||||||
|
info!("Idle kernel terminated");
|
||||||
}
|
}
|
||||||
}).fuse() => (),
|
}).fuse() => (),
|
||||||
_ = terminate.async_wait().fuse() => ()
|
_ = terminate.async_wait().fuse() => ()
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
#[cfg(all(feature = "target_kasli_soc", has_virtual_leds))]
|
#[cfg(feature = "target_kasli_soc")]
|
||||||
use core::cell::RefCell;
|
use core::cell::RefCell;
|
||||||
|
|
||||||
use ksupport;
|
use ksupport;
|
||||||
|
@ -21,7 +21,7 @@ use libboard_artiq::{identifier_read, logger, pl};
|
||||||
use libboard_zynq::{gic, mpcore, timer::GlobalTimer};
|
use libboard_zynq::{gic, mpcore, timer::GlobalTimer};
|
||||||
use libconfig::Config;
|
use libconfig::Config;
|
||||||
use libcortex_a9::l2c::enable_l2_cache;
|
use libcortex_a9::l2c::enable_l2_cache;
|
||||||
use libsupport_zynq::{exception_vectors, ram};
|
use libsupport_zynq::ram;
|
||||||
use log::{info, warn};
|
use log::{info, warn};
|
||||||
|
|
||||||
mod analyzer;
|
mod analyzer;
|
||||||
|
@ -38,12 +38,7 @@ mod rtio_mgt;
|
||||||
#[cfg(has_drtio)]
|
#[cfg(has_drtio)]
|
||||||
mod subkernel;
|
mod subkernel;
|
||||||
|
|
||||||
// linker symbols
|
#[cfg(feature = "target_kasli_soc")]
|
||||||
extern "C" {
|
|
||||||
static __exceptions_start: u32;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(all(feature = "target_kasli_soc", has_virtual_leds))]
|
|
||||||
async fn io_expanders_service(
|
async fn io_expanders_service(
|
||||||
i2c_bus: RefCell<&mut libboard_zynq::i2c::I2c>,
|
i2c_bus: RefCell<&mut libboard_zynq::i2c::I2c>,
|
||||||
io_expander0: RefCell<io_expander::IoExpander>,
|
io_expander0: RefCell<io_expander::IoExpander>,
|
||||||
|
@ -82,9 +77,6 @@ static mut LOG_BUFFER: [u8; 1 << 17] = [0; 1 << 17];
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub fn main_core0() {
|
pub fn main_core0() {
|
||||||
unsafe {
|
|
||||||
exception_vectors::set_vector_table(&__exceptions_start as *const u32 as u32);
|
|
||||||
}
|
|
||||||
enable_l2_cache(0x8);
|
enable_l2_cache(0x8);
|
||||||
let mut timer = GlobalTimer::start();
|
let mut timer = GlobalTimer::start();
|
||||||
|
|
||||||
|
@ -102,21 +94,20 @@ pub fn main_core0() {
|
||||||
|
|
||||||
ksupport::i2c::init();
|
ksupport::i2c::init();
|
||||||
#[cfg(feature = "target_kasli_soc")]
|
#[cfg(feature = "target_kasli_soc")]
|
||||||
|
let i2c_bus = unsafe { (ksupport::i2c::I2C_BUS).as_mut().unwrap() };
|
||||||
|
|
||||||
|
#[cfg(feature = "target_kasli_soc")]
|
||||||
|
let (mut io_expander0, mut io_expander1);
|
||||||
|
#[cfg(feature = "target_kasli_soc")]
|
||||||
{
|
{
|
||||||
let i2c_bus = unsafe { (ksupport::i2c::I2C_BUS).as_mut().unwrap() };
|
io_expander0 = io_expander::IoExpander::new(i2c_bus, 0).unwrap();
|
||||||
let mut io_expander0 = io_expander::IoExpander::new(i2c_bus, 0).unwrap();
|
io_expander1 = io_expander::IoExpander::new(i2c_bus, 1).unwrap();
|
||||||
let mut io_expander1 = io_expander::IoExpander::new(i2c_bus, 1).unwrap();
|
|
||||||
io_expander0
|
io_expander0
|
||||||
.init(i2c_bus)
|
.init(i2c_bus)
|
||||||
.expect("I2C I/O expander #0 initialization failed");
|
.expect("I2C I/O expander #0 initialization failed");
|
||||||
io_expander1
|
io_expander1
|
||||||
.init(i2c_bus)
|
.init(i2c_bus)
|
||||||
.expect("I2C I/O expander #1 initialization failed");
|
.expect("I2C I/O expander #1 initialization failed");
|
||||||
|
|
||||||
// Drive CLK_SEL to true
|
|
||||||
#[cfg(has_si549)]
|
|
||||||
io_expander0.set(1, 7, true);
|
|
||||||
|
|
||||||
// Drive TX_DISABLE to false on SFP0..3
|
// Drive TX_DISABLE to false on SFP0..3
|
||||||
io_expander0.set(0, 1, false);
|
io_expander0.set(0, 1, false);
|
||||||
io_expander1.set(0, 1, false);
|
io_expander1.set(0, 1, false);
|
||||||
|
@ -124,12 +115,6 @@ pub fn main_core0() {
|
||||||
io_expander1.set(1, 1, false);
|
io_expander1.set(1, 1, false);
|
||||||
io_expander0.service(i2c_bus).unwrap();
|
io_expander0.service(i2c_bus).unwrap();
|
||||||
io_expander1.service(i2c_bus).unwrap();
|
io_expander1.service(i2c_bus).unwrap();
|
||||||
#[cfg(has_virtual_leds)]
|
|
||||||
task::spawn(io_expanders_service(
|
|
||||||
RefCell::new(i2c_bus),
|
|
||||||
RefCell::new(io_expander0),
|
|
||||||
RefCell::new(io_expander1),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let cfg = match Config::new() {
|
let cfg = match Config::new() {
|
||||||
|
@ -150,5 +135,11 @@ pub fn main_core0() {
|
||||||
|
|
||||||
task::spawn(ksupport::report_async_rtio_errors());
|
task::spawn(ksupport::report_async_rtio_errors());
|
||||||
|
|
||||||
|
#[cfg(feature = "target_kasli_soc")]
|
||||||
|
task::spawn(io_expanders_service(
|
||||||
|
RefCell::new(i2c_bus),
|
||||||
|
RefCell::new(io_expander0),
|
||||||
|
RefCell::new(io_expander1),
|
||||||
|
));
|
||||||
comms::main(timer, cfg);
|
comms::main(timer, cfg);
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,11 +58,10 @@ mod remote_moninj {
|
||||||
use log::error;
|
use log::error;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::rtio_mgt::{drtio, drtio::Error as DrtioError};
|
use crate::rtio_mgt::drtio;
|
||||||
|
|
||||||
pub async fn read_probe(
|
pub async fn read_probe(
|
||||||
aux_mutex: &Rc<Mutex<bool>>,
|
aux_mutex: &Rc<Mutex<bool>>,
|
||||||
routing_table: &drtio_routing::RoutingTable,
|
|
||||||
timer: GlobalTimer,
|
timer: GlobalTimer,
|
||||||
linkno: u8,
|
linkno: u8,
|
||||||
destination: u8,
|
destination: u8,
|
||||||
|
@ -72,7 +71,6 @@ mod remote_moninj {
|
||||||
let reply = drtio::aux_transact(
|
let reply = drtio::aux_transact(
|
||||||
aux_mutex,
|
aux_mutex,
|
||||||
linkno,
|
linkno,
|
||||||
routing_table,
|
|
||||||
&drtioaux_async::Packet::MonitorRequest {
|
&drtioaux_async::Packet::MonitorRequest {
|
||||||
destination: destination,
|
destination: destination,
|
||||||
channel: channel as _,
|
channel: channel as _,
|
||||||
|
@ -84,8 +82,8 @@ mod remote_moninj {
|
||||||
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(DrtioError::LinkDown) => {
|
Err("link went down") => {
|
||||||
warn!("link is down");
|
debug!("link is down");
|
||||||
}
|
}
|
||||||
Err(e) => error!("aux packet error ({})", e),
|
Err(e) => error!("aux packet error ({})", e),
|
||||||
}
|
}
|
||||||
|
@ -94,7 +92,6 @@ mod remote_moninj {
|
||||||
|
|
||||||
pub async fn inject(
|
pub async fn inject(
|
||||||
aux_mutex: &Rc<Mutex<bool>>,
|
aux_mutex: &Rc<Mutex<bool>>,
|
||||||
_routing_table: &drtio_routing::RoutingTable,
|
|
||||||
_timer: GlobalTimer,
|
_timer: GlobalTimer,
|
||||||
linkno: u8,
|
linkno: u8,
|
||||||
destination: u8,
|
destination: u8,
|
||||||
|
@ -118,7 +115,6 @@ mod remote_moninj {
|
||||||
|
|
||||||
pub async fn read_injection_status(
|
pub async fn read_injection_status(
|
||||||
aux_mutex: &Rc<Mutex<bool>>,
|
aux_mutex: &Rc<Mutex<bool>>,
|
||||||
routing_table: &drtio_routing::RoutingTable,
|
|
||||||
timer: GlobalTimer,
|
timer: GlobalTimer,
|
||||||
linkno: u8,
|
linkno: u8,
|
||||||
destination: u8,
|
destination: u8,
|
||||||
|
@ -128,7 +124,6 @@ mod remote_moninj {
|
||||||
let reply = drtio::aux_transact(
|
let reply = drtio::aux_transact(
|
||||||
aux_mutex,
|
aux_mutex,
|
||||||
linkno,
|
linkno,
|
||||||
routing_table,
|
|
||||||
&drtioaux_async::Packet::InjectionStatusRequest {
|
&drtioaux_async::Packet::InjectionStatusRequest {
|
||||||
destination: destination,
|
destination: destination,
|
||||||
channel: channel as _,
|
channel: channel as _,
|
||||||
|
@ -140,8 +135,8 @@ mod remote_moninj {
|
||||||
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(DrtioError::LinkDown) => {
|
Err("link went down") => {
|
||||||
warn!("link is down");
|
debug!("link is down");
|
||||||
}
|
}
|
||||||
Err(e) => error!("aux packet error ({})", e),
|
Err(e) => error!("aux packet error ({})", e),
|
||||||
}
|
}
|
||||||
|
@ -188,7 +183,7 @@ macro_rules! dispatch {
|
||||||
local_moninj::$func(channel.into(), $($param, )*)
|
local_moninj::$func(channel.into(), $($param, )*)
|
||||||
} else {
|
} else {
|
||||||
let linkno = hop - 1 as u8;
|
let linkno = hop - 1 as u8;
|
||||||
remote_moninj::$func($aux_mutex, $routing_table, $timer, linkno, destination, channel, $($param, )*).await
|
remote_moninj::$func($aux_mutex, $timer, linkno, destination, channel, $($param, )*).await
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,8 +4,6 @@ use ksupport::i2c;
|
||||||
use libboard_artiq::pl;
|
use libboard_artiq::pl;
|
||||||
#[cfg(has_si5324)]
|
#[cfg(has_si5324)]
|
||||||
use libboard_artiq::si5324;
|
use libboard_artiq::si5324;
|
||||||
#[cfg(has_si549)]
|
|
||||||
use libboard_artiq::si549;
|
|
||||||
#[cfg(has_si5324)]
|
#[cfg(has_si5324)]
|
||||||
use libboard_zynq::i2c::I2c;
|
use libboard_zynq::i2c::I2c;
|
||||||
use libboard_zynq::timer::GlobalTimer;
|
use libboard_zynq::timer::GlobalTimer;
|
||||||
|
@ -262,150 +260,6 @@ fn setup_si5324(i2c: &mut I2c, timer: &mut GlobalTimer, clk: RtioClock) {
|
||||||
si5324::setup(i2c, &si5324_settings, si5324_ref_input, timer).expect("cannot initialize Si5324");
|
si5324::setup(i2c, &si5324_settings, si5324_ref_input, timer).expect("cannot initialize Si5324");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(all(has_si549, has_wrpll))]
|
|
||||||
fn wrpll_setup(timer: &mut GlobalTimer, clk: RtioClock, si549_settings: &si549::FrequencySetting) {
|
|
||||||
// register values are directly copied from preconfigured mmcm
|
|
||||||
let (mmcm_setting, mmcm_bypass) = match clk {
|
|
||||||
RtioClock::Ext0_Synth0_10to125 => (
|
|
||||||
si549::wrpll_refclk::MmcmSetting {
|
|
||||||
// CLKFBOUT_MULT = 62.5, DIVCLK_DIVIDE = 1 , CLKOUT0_DIVIDE = 5
|
|
||||||
clkout0_reg1: 0x1083,
|
|
||||||
clkout0_reg2: 0x0080,
|
|
||||||
clkfbout_reg1: 0x179e,
|
|
||||||
clkfbout_reg2: 0x4c00,
|
|
||||||
div_reg: 0x1041,
|
|
||||||
lock_reg1: 0x00fa,
|
|
||||||
lock_reg2: 0x7c01,
|
|
||||||
lock_reg3: 0xffe9,
|
|
||||||
power_reg: 0x9900,
|
|
||||||
filt_reg1: 0x1008,
|
|
||||||
filt_reg2: 0x8800,
|
|
||||||
},
|
|
||||||
false,
|
|
||||||
),
|
|
||||||
RtioClock::Ext0_Synth0_80to125 => (
|
|
||||||
si549::wrpll_refclk::MmcmSetting {
|
|
||||||
// CLKFBOUT_MULT = 15.625, DIVCLK_DIVIDE = 1 , CLKOUT0_DIVIDE = 10
|
|
||||||
clkout0_reg1: 0x1145,
|
|
||||||
clkout0_reg2: 0x0000,
|
|
||||||
clkfbout_reg1: 0x11c7,
|
|
||||||
clkfbout_reg2: 0x5880,
|
|
||||||
div_reg: 0x1041,
|
|
||||||
lock_reg1: 0x028a,
|
|
||||||
lock_reg2: 0x7c01,
|
|
||||||
lock_reg3: 0xffe9,
|
|
||||||
power_reg: 0x9900,
|
|
||||||
filt_reg1: 0x9908,
|
|
||||||
filt_reg2: 0x8100,
|
|
||||||
},
|
|
||||||
false,
|
|
||||||
),
|
|
||||||
RtioClock::Ext0_Synth0_100to125 => (
|
|
||||||
si549::wrpll_refclk::MmcmSetting {
|
|
||||||
// CLKFBOUT_MULT = 12.5, DIVCLK_DIVIDE = 1 , CLKOUT0_DIVIDE = 10
|
|
||||||
clkout0_reg1: 0x1145,
|
|
||||||
clkout0_reg2: 0x0000,
|
|
||||||
clkfbout_reg1: 0x1145,
|
|
||||||
clkfbout_reg2: 0x4c00,
|
|
||||||
div_reg: 0x1041,
|
|
||||||
lock_reg1: 0x0339,
|
|
||||||
lock_reg2: 0x7c01,
|
|
||||||
lock_reg3: 0xffe9,
|
|
||||||
power_reg: 0x9900,
|
|
||||||
filt_reg1: 0x9108,
|
|
||||||
filt_reg2: 0x0100,
|
|
||||||
},
|
|
||||||
false,
|
|
||||||
),
|
|
||||||
RtioClock::Ext0_Synth0_125to125 => (
|
|
||||||
si549::wrpll_refclk::MmcmSetting {
|
|
||||||
// CLKFBOUT_MULT = 10, DIVCLK_DIVIDE = 1 , CLKOUT0_DIVIDE = 10
|
|
||||||
clkout0_reg1: 0x1145,
|
|
||||||
clkout0_reg2: 0x0000,
|
|
||||||
clkfbout_reg1: 0x1145,
|
|
||||||
clkfbout_reg2: 0x0000,
|
|
||||||
div_reg: 0x1041,
|
|
||||||
lock_reg1: 0x03e8,
|
|
||||||
lock_reg2: 0x7001,
|
|
||||||
lock_reg3: 0xf3e9,
|
|
||||||
power_reg: 0x0100,
|
|
||||||
filt_reg1: 0x9908,
|
|
||||||
filt_reg2: 0x1100,
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
),
|
|
||||||
_ => unreachable!(),
|
|
||||||
};
|
|
||||||
|
|
||||||
si549::helper_setup(timer, &si549_settings).expect("cannot initialize helper Si549");
|
|
||||||
si549::wrpll_refclk::setup(timer, mmcm_setting, mmcm_bypass).expect("cannot initialize ref clk for wrpll");
|
|
||||||
si549::wrpll::select_recovered_clock(true, timer);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(has_si549)]
|
|
||||||
fn get_si549_setting(clk: RtioClock) -> si549::FrequencySetting {
|
|
||||||
match clk {
|
|
||||||
RtioClock::Ext0_Synth0_10to125 => {
|
|
||||||
info!("using 10MHz reference to make 125MHz RTIO clock with WRPLL");
|
|
||||||
}
|
|
||||||
RtioClock::Ext0_Synth0_80to125 => {
|
|
||||||
info!("using 80MHz reference to make 125MHz RTIO clock with WRPLL");
|
|
||||||
}
|
|
||||||
RtioClock::Ext0_Synth0_100to125 => {
|
|
||||||
info!("using 100MHz reference to make 125MHz RTIO clock with WRPLL");
|
|
||||||
}
|
|
||||||
RtioClock::Ext0_Synth0_125to125 => {
|
|
||||||
info!("using 125MHz reference to make 125MHz RTIO clock with WRPLL");
|
|
||||||
}
|
|
||||||
RtioClock::Int_100 => {
|
|
||||||
info!("using internal 100MHz RTIO clock");
|
|
||||||
}
|
|
||||||
RtioClock::Int_125 => {
|
|
||||||
info!("using internal 125MHz RTIO clock");
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
warn!(
|
|
||||||
"rtio_clock setting '{:?}' is unsupported. Falling back to default internal 125MHz RTIO clock.",
|
|
||||||
clk
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
match clk {
|
|
||||||
RtioClock::Int_100 => {
|
|
||||||
si549::FrequencySetting {
|
|
||||||
main: si549::DividerConfig {
|
|
||||||
hsdiv: 0x06C,
|
|
||||||
lsdiv: 0,
|
|
||||||
fbdiv: 0x046C5F49797,
|
|
||||||
},
|
|
||||||
helper: si549::DividerConfig {
|
|
||||||
// 100MHz*32767/32768
|
|
||||||
hsdiv: 0x06C,
|
|
||||||
lsdiv: 0,
|
|
||||||
fbdiv: 0x046C5670BBD,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
// Everything else use 125MHz
|
|
||||||
si549::FrequencySetting {
|
|
||||||
main: si549::DividerConfig {
|
|
||||||
hsdiv: 0x058,
|
|
||||||
lsdiv: 0,
|
|
||||||
fbdiv: 0x04815791F25,
|
|
||||||
},
|
|
||||||
helper: si549::DividerConfig {
|
|
||||||
// 125MHz*32767/32768
|
|
||||||
hsdiv: 0x058,
|
|
||||||
lsdiv: 0,
|
|
||||||
fbdiv: 0x04814E8F442,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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)]
|
||||||
|
@ -420,29 +274,9 @@ pub fn init(timer: &mut GlobalTimer, cfg: &Config) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(has_si549)]
|
|
||||||
let si549_settings = get_si549_setting(clk);
|
|
||||||
|
|
||||||
#[cfg(has_si549)]
|
|
||||||
si549::main_setup(timer, &si549_settings).expect("cannot initialize main Si549");
|
|
||||||
|
|
||||||
#[cfg(has_drtio)]
|
#[cfg(has_drtio)]
|
||||||
init_drtio(timer);
|
init_drtio(timer);
|
||||||
|
|
||||||
#[cfg(not(has_drtio))]
|
#[cfg(not(has_drtio))]
|
||||||
init_rtio(timer);
|
init_rtio(timer);
|
||||||
|
|
||||||
#[cfg(all(has_si549, has_wrpll))]
|
|
||||||
{
|
|
||||||
// SYS CLK switch will reset CSRs that are used by WRPLL
|
|
||||||
match clk {
|
|
||||||
RtioClock::Ext0_Synth0_10to125
|
|
||||||
| RtioClock::Ext0_Synth0_80to125
|
|
||||||
| RtioClock::Ext0_Synth0_100to125
|
|
||||||
| RtioClock::Ext0_Synth0_125to125 => {
|
|
||||||
wrpll_setup(timer, clk, &si549_settings);
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -142,9 +142,9 @@ pub mod remote_dma {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn playback_done(&mut self, source: u8, error: u8, channel: u32, timestamp: u64) {
|
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 traces_locked = self.traces.async_lock().await;
|
||||||
let mut trace = traces_locked.get_mut(&source).unwrap();
|
let mut trace = traces_locked.get_mut(&destination).unwrap();
|
||||||
trace.state = RemoteState::PlaybackEnded {
|
trace.state = RemoteState::PlaybackEnded {
|
||||||
error: error,
|
error: error,
|
||||||
channel: channel,
|
channel: channel,
|
||||||
|
|
|
@ -1,69 +1,29 @@
|
||||||
use alloc::rc::Rc;
|
use alloc::rc::Rc;
|
||||||
use core::cell::RefCell;
|
use core::cell::RefCell;
|
||||||
|
|
||||||
use libboard_artiq::{drtio_routing, drtio_routing::RoutingTable, pl::csr};
|
use libboard_artiq::{drtio_routing, pl::csr};
|
||||||
use libboard_zynq::timer::GlobalTimer;
|
use libboard_zynq::timer::GlobalTimer;
|
||||||
use libconfig::Config;
|
|
||||||
use libcortex_a9::mutex::Mutex;
|
use libcortex_a9::mutex::Mutex;
|
||||||
use log::{info, warn};
|
|
||||||
|
|
||||||
#[cfg(has_drtio)]
|
#[cfg(has_drtio)]
|
||||||
pub mod drtio {
|
pub mod drtio {
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
use core::fmt;
|
|
||||||
|
|
||||||
use embedded_hal::blocking::delay::DelayMs;
|
use embedded_hal::blocking::delay::DelayMs;
|
||||||
use ksupport::{resolve_channel_name, ASYNC_ERROR_BUSY, ASYNC_ERROR_COLLISION, ASYNC_ERROR_SEQUENCE_ERROR,
|
use ksupport::{resolve_channel_name, ASYNC_ERROR_BUSY, ASYNC_ERROR_COLLISION, ASYNC_ERROR_SEQUENCE_ERROR,
|
||||||
SEEN_ASYNC_ERRORS};
|
SEEN_ASYNC_ERRORS};
|
||||||
use libasync::{delay, task};
|
use libasync::{delay, task};
|
||||||
use libboard_artiq::{drtioaux::Error as DrtioError,
|
use libboard_artiq::{drtioaux::Error, drtioaux_async, drtioaux_async::Packet,
|
||||||
drtioaux_async,
|
drtioaux_proto::MASTER_PAYLOAD_MAX_SIZE};
|
||||||
drtioaux_async::Packet,
|
|
||||||
drtioaux_proto::{PayloadStatus, MASTER_PAYLOAD_MAX_SIZE}};
|
|
||||||
use libboard_zynq::time::Milliseconds;
|
use libboard_zynq::time::Milliseconds;
|
||||||
use log::{error, info, warn};
|
use log::{error, info, warn};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::{analyzer::remote_analyzer::RemoteBuffer, rtio_dma::remote_dma, subkernel};
|
use crate::{analyzer::remote_analyzer::RemoteBuffer, rtio_dma::remote_dma, subkernel};
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
|
||||||
pub enum Error {
|
|
||||||
Timeout,
|
|
||||||
AuxError,
|
|
||||||
LinkDown,
|
|
||||||
UnexpectedReply,
|
|
||||||
DmaAddTraceFail(u8),
|
|
||||||
DmaEraseFail(u8),
|
|
||||||
DmaPlaybackFail(u8),
|
|
||||||
SubkernelAddFail(u8),
|
|
||||||
SubkernelRunFail(u8),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for Error {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
Error::Timeout => write!(f, "timed out"),
|
|
||||||
Error::AuxError => write!(f, "aux packet error"),
|
|
||||||
Error::LinkDown => write!(f, "link down"),
|
|
||||||
Error::UnexpectedReply => write!(f, "unexpected reply"),
|
|
||||||
Error::DmaAddTraceFail(dest) => write!(f, "error adding DMA trace on satellite #{}", dest),
|
|
||||||
Error::DmaEraseFail(dest) => write!(f, "error erasing DMA trace on satellite #{}", dest),
|
|
||||||
Error::DmaPlaybackFail(dest) => write!(f, "error playing back DMA trace on satellite #{}", dest),
|
|
||||||
Error::SubkernelAddFail(dest) => write!(f, "error adding subkernel on satellite #{}", dest),
|
|
||||||
Error::SubkernelRunFail(dest) => write!(f, "error on subkernel run request on satellite #{}", dest),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<DrtioError> for Error {
|
|
||||||
fn from(_error: DrtioError) -> Self {
|
|
||||||
Error::AuxError
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn startup(
|
pub fn startup(
|
||||||
aux_mutex: &Rc<Mutex<bool>>,
|
aux_mutex: &Rc<Mutex<bool>>,
|
||||||
routing_table: &Rc<RefCell<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,
|
||||||
) {
|
) {
|
||||||
|
@ -81,121 +41,78 @@ pub mod drtio {
|
||||||
unsafe { (csr::DRTIO[linkno].rx_up_read)() == 1 }
|
unsafe { (csr::DRTIO[linkno].rx_up_read)() == 1 }
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn process_async_packets(linkno: u8, routing_table: &RoutingTable, packet: Packet) -> Option<Packet> {
|
async fn process_async_packets(aux_mutex: &Mutex<bool>, linkno: u8, packet: Packet) -> Option<Packet> {
|
||||||
|
// returns None if an async packet has been consumed
|
||||||
match packet {
|
match packet {
|
||||||
Packet::DmaPlaybackStatus {
|
Packet::DmaPlaybackStatus {
|
||||||
id,
|
id,
|
||||||
source,
|
destination,
|
||||||
destination: 0,
|
|
||||||
error,
|
error,
|
||||||
channel,
|
channel,
|
||||||
timestamp,
|
timestamp,
|
||||||
} => {
|
} => {
|
||||||
remote_dma::playback_done(id, source, error, channel, timestamp).await;
|
remote_dma::playback_done(id, destination, error, channel, timestamp).await;
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
Packet::SubkernelFinished {
|
Packet::SubkernelFinished { id, with_exception } => {
|
||||||
id,
|
subkernel::subkernel_finished(id, with_exception).await;
|
||||||
destination: 0,
|
|
||||||
with_exception,
|
|
||||||
exception_src,
|
|
||||||
} => {
|
|
||||||
subkernel::subkernel_finished(id, with_exception, exception_src).await;
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
Packet::SubkernelMessage {
|
Packet::SubkernelMessage {
|
||||||
id,
|
id,
|
||||||
source,
|
destination: from,
|
||||||
destination: 0,
|
last,
|
||||||
status,
|
|
||||||
length,
|
length,
|
||||||
data,
|
data,
|
||||||
} => {
|
} => {
|
||||||
subkernel::message_handle_incoming(id, status, length as usize, &data).await;
|
subkernel::message_handle_incoming(id, last, length as usize, &data).await;
|
||||||
// acknowledge receiving part of the message
|
// acknowledge receiving part of the message
|
||||||
drtioaux_async::send(linkno, &Packet::SubkernelMessageAck { destination: source })
|
let _lock = aux_mutex.async_lock().await;
|
||||||
|
drtioaux_async::send(linkno, &Packet::SubkernelMessageAck { destination: from })
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
// routable packets
|
|
||||||
Packet::DmaAddTraceRequest { destination, .. }
|
|
||||||
| Packet::DmaAddTraceReply { destination, .. }
|
|
||||||
| Packet::DmaRemoveTraceRequest { destination, .. }
|
|
||||||
| Packet::DmaRemoveTraceReply { destination, .. }
|
|
||||||
| Packet::DmaPlaybackRequest { destination, .. }
|
|
||||||
| Packet::DmaPlaybackReply { destination, .. }
|
|
||||||
| Packet::SubkernelLoadRunRequest { destination, .. }
|
|
||||||
| Packet::SubkernelLoadRunReply { destination, .. }
|
|
||||||
| Packet::SubkernelMessage { destination, .. }
|
|
||||||
| Packet::SubkernelMessageAck { destination, .. }
|
|
||||||
| Packet::SubkernelException { destination, .. }
|
|
||||||
| Packet::SubkernelExceptionRequest { destination, .. }
|
|
||||||
| Packet::DmaPlaybackStatus { destination, .. }
|
|
||||||
| Packet::SubkernelFinished { destination, .. } => {
|
|
||||||
if destination == 0 {
|
|
||||||
Some(packet)
|
|
||||||
} else {
|
|
||||||
let dest_link = routing_table.0[destination as usize][0] - 1;
|
|
||||||
if dest_link == linkno {
|
|
||||||
warn!(
|
|
||||||
"[LINK#{}] Re-routed packet would return to the same link, dropping: {:?}",
|
|
||||||
linkno, packet
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
drtioaux_async::send(dest_link, &packet).await.unwrap();
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
other => Some(other),
|
other => Some(other),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn recv_aux_timeout(linkno: u8, timeout: u64, timer: GlobalTimer) -> Result<Packet, Error> {
|
async fn recv_aux_timeout(linkno: u8, timeout: u64, timer: GlobalTimer) -> Result<Packet, &'static str> {
|
||||||
if !link_rx_up(linkno).await {
|
if !link_rx_up(linkno).await {
|
||||||
return Err(Error::LinkDown);
|
return Err("link went down");
|
||||||
}
|
}
|
||||||
match drtioaux_async::recv_timeout(linkno, Some(timeout), timer).await {
|
match drtioaux_async::recv_timeout(linkno, Some(timeout), timer).await {
|
||||||
Ok(packet) => return Ok(packet),
|
Ok(packet) => return Ok(packet),
|
||||||
Err(DrtioError::TimedOut) => return Err(Error::Timeout),
|
Err(Error::TimedOut) => return Err("timed out"),
|
||||||
Err(_) => return Err(Error::AuxError),
|
Err(_) => return Err("aux packet error"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn aux_transact(
|
pub async fn aux_transact(
|
||||||
aux_mutex: &Mutex<bool>,
|
aux_mutex: &Mutex<bool>,
|
||||||
linkno: u8,
|
linkno: u8,
|
||||||
routing_table: &RoutingTable,
|
|
||||||
request: &Packet,
|
request: &Packet,
|
||||||
timer: GlobalTimer,
|
timer: GlobalTimer,
|
||||||
) -> Result<Packet, Error> {
|
) -> Result<Packet, &'static str> {
|
||||||
if !link_rx_up(linkno).await {
|
if !link_rx_up(linkno).await {
|
||||||
return Err(Error::LinkDown);
|
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 {
|
Ok(recv_aux_timeout(linkno, 200, timer).await?)
|
||||||
let packet = recv_aux_timeout(linkno, 200, timer).await?;
|
|
||||||
if let Some(packet) = process_async_packets(linkno, routing_table, packet).await {
|
|
||||||
return Ok(packet);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn drain_buffer(linkno: u8, draining_time: Milliseconds, timer: GlobalTimer) {
|
async fn drain_buffer(linkno: u8, draining_time: Milliseconds, timer: GlobalTimer) {
|
||||||
let max_time = timer.get_time() + draining_time;
|
let max_time = timer.get_time() + draining_time;
|
||||||
while timer.get_time() < max_time {
|
loop {
|
||||||
|
if timer.get_time() > max_time {
|
||||||
|
return;
|
||||||
|
} //could this be cut short?
|
||||||
let _ = drtioaux_async::recv(linkno).await;
|
let _ = drtioaux_async::recv(linkno).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn ping_remote(
|
async fn ping_remote(aux_mutex: &Rc<Mutex<bool>>, linkno: u8, timer: GlobalTimer) -> u32 {
|
||||||
aux_mutex: &Rc<Mutex<bool>>,
|
|
||||||
linkno: u8,
|
|
||||||
routing_table: &RoutingTable,
|
|
||||||
timer: GlobalTimer,
|
|
||||||
) -> u32 {
|
|
||||||
let mut count = 0;
|
let mut count = 0;
|
||||||
loop {
|
loop {
|
||||||
if !link_rx_up(linkno).await {
|
if !link_rx_up(linkno).await {
|
||||||
|
@ -205,7 +122,7 @@ pub mod drtio {
|
||||||
if count > 100 {
|
if count > 100 {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
let reply = aux_transact(aux_mutex, linkno, routing_table, &Packet::EchoRequest, timer).await;
|
let reply = aux_transact(aux_mutex, linkno, &Packet::EchoRequest, timer).await;
|
||||||
match reply {
|
match reply {
|
||||||
Ok(Packet::EchoReply) => {
|
Ok(Packet::EchoReply) => {
|
||||||
// make sure receive buffer is drained
|
// make sure receive buffer is drained
|
||||||
|
@ -218,7 +135,7 @@ pub mod drtio {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn sync_tsc(aux_mutex: &Rc<Mutex<bool>>, linkno: u8, timer: GlobalTimer) -> Result<(), Error> {
|
async fn sync_tsc(aux_mutex: &Rc<Mutex<bool>>, linkno: u8, timer: GlobalTimer) -> Result<(), &'static str> {
|
||||||
let _lock = aux_mutex.async_lock().await;
|
let _lock = aux_mutex.async_lock().await;
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -229,23 +146,22 @@ pub mod drtio {
|
||||||
// by the satellite, in response to a TSC set on the RT link.
|
// by the satellite, in response to a TSC set on the RT link.
|
||||||
let reply = recv_aux_timeout(linkno, 10000, timer).await?;
|
let reply = recv_aux_timeout(linkno, 10000, timer).await?;
|
||||||
if reply == Packet::TSCAck {
|
if reply == Packet::TSCAck {
|
||||||
Ok(())
|
return Ok(());
|
||||||
} else {
|
} else {
|
||||||
Err(Error::UnexpectedReply)
|
return Err("unexpected reply");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn load_routing_table(
|
async fn load_routing_table(
|
||||||
aux_mutex: &Rc<Mutex<bool>>,
|
aux_mutex: &Rc<Mutex<bool>>,
|
||||||
linkno: u8,
|
linkno: u8,
|
||||||
routing_table: &RoutingTable,
|
routing_table: &drtio_routing::RoutingTable,
|
||||||
timer: GlobalTimer,
|
timer: GlobalTimer,
|
||||||
) -> Result<(), Error> {
|
) -> 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,
|
aux_mutex,
|
||||||
linkno,
|
linkno,
|
||||||
routing_table,
|
|
||||||
&Packet::RoutingSetPath {
|
&Packet::RoutingSetPath {
|
||||||
destination: i as u8,
|
destination: i as u8,
|
||||||
hops: routing_table.0[i],
|
hops: routing_table.0[i],
|
||||||
|
@ -254,7 +170,7 @@ pub mod drtio {
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
if reply != Packet::RoutingAck {
|
if reply != Packet::RoutingAck {
|
||||||
return Err(Error::UnexpectedReply);
|
return Err("unexpected reply");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -264,21 +180,13 @@ pub mod drtio {
|
||||||
aux_mutex: &Rc<Mutex<bool>>,
|
aux_mutex: &Rc<Mutex<bool>>,
|
||||||
linkno: u8,
|
linkno: u8,
|
||||||
rank: u8,
|
rank: u8,
|
||||||
routing_table: &RoutingTable,
|
|
||||||
timer: GlobalTimer,
|
timer: GlobalTimer,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), &'static str> {
|
||||||
let reply = aux_transact(
|
let reply = aux_transact(aux_mutex, linkno, &Packet::RoutingSetRank { rank: rank }, timer).await?;
|
||||||
aux_mutex,
|
if reply != Packet::RoutingAck {
|
||||||
linkno,
|
return Err("unexpected reply");
|
||||||
routing_table,
|
|
||||||
&Packet::RoutingSetRank { rank: rank },
|
|
||||||
timer,
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
match reply {
|
|
||||||
Packet::RoutingAck => Ok(()),
|
|
||||||
_ => Err(Error::UnexpectedReply),
|
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn init_buffer_space(destination: u8, linkno: u8) {
|
async fn init_buffer_space(destination: u8, linkno: u8) {
|
||||||
|
@ -297,11 +205,11 @@ pub mod drtio {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn process_unsolicited_aux(aux_mutex: &Mutex<bool>, linkno: u8, routing_table: &RoutingTable) {
|
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)) => {
|
Ok(Some(packet)) => {
|
||||||
if let Some(packet) = process_async_packets(linkno, routing_table, packet).await {
|
if let Some(packet) = process_async_packets(aux_mutex, linkno, packet).await {
|
||||||
warn!("[LINK#{}] unsolicited aux packet: {:?}", linkno, packet);
|
warn!("[LINK#{}] unsolicited aux packet: {:?}", linkno, packet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -332,7 +240,7 @@ pub mod drtio {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn destination_set_up(
|
async fn destination_set_up(
|
||||||
routing_table: &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,
|
destination: u8,
|
||||||
up: bool,
|
up: bool,
|
||||||
|
@ -355,7 +263,7 @@ pub mod drtio {
|
||||||
|
|
||||||
async fn destination_survey(
|
async fn destination_survey(
|
||||||
aux_mutex: &Rc<Mutex<bool>>,
|
aux_mutex: &Rc<Mutex<bool>>,
|
||||||
routing_table: &RoutingTable,
|
routing_table: &drtio_routing::RoutingTable,
|
||||||
up_links: &[bool],
|
up_links: &[bool],
|
||||||
up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>,
|
up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>,
|
||||||
timer: GlobalTimer,
|
timer: GlobalTimer,
|
||||||
|
@ -373,54 +281,67 @@ 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(
|
loop {
|
||||||
aux_mutex,
|
let reply = aux_transact(
|
||||||
linkno,
|
aux_mutex,
|
||||||
routing_table,
|
linkno,
|
||||||
&Packet::DestinationStatusRequest {
|
&Packet::DestinationStatusRequest {
|
||||||
destination: destination,
|
destination: destination,
|
||||||
},
|
},
|
||||||
timer,
|
timer,
|
||||||
)
|
)
|
||||||
.await;
|
.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)
|
remote_dma::destination_changed(
|
||||||
.await;
|
aux_mutex,
|
||||||
subkernel::destination_changed(aux_mutex, routing_table, timer, destination, false)
|
routing_table,
|
||||||
|
timer,
|
||||||
|
destination,
|
||||||
|
false,
|
||||||
|
)
|
||||||
.await;
|
.await;
|
||||||
|
subkernel::destination_changed(aux_mutex, routing_table, timer, destination, false)
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
Ok(Packet::DestinationOkReply) => (),
|
||||||
|
Ok(Packet::DestinationSequenceErrorReply { channel }) => {
|
||||||
|
error!(
|
||||||
|
"[DEST#{}] RTIO sequence error involving channel 0x{:04x}:{}",
|
||||||
|
destination,
|
||||||
|
channel,
|
||||||
|
resolve_channel_name(channel as u32)
|
||||||
|
);
|
||||||
|
unsafe { SEEN_ASYNC_ERRORS |= ASYNC_ERROR_SEQUENCE_ERROR };
|
||||||
|
}
|
||||||
|
Ok(Packet::DestinationCollisionReply { channel }) => {
|
||||||
|
error!(
|
||||||
|
"[DEST#{}] RTIO collision involving channel 0x{:04x}:{}",
|
||||||
|
destination,
|
||||||
|
channel,
|
||||||
|
resolve_channel_name(channel as u32)
|
||||||
|
);
|
||||||
|
unsafe { SEEN_ASYNC_ERRORS |= ASYNC_ERROR_COLLISION };
|
||||||
|
}
|
||||||
|
Ok(Packet::DestinationBusyReply { channel }) => {
|
||||||
|
error!(
|
||||||
|
"[DEST#{}] RTIO busy error involving channel 0x{:04x}:{}",
|
||||||
|
destination,
|
||||||
|
channel,
|
||||||
|
resolve_channel_name(channel as u32)
|
||||||
|
);
|
||||||
|
unsafe { SEEN_ASYNC_ERRORS |= ASYNC_ERROR_BUSY };
|
||||||
|
}
|
||||||
|
Ok(packet) => match process_async_packets(aux_mutex, linkno, packet).await {
|
||||||
|
Some(packet) => {
|
||||||
|
error!("[DEST#{}] received unexpected aux packet: {:?}", destination, packet)
|
||||||
|
}
|
||||||
|
None => continue,
|
||||||
|
},
|
||||||
|
Err(e) => error!("[DEST#{}] communication failed ({})", destination, e),
|
||||||
}
|
}
|
||||||
Ok(Packet::DestinationOkReply) => (),
|
break;
|
||||||
Ok(Packet::DestinationSequenceErrorReply { channel }) => {
|
|
||||||
error!(
|
|
||||||
"[DEST#{}] RTIO sequence error involving channel 0x{:04x}:{}",
|
|
||||||
destination,
|
|
||||||
channel,
|
|
||||||
resolve_channel_name(channel as u32)
|
|
||||||
);
|
|
||||||
unsafe { SEEN_ASYNC_ERRORS |= ASYNC_ERROR_SEQUENCE_ERROR };
|
|
||||||
}
|
|
||||||
Ok(Packet::DestinationCollisionReply { channel }) => {
|
|
||||||
error!(
|
|
||||||
"[DEST#{}] RTIO collision involving channel 0x{:04x}:{}",
|
|
||||||
destination,
|
|
||||||
channel,
|
|
||||||
resolve_channel_name(channel as u32)
|
|
||||||
);
|
|
||||||
unsafe { SEEN_ASYNC_ERRORS |= ASYNC_ERROR_COLLISION };
|
|
||||||
}
|
|
||||||
Ok(Packet::DestinationBusyReply { channel }) => {
|
|
||||||
error!(
|
|
||||||
"[DEST#{}] RTIO busy error involving channel 0x{:04x}:{}",
|
|
||||||
destination,
|
|
||||||
channel,
|
|
||||||
resolve_channel_name(channel as u32)
|
|
||||||
);
|
|
||||||
unsafe { SEEN_ASYNC_ERRORS |= ASYNC_ERROR_BUSY };
|
|
||||||
}
|
|
||||||
Ok(packet) => error!("[DEST#{}] received unexpected aux packet: {:?}", destination, packet),
|
|
||||||
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;
|
||||||
|
@ -432,7 +353,6 @@ pub mod drtio {
|
||||||
let reply = aux_transact(
|
let reply = aux_transact(
|
||||||
aux_mutex,
|
aux_mutex,
|
||||||
linkno,
|
linkno,
|
||||||
routing_table,
|
|
||||||
&Packet::DestinationStatusRequest {
|
&Packet::DestinationStatusRequest {
|
||||||
destination: destination,
|
destination: destination,
|
||||||
},
|
},
|
||||||
|
@ -460,7 +380,7 @@ 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: &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,
|
||||||
) {
|
) {
|
||||||
|
@ -471,7 +391,7 @@ pub mod drtio {
|
||||||
if up_links[linkno as usize] {
|
if up_links[linkno as usize] {
|
||||||
/* link was previously up */
|
/* link was previously up */
|
||||||
if link_rx_up(linkno).await {
|
if link_rx_up(linkno).await {
|
||||||
process_unsolicited_aux(aux_mutex, linkno, routing_table).await;
|
process_unsolicited_aux(aux_mutex, linkno).await;
|
||||||
process_local_errors(linkno).await;
|
process_local_errors(linkno).await;
|
||||||
} else {
|
} else {
|
||||||
info!("[LINK#{}] link is down", linkno);
|
info!("[LINK#{}] link is down", linkno);
|
||||||
|
@ -481,7 +401,7 @@ pub mod drtio {
|
||||||
/* link was previously down */
|
/* link was previously down */
|
||||||
if link_rx_up(linkno).await {
|
if link_rx_up(linkno).await {
|
||||||
info!("[LINK#{}] link RX became up, pinging", linkno);
|
info!("[LINK#{}] link RX became up, pinging", linkno);
|
||||||
let ping_count = ping_remote(aux_mutex, linkno, routing_table, timer).await;
|
let ping_count = ping_remote(aux_mutex, linkno, timer).await;
|
||||||
if ping_count > 0 {
|
if ping_count > 0 {
|
||||||
info!("[LINK#{}] remote replied after {} packets", linkno, ping_count);
|
info!("[LINK#{}] remote replied after {} packets", linkno, ping_count);
|
||||||
up_links[linkno as usize] = true;
|
up_links[linkno as usize] = true;
|
||||||
|
@ -491,7 +411,7 @@ pub mod drtio {
|
||||||
if let Err(e) = load_routing_table(aux_mutex, linkno, routing_table, timer).await {
|
if let Err(e) = load_routing_table(aux_mutex, linkno, routing_table, timer).await {
|
||||||
error!("[LINK#{}] failed to load routing table ({})", linkno, e);
|
error!("[LINK#{}] failed to load routing table ({})", linkno, e);
|
||||||
}
|
}
|
||||||
if let Err(e) = set_rank(aux_mutex, linkno, 1 as u8, routing_table, timer).await {
|
if let Err(e) = set_rank(aux_mutex, linkno, 1 as u8, timer).await {
|
||||||
error!("[LINK#{}] failed to set rank ({})", linkno, e);
|
error!("[LINK#{}] failed to set rank ({})", linkno, e);
|
||||||
}
|
}
|
||||||
info!("[LINK#{}] link initialization completed", linkno);
|
info!("[LINK#{}] link initialization completed", linkno);
|
||||||
|
@ -508,7 +428,7 @@ pub mod drtio {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn reset(aux_mutex: Rc<Mutex<bool>>, routing_table: &RoutingTable, mut timer: GlobalTimer) {
|
pub fn reset(aux_mutex: Rc<Mutex<bool>>, mut timer: GlobalTimer) {
|
||||||
for linkno in 0..csr::DRTIO.len() {
|
for linkno in 0..csr::DRTIO.len() {
|
||||||
unsafe {
|
unsafe {
|
||||||
(csr::DRTIO[linkno].reset_write)(1);
|
(csr::DRTIO[linkno].reset_write)(1);
|
||||||
|
@ -524,13 +444,7 @@ 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(
|
let reply = task::block_on(aux_transact(&aux_mutex, linkno, &Packet::ResetRequest, timer));
|
||||||
&aux_mutex,
|
|
||||||
linkno,
|
|
||||||
routing_table,
|
|
||||||
&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),
|
||||||
|
@ -543,15 +457,14 @@ pub mod drtio {
|
||||||
async fn partition_data<PacketF, HandlerF>(
|
async fn partition_data<PacketF, HandlerF>(
|
||||||
linkno: u8,
|
linkno: u8,
|
||||||
aux_mutex: &Rc<Mutex<bool>>,
|
aux_mutex: &Rc<Mutex<bool>>,
|
||||||
routing_table: &RoutingTable,
|
|
||||||
timer: GlobalTimer,
|
timer: GlobalTimer,
|
||||||
data: &[u8],
|
data: &[u8],
|
||||||
packet_f: PacketF,
|
packet_f: PacketF,
|
||||||
reply_handler_f: HandlerF,
|
reply_handler_f: HandlerF,
|
||||||
) -> Result<(), Error>
|
) -> Result<(), &'static str>
|
||||||
where
|
where
|
||||||
PacketF: Fn(&[u8; MASTER_PAYLOAD_MAX_SIZE], PayloadStatus, usize) -> Packet,
|
PacketF: Fn(&[u8; MASTER_PAYLOAD_MAX_SIZE], bool, usize) -> Packet,
|
||||||
HandlerF: Fn(&Packet) -> Result<(), Error>,
|
HandlerF: Fn(&Packet) -> Result<(), &'static str>,
|
||||||
{
|
{
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
while i < data.len() {
|
while i < data.len() {
|
||||||
|
@ -561,13 +474,11 @@ pub mod drtio {
|
||||||
} else {
|
} else {
|
||||||
data.len() - i
|
data.len() - i
|
||||||
} as usize;
|
} as usize;
|
||||||
let first = i == 0;
|
|
||||||
let last = i + len == data.len();
|
let last = i + len == data.len();
|
||||||
slice[..len].clone_from_slice(&data[i..i + len]);
|
slice[..len].clone_from_slice(&data[i..i + len]);
|
||||||
i += len;
|
i += len;
|
||||||
let status = PayloadStatus::from_status(first, last);
|
let packet = packet_f(&slice, last, len);
|
||||||
let packet = packet_f(&slice, status, len);
|
let reply = aux_transact(aux_mutex, linkno, &packet, timer).await?;
|
||||||
let reply = aux_transact(aux_mutex, linkno, routing_table, &packet, timer).await?;
|
|
||||||
reply_handler_f(&reply)?;
|
reply_handler_f(&reply)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -575,39 +486,29 @@ pub mod drtio {
|
||||||
|
|
||||||
pub async fn ddma_upload_trace(
|
pub async fn ddma_upload_trace(
|
||||||
aux_mutex: &Rc<Mutex<bool>>,
|
aux_mutex: &Rc<Mutex<bool>>,
|
||||||
routing_table: &RoutingTable,
|
routing_table: &drtio_routing::RoutingTable,
|
||||||
timer: GlobalTimer,
|
timer: GlobalTimer,
|
||||||
id: u32,
|
id: u32,
|
||||||
destination: u8,
|
destination: u8,
|
||||||
trace: &Vec<u8>,
|
trace: &Vec<u8>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), &'static str> {
|
||||||
let linkno = routing_table.0[destination as usize][0] - 1;
|
let linkno = routing_table.0[destination as usize][0] - 1;
|
||||||
partition_data(
|
partition_data(
|
||||||
linkno,
|
linkno,
|
||||||
aux_mutex,
|
aux_mutex,
|
||||||
routing_table,
|
|
||||||
timer,
|
timer,
|
||||||
trace,
|
trace,
|
||||||
|slice, status, len| Packet::DmaAddTraceRequest {
|
|slice, last, len| Packet::DmaAddTraceRequest {
|
||||||
id: id,
|
id: id,
|
||||||
source: 0,
|
|
||||||
destination: destination,
|
destination: destination,
|
||||||
status: status,
|
last: last,
|
||||||
length: len as u16,
|
length: len as u16,
|
||||||
trace: *slice,
|
trace: *slice,
|
||||||
},
|
},
|
||||||
|reply| match reply {
|
|reply| match reply {
|
||||||
Packet::DmaAddTraceReply {
|
Packet::DmaAddTraceReply { succeeded: true } => Ok(()),
|
||||||
destination: 0,
|
Packet::DmaAddTraceReply { succeeded: false } => Err("error adding trace on satellite"),
|
||||||
succeeded: true,
|
_ => Err("adding DMA trace failed, unexpected aux packet"),
|
||||||
..
|
|
||||||
} => Ok(()),
|
|
||||||
Packet::DmaAddTraceReply {
|
|
||||||
destination: 0,
|
|
||||||
succeeded: false,
|
|
||||||
..
|
|
||||||
} => Err(Error::DmaAddTraceFail(destination)),
|
|
||||||
_ => Err(Error::UnexpectedReply),
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
|
@ -615,96 +516,82 @@ pub mod drtio {
|
||||||
|
|
||||||
pub async fn ddma_send_erase(
|
pub async fn ddma_send_erase(
|
||||||
aux_mutex: &Rc<Mutex<bool>>,
|
aux_mutex: &Rc<Mutex<bool>>,
|
||||||
routing_table: &RoutingTable,
|
routing_table: &drtio_routing::RoutingTable,
|
||||||
timer: GlobalTimer,
|
timer: GlobalTimer,
|
||||||
id: u32,
|
id: u32,
|
||||||
destination: u8,
|
destination: u8,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), &'static str> {
|
||||||
let linkno = routing_table.0[destination as usize][0] - 1;
|
let linkno = routing_table.0[destination as usize][0] - 1;
|
||||||
let reply = aux_transact(
|
let reply = aux_transact(
|
||||||
aux_mutex,
|
aux_mutex,
|
||||||
linkno,
|
linkno,
|
||||||
routing_table,
|
|
||||||
&Packet::DmaRemoveTraceRequest {
|
&Packet::DmaRemoveTraceRequest {
|
||||||
id: id,
|
id: id,
|
||||||
source: 0,
|
|
||||||
destination: destination,
|
destination: destination,
|
||||||
},
|
},
|
||||||
timer,
|
timer,
|
||||||
)
|
)
|
||||||
.await?;
|
.await;
|
||||||
match reply {
|
match reply {
|
||||||
Packet::DmaRemoveTraceReply {
|
Ok(Packet::DmaRemoveTraceReply { succeeded: true }) => Ok(()),
|
||||||
destination: 0,
|
Ok(Packet::DmaRemoveTraceReply { succeeded: false }) => Err("satellite DMA erase error"),
|
||||||
succeeded: true,
|
Ok(_) => Err("adding trace failed, unexpected aux packet"),
|
||||||
} => Ok(()),
|
Err(_) => Err("erasing trace failed, aux error"),
|
||||||
Packet::DmaRemoveTraceReply {
|
|
||||||
destination: 0,
|
|
||||||
succeeded: false,
|
|
||||||
} => Err(Error::DmaEraseFail(destination)),
|
|
||||||
_ => Err(Error::UnexpectedReply),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn ddma_send_playback(
|
pub async fn ddma_send_playback(
|
||||||
aux_mutex: &Rc<Mutex<bool>>,
|
aux_mutex: &Rc<Mutex<bool>>,
|
||||||
routing_table: &RoutingTable,
|
routing_table: &drtio_routing::RoutingTable,
|
||||||
timer: GlobalTimer,
|
timer: GlobalTimer,
|
||||||
id: u32,
|
id: u32,
|
||||||
destination: u8,
|
destination: u8,
|
||||||
timestamp: u64,
|
timestamp: u64,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), &'static str> {
|
||||||
let linkno = routing_table.0[destination as usize][0] - 1;
|
let linkno = routing_table.0[destination as usize][0] - 1;
|
||||||
let reply = aux_transact(
|
let reply = aux_transact(
|
||||||
aux_mutex,
|
aux_mutex,
|
||||||
linkno,
|
linkno,
|
||||||
routing_table,
|
|
||||||
&Packet::DmaPlaybackRequest {
|
&Packet::DmaPlaybackRequest {
|
||||||
id: id,
|
id: id,
|
||||||
source: 0,
|
|
||||||
destination: destination,
|
destination: destination,
|
||||||
timestamp: timestamp,
|
timestamp: timestamp,
|
||||||
},
|
},
|
||||||
timer,
|
timer,
|
||||||
)
|
)
|
||||||
.await?;
|
.await;
|
||||||
match reply {
|
match reply {
|
||||||
Packet::DmaPlaybackReply {
|
Ok(Packet::DmaPlaybackReply { succeeded: true }) => Ok(()),
|
||||||
destination: 0,
|
Ok(Packet::DmaPlaybackReply { succeeded: false }) => Err("error on DMA playback request"),
|
||||||
succeeded: true,
|
Ok(_) => Err("received unexpected aux packet during DMA playback"),
|
||||||
} => Ok(()),
|
Err(_) => Err("aux error on DMA playback"),
|
||||||
Packet::DmaPlaybackReply {
|
|
||||||
destination: 0,
|
|
||||||
succeeded: false,
|
|
||||||
} => Err(Error::DmaPlaybackFail(destination)),
|
|
||||||
_ => Err(Error::UnexpectedReply),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn analyzer_get_data(
|
async fn analyzer_get_data(
|
||||||
aux_mutex: &Rc<Mutex<bool>>,
|
aux_mutex: &Rc<Mutex<bool>>,
|
||||||
routing_table: &RoutingTable,
|
routing_table: &drtio_routing::RoutingTable,
|
||||||
timer: GlobalTimer,
|
timer: GlobalTimer,
|
||||||
destination: u8,
|
destination: u8,
|
||||||
) -> Result<RemoteBuffer, Error> {
|
) -> Result<RemoteBuffer, &'static str> {
|
||||||
let linkno = routing_table.0[destination as usize][0] - 1;
|
let linkno = routing_table.0[destination as usize][0] - 1;
|
||||||
let reply = aux_transact(
|
let reply = aux_transact(
|
||||||
aux_mutex,
|
aux_mutex,
|
||||||
linkno,
|
linkno,
|
||||||
routing_table,
|
|
||||||
&Packet::AnalyzerHeaderRequest {
|
&Packet::AnalyzerHeaderRequest {
|
||||||
destination: destination,
|
destination: destination,
|
||||||
},
|
},
|
||||||
timer,
|
timer,
|
||||||
)
|
)
|
||||||
.await?;
|
.await;
|
||||||
let (sent, total, overflow) = match reply {
|
let (sent, total, overflow) = match reply {
|
||||||
Packet::AnalyzerHeader {
|
Ok(Packet::AnalyzerHeader {
|
||||||
sent_bytes,
|
sent_bytes,
|
||||||
total_byte_count,
|
total_byte_count,
|
||||||
overflow_occurred,
|
overflow_occurred,
|
||||||
} => (sent_bytes, total_byte_count, overflow_occurred),
|
}) => (sent_bytes, total_byte_count, overflow_occurred),
|
||||||
_ => return Err(Error::UnexpectedReply),
|
Ok(_) => return Err("received unexpected aux packet during remote analyzer header request"),
|
||||||
|
Err(e) => return Err(e),
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut remote_data: Vec<u8> = Vec::new();
|
let mut remote_data: Vec<u8> = Vec::new();
|
||||||
|
@ -714,19 +601,19 @@ pub mod drtio {
|
||||||
let reply = aux_transact(
|
let reply = aux_transact(
|
||||||
aux_mutex,
|
aux_mutex,
|
||||||
linkno,
|
linkno,
|
||||||
routing_table,
|
|
||||||
&Packet::AnalyzerDataRequest {
|
&Packet::AnalyzerDataRequest {
|
||||||
destination: destination,
|
destination: destination,
|
||||||
},
|
},
|
||||||
timer,
|
timer,
|
||||||
)
|
)
|
||||||
.await?;
|
.await;
|
||||||
match reply {
|
match reply {
|
||||||
Packet::AnalyzerData { last, length, data } => {
|
Ok(Packet::AnalyzerData { last, length, data }) => {
|
||||||
last_packet = last;
|
last_packet = last;
|
||||||
remote_data.extend(&data[0..length as usize]);
|
remote_data.extend(&data[0..length as usize]);
|
||||||
}
|
}
|
||||||
_ => return Err(Error::UnexpectedReply),
|
Ok(_) => return Err("received unexpected aux packet during remote analyzer data request"),
|
||||||
|
Err(e) => return Err(e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -741,10 +628,10 @@ pub mod drtio {
|
||||||
|
|
||||||
pub async fn analyzer_query(
|
pub async fn analyzer_query(
|
||||||
aux_mutex: &Rc<Mutex<bool>>,
|
aux_mutex: &Rc<Mutex<bool>>,
|
||||||
routing_table: &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,
|
||||||
) -> Result<Vec<RemoteBuffer>, Error> {
|
) -> Result<Vec<RemoteBuffer>, &'static str> {
|
||||||
let mut remote_buffers: Vec<RemoteBuffer> = Vec::new();
|
let mut remote_buffers: Vec<RemoteBuffer> = Vec::new();
|
||||||
for i in 1..drtio_routing::DEST_COUNT {
|
for i in 1..drtio_routing::DEST_COUNT {
|
||||||
if destination_up(up_destinations, i as u8).await {
|
if destination_up(up_destinations, i as u8).await {
|
||||||
|
@ -756,30 +643,29 @@ pub mod drtio {
|
||||||
|
|
||||||
pub async fn subkernel_upload(
|
pub async fn subkernel_upload(
|
||||||
aux_mutex: &Rc<Mutex<bool>>,
|
aux_mutex: &Rc<Mutex<bool>>,
|
||||||
routing_table: &RoutingTable,
|
routing_table: &drtio_routing::RoutingTable,
|
||||||
timer: GlobalTimer,
|
timer: GlobalTimer,
|
||||||
id: u32,
|
id: u32,
|
||||||
destination: u8,
|
destination: u8,
|
||||||
data: &Vec<u8>,
|
data: &Vec<u8>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), &'static str> {
|
||||||
let linkno = routing_table.0[destination as usize][0] - 1;
|
let linkno = routing_table.0[destination as usize][0] - 1;
|
||||||
partition_data(
|
partition_data(
|
||||||
linkno,
|
linkno,
|
||||||
aux_mutex,
|
aux_mutex,
|
||||||
routing_table,
|
|
||||||
timer,
|
timer,
|
||||||
data,
|
data,
|
||||||
|slice, status, len| Packet::SubkernelAddDataRequest {
|
|slice, last, len| Packet::SubkernelAddDataRequest {
|
||||||
id: id,
|
id: id,
|
||||||
destination: destination,
|
destination: destination,
|
||||||
status: status,
|
last: last,
|
||||||
length: len as u16,
|
length: len as u16,
|
||||||
data: *slice,
|
data: *slice,
|
||||||
},
|
},
|
||||||
|reply| match reply {
|
|reply| match reply {
|
||||||
Packet::SubkernelAddDataReply { succeeded: true } => Ok(()),
|
Packet::SubkernelAddDataReply { succeeded: true } => Ok(()),
|
||||||
Packet::SubkernelAddDataReply { succeeded: false } => Err(Error::SubkernelAddFail(destination)),
|
Packet::SubkernelAddDataReply { succeeded: false } => Err("error adding subkernel on satellite"),
|
||||||
_ => Err(Error::UnexpectedReply),
|
_ => Err("adding subkernel failed, unexpected aux packet"),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
|
@ -787,20 +673,18 @@ pub mod drtio {
|
||||||
|
|
||||||
pub async fn subkernel_load(
|
pub async fn subkernel_load(
|
||||||
aux_mutex: &Rc<Mutex<bool>>,
|
aux_mutex: &Rc<Mutex<bool>>,
|
||||||
routing_table: &RoutingTable,
|
routing_table: &drtio_routing::RoutingTable,
|
||||||
timer: GlobalTimer,
|
timer: GlobalTimer,
|
||||||
id: u32,
|
id: u32,
|
||||||
destination: u8,
|
destination: u8,
|
||||||
run: bool,
|
run: bool,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), &'static str> {
|
||||||
let linkno = routing_table.0[destination as usize][0] - 1;
|
let linkno = routing_table.0[destination as usize][0] - 1;
|
||||||
let reply = aux_transact(
|
let reply = aux_transact(
|
||||||
aux_mutex,
|
aux_mutex,
|
||||||
linkno,
|
linkno,
|
||||||
routing_table,
|
|
||||||
&Packet::SubkernelLoadRunRequest {
|
&Packet::SubkernelLoadRunRequest {
|
||||||
id: id,
|
id: id,
|
||||||
source: 0,
|
|
||||||
destination: destination,
|
destination: destination,
|
||||||
run: run,
|
run: run,
|
||||||
},
|
},
|
||||||
|
@ -808,81 +692,66 @@ pub mod drtio {
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
match reply {
|
match reply {
|
||||||
Packet::SubkernelLoadRunReply {
|
Packet::SubkernelLoadRunReply { succeeded: true } => return Ok(()),
|
||||||
destination: 0,
|
Packet::SubkernelLoadRunReply { succeeded: false } => return Err("error on subkernel run request"),
|
||||||
succeeded: true,
|
_ => return Err("received unexpected aux packet during subkernel run"),
|
||||||
} => return Ok(()),
|
|
||||||
Packet::SubkernelLoadRunReply {
|
|
||||||
destination: 0,
|
|
||||||
succeeded: false,
|
|
||||||
} => return Err(Error::SubkernelRunFail(destination)),
|
|
||||||
_ => Err(Error::UnexpectedReply),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn subkernel_retrieve_exception(
|
pub async fn subkernel_retrieve_exception(
|
||||||
aux_mutex: &Rc<Mutex<bool>>,
|
aux_mutex: &Rc<Mutex<bool>>,
|
||||||
routing_table: &RoutingTable,
|
routing_table: &drtio_routing::RoutingTable,
|
||||||
timer: GlobalTimer,
|
timer: GlobalTimer,
|
||||||
destination: u8,
|
destination: u8,
|
||||||
) -> Result<Vec<u8>, Error> {
|
) -> Result<Vec<u8>, &'static str> {
|
||||||
let linkno = routing_table.0[destination as usize][0] - 1;
|
let linkno = routing_table.0[destination as usize][0] - 1;
|
||||||
let mut remote_data: Vec<u8> = Vec::new();
|
let mut remote_data: Vec<u8> = Vec::new();
|
||||||
loop {
|
loop {
|
||||||
let reply = aux_transact(
|
let reply = aux_transact(
|
||||||
aux_mutex,
|
aux_mutex,
|
||||||
linkno,
|
linkno,
|
||||||
routing_table,
|
|
||||||
&Packet::SubkernelExceptionRequest {
|
&Packet::SubkernelExceptionRequest {
|
||||||
source: 0,
|
|
||||||
destination: destination,
|
destination: destination,
|
||||||
},
|
},
|
||||||
timer,
|
timer,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
match reply {
|
match reply {
|
||||||
Packet::SubkernelException {
|
Packet::SubkernelException { last, length, data } => {
|
||||||
destination: 0,
|
|
||||||
last,
|
|
||||||
length,
|
|
||||||
data,
|
|
||||||
} => {
|
|
||||||
remote_data.extend(&data[0..length as usize]);
|
remote_data.extend(&data[0..length as usize]);
|
||||||
if last {
|
if last {
|
||||||
return Ok(remote_data);
|
return Ok(remote_data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => return Err(Error::UnexpectedReply),
|
_ => return Err("received unexpected aux packet during subkernel exception request"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn subkernel_send_message(
|
pub async fn subkernel_send_message(
|
||||||
aux_mutex: &Rc<Mutex<bool>>,
|
aux_mutex: &Rc<Mutex<bool>>,
|
||||||
routing_table: &RoutingTable,
|
routing_table: &drtio_routing::RoutingTable,
|
||||||
timer: GlobalTimer,
|
timer: GlobalTimer,
|
||||||
id: u32,
|
id: u32,
|
||||||
destination: u8,
|
destination: u8,
|
||||||
message: &[u8],
|
message: &[u8],
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), &'static str> {
|
||||||
let linkno = routing_table.0[destination as usize][0] - 1;
|
let linkno = routing_table.0[destination as usize][0] - 1;
|
||||||
partition_data(
|
partition_data(
|
||||||
linkno,
|
linkno,
|
||||||
aux_mutex,
|
aux_mutex,
|
||||||
routing_table,
|
|
||||||
timer,
|
timer,
|
||||||
message,
|
message,
|
||||||
|slice, status, len| Packet::SubkernelMessage {
|
|slice, last, len| Packet::SubkernelMessage {
|
||||||
source: 0,
|
|
||||||
destination: destination,
|
destination: destination,
|
||||||
id: id,
|
id: id,
|
||||||
status: status,
|
last: last,
|
||||||
length: len as u16,
|
length: len as u16,
|
||||||
data: *slice,
|
data: *slice,
|
||||||
},
|
},
|
||||||
|reply| match reply {
|
|reply| match reply {
|
||||||
Packet::SubkernelMessageAck { .. } => Ok(()),
|
Packet::SubkernelMessageAck { .. } => Ok(()),
|
||||||
_ => Err(Error::UnexpectedReply),
|
_ => Err("sending message to subkernel failed, unexpected aux packet"),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
|
@ -895,46 +764,22 @@ pub mod drtio {
|
||||||
|
|
||||||
pub fn startup(
|
pub fn startup(
|
||||||
_aux_mutex: &Rc<Mutex<bool>>,
|
_aux_mutex: &Rc<Mutex<bool>>,
|
||||||
_routing_table: &Rc<RefCell<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,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn reset(_aux_mutex: Rc<Mutex<bool>>, _routing_table: &RoutingTable, mut _timer: GlobalTimer) {}
|
pub fn reset(_aux_mutex: Rc<Mutex<bool>>, mut _timer: GlobalTimer) {}
|
||||||
}
|
|
||||||
|
|
||||||
fn toggle_sed_spread(val: u8) {
|
|
||||||
unsafe {
|
|
||||||
csr::rtio_core::sed_spread_enable_write(val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn setup_sed_spread(cfg: &Config) {
|
|
||||||
if let Ok(spread_enable) = cfg.read_str("sed_spread_enable") {
|
|
||||||
match spread_enable.as_ref() {
|
|
||||||
"1" => toggle_sed_spread(1),
|
|
||||||
"0" => toggle_sed_spread(0),
|
|
||||||
_ => {
|
|
||||||
warn!("sed_spread_enable value not supported (only 1, 0 allowed), disabling by default");
|
|
||||||
toggle_sed_spread(0)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
info!("SED spreading disabled by default");
|
|
||||||
toggle_sed_spread(0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn startup(
|
pub fn startup(
|
||||||
aux_mutex: &Rc<Mutex<bool>>,
|
aux_mutex: &Rc<Mutex<bool>>,
|
||||||
routing_table: &Rc<RefCell<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]>>,
|
||||||
cfg: &Config,
|
|
||||||
timer: GlobalTimer,
|
timer: GlobalTimer,
|
||||||
) {
|
) {
|
||||||
setup_sed_spread(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);
|
||||||
|
@ -942,9 +787,9 @@ pub fn startup(
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn reset(aux_mutex: Rc<Mutex<bool>>, routing_table: &RoutingTable, timer: GlobalTimer) {
|
pub fn reset(aux_mutex: Rc<Mutex<bool>>, timer: GlobalTimer) {
|
||||||
unsafe {
|
unsafe {
|
||||||
csr::rtio_core::reset_write(1);
|
csr::rtio_core::reset_write(1);
|
||||||
}
|
}
|
||||||
drtio::reset(aux_mutex, routing_table, timer)
|
drtio::reset(aux_mutex, timer)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,19 +1,18 @@
|
||||||
use alloc::{collections::BTreeMap, rc::Rc, vec::Vec};
|
use alloc::{collections::BTreeMap, rc::Rc, vec::Vec};
|
||||||
|
|
||||||
use libasync::task;
|
use libasync::task;
|
||||||
use libboard_artiq::{drtio_routing::RoutingTable,
|
use libboard_artiq::{drtio_routing::RoutingTable, drtioaux_proto::MASTER_PAYLOAD_MAX_SIZE};
|
||||||
drtioaux_proto::{PayloadStatus, MASTER_PAYLOAD_MAX_SIZE}};
|
|
||||||
use libboard_zynq::{time::Milliseconds, timer::GlobalTimer};
|
use libboard_zynq::{time::Milliseconds, timer::GlobalTimer};
|
||||||
use libcortex_a9::mutex::Mutex;
|
use libcortex_a9::mutex::Mutex;
|
||||||
use log::{error, warn};
|
use log::error;
|
||||||
|
|
||||||
use crate::rtio_mgt::{drtio, drtio::Error as DrtioError};
|
use crate::rtio_mgt::drtio;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone, Copy)]
|
#[derive(Debug, PartialEq, Clone, Copy)]
|
||||||
pub enum FinishStatus {
|
pub enum FinishStatus {
|
||||||
Ok,
|
Ok,
|
||||||
CommLost,
|
CommLost,
|
||||||
Exception(u8), // exception source
|
Exception,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone, Copy)]
|
#[derive(Debug, PartialEq, Clone, Copy)]
|
||||||
|
@ -29,13 +28,12 @@ pub enum Error {
|
||||||
Timeout,
|
Timeout,
|
||||||
IncorrectState,
|
IncorrectState,
|
||||||
SubkernelNotFound,
|
SubkernelNotFound,
|
||||||
SubkernelException,
|
|
||||||
CommLost,
|
CommLost,
|
||||||
DrtioError(DrtioError),
|
DrtioError(&'static str),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<DrtioError> for Error {
|
impl From<&'static str> for Error {
|
||||||
fn from(value: DrtioError) -> Error {
|
fn from(value: &'static str) -> Error {
|
||||||
Error::DrtioError(value)
|
Error::DrtioError(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -121,17 +119,15 @@ pub async fn clear_subkernels() {
|
||||||
CURRENT_MESSAGES.async_lock().await.clear();
|
CURRENT_MESSAGES.async_lock().await.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn subkernel_finished(id: u32, with_exception: bool, exception_src: u8) {
|
pub async fn subkernel_finished(id: u32, with_exception: bool) {
|
||||||
// called upon receiving DRTIO SubkernelRunDone
|
// called upon receiving DRTIO SubkernelRunDone
|
||||||
// may be None if session ends and is cleared
|
// may be None if session ends and is cleared
|
||||||
if let Some(subkernel) = SUBKERNELS.async_lock().await.get_mut(&id) {
|
if let Some(subkernel) = SUBKERNELS.async_lock().await.get_mut(&id) {
|
||||||
if subkernel.state == SubkernelState::Running {
|
subkernel.state = SubkernelState::Finished {
|
||||||
subkernel.state = SubkernelState::Finished {
|
status: match with_exception {
|
||||||
status: match with_exception {
|
true => FinishStatus::Exception,
|
||||||
true => FinishStatus::Exception(exception_src),
|
false => FinishStatus::Ok,
|
||||||
false => FinishStatus::Ok,
|
},
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -169,34 +165,25 @@ pub async fn await_finish(
|
||||||
routing_table: &RoutingTable,
|
routing_table: &RoutingTable,
|
||||||
timer: GlobalTimer,
|
timer: GlobalTimer,
|
||||||
id: u32,
|
id: u32,
|
||||||
timeout: i64,
|
timeout: u64,
|
||||||
) -> Result<SubkernelFinished, Error> {
|
) -> Result<SubkernelFinished, Error> {
|
||||||
match SUBKERNELS.async_lock().await.get(&id).unwrap().state {
|
match SUBKERNELS.async_lock().await.get(&id).unwrap().state {
|
||||||
SubkernelState::Running | SubkernelState::Finished { .. } => (),
|
SubkernelState::Running | SubkernelState::Finished { .. } => (),
|
||||||
_ => return Err(Error::IncorrectState),
|
_ => return Err(Error::IncorrectState),
|
||||||
}
|
}
|
||||||
if timeout > 0 {
|
let max_time = timer.get_time() + Milliseconds(timeout);
|
||||||
let max_time = timer.get_time() + Milliseconds(timeout as u64);
|
while timer.get_time() < max_time {
|
||||||
while timer.get_time() < max_time {
|
{
|
||||||
match SUBKERNELS.async_lock().await.get(&id).unwrap().state {
|
match SUBKERNELS.async_lock().await.get(&id).unwrap().state {
|
||||||
SubkernelState::Finished { .. } => break,
|
SubkernelState::Finished { .. } => break,
|
||||||
_ => (),
|
_ => (),
|
||||||
};
|
};
|
||||||
task::r#yield().await;
|
|
||||||
}
|
|
||||||
if timer.get_time() >= max_time {
|
|
||||||
error!("Remote subkernel finish await timed out");
|
|
||||||
return Err(Error::Timeout);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// no timeout, wait forever
|
|
||||||
loop {
|
|
||||||
match SUBKERNELS.async_lock().await.get(&id).unwrap().state {
|
|
||||||
SubkernelState::Finished { .. } => break,
|
|
||||||
_ => (),
|
|
||||||
};
|
|
||||||
task::r#yield().await;
|
|
||||||
}
|
}
|
||||||
|
task::r#yield().await;
|
||||||
|
}
|
||||||
|
if timer.get_time() >= max_time {
|
||||||
|
error!("Remote subkernel finish await timed out");
|
||||||
|
return Err(Error::Timeout);
|
||||||
}
|
}
|
||||||
if let Some(subkernel) = SUBKERNELS.async_lock().await.get_mut(&id) {
|
if let Some(subkernel) = SUBKERNELS.async_lock().await.get_mut(&id) {
|
||||||
match subkernel.state {
|
match subkernel.state {
|
||||||
|
@ -205,8 +192,11 @@ pub async fn await_finish(
|
||||||
Ok(SubkernelFinished {
|
Ok(SubkernelFinished {
|
||||||
id: id,
|
id: id,
|
||||||
status: status,
|
status: status,
|
||||||
exception: if let FinishStatus::Exception(dest) = status {
|
exception: if status == FinishStatus::Exception {
|
||||||
Some(drtio::subkernel_retrieve_exception(aux_mutex, routing_table, timer, dest).await?)
|
Some(
|
||||||
|
drtio::subkernel_retrieve_exception(aux_mutex, routing_table, timer, subkernel.destination)
|
||||||
|
.await?,
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
},
|
},
|
||||||
|
@ -230,28 +220,13 @@ static MESSAGE_QUEUE: Mutex<Vec<Message>> = Mutex::new(Vec::new());
|
||||||
// currently under construction message(s) (can be from multiple sources)
|
// currently under construction message(s) (can be from multiple sources)
|
||||||
static CURRENT_MESSAGES: Mutex<BTreeMap<u32, Message>> = Mutex::new(BTreeMap::new());
|
static CURRENT_MESSAGES: Mutex<BTreeMap<u32, Message>> = Mutex::new(BTreeMap::new());
|
||||||
|
|
||||||
pub async fn message_handle_incoming(
|
pub async fn message_handle_incoming(id: u32, last: bool, length: usize, data: &[u8; MASTER_PAYLOAD_MAX_SIZE]) {
|
||||||
id: u32,
|
|
||||||
status: PayloadStatus,
|
|
||||||
length: usize,
|
|
||||||
data: &[u8; MASTER_PAYLOAD_MAX_SIZE],
|
|
||||||
) {
|
|
||||||
// called when receiving a message from satellite
|
// called when receiving a message from satellite
|
||||||
{
|
if SUBKERNELS.async_lock().await.get(&id).is_none() {
|
||||||
let subkernel_lock = SUBKERNELS.async_lock().await;
|
// do not add messages for non-existing or deleted subkernels
|
||||||
let subkernel = subkernel_lock.get(&id);
|
return;
|
||||||
if subkernel.is_some() && subkernel.unwrap().state != SubkernelState::Running {
|
|
||||||
// do not add messages for non-running or deleted subkernels
|
|
||||||
warn!("received a message for a non-running subkernel #{}", id);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
let mut current_messages = CURRENT_MESSAGES.async_lock().await;
|
let mut current_messages = CURRENT_MESSAGES.async_lock().await;
|
||||||
|
|
||||||
if status.is_first() {
|
|
||||||
current_messages.remove(&id);
|
|
||||||
}
|
|
||||||
|
|
||||||
match current_messages.get_mut(&id) {
|
match current_messages.get_mut(&id) {
|
||||||
Some(message) => message.data.extend(&data[..length]),
|
Some(message) => message.data.extend(&data[..length]),
|
||||||
None => {
|
None => {
|
||||||
|
@ -265,7 +240,7 @@ pub async fn message_handle_incoming(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if status.is_last() {
|
if last {
|
||||||
// when done, remove from working queue
|
// when done, remove from working queue
|
||||||
MESSAGE_QUEUE
|
MESSAGE_QUEUE
|
||||||
.async_lock()
|
.async_lock()
|
||||||
|
@ -274,19 +249,16 @@ pub async fn message_handle_incoming(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn message_await(id: u32, timeout: i64, timer: GlobalTimer) -> Result<Message, Error> {
|
pub async fn message_await(id: u32, timeout: u64, timer: GlobalTimer) -> Result<Message, Error> {
|
||||||
let is_subkernel = SUBKERNELS.async_lock().await.get(&id).is_some();
|
match SUBKERNELS.async_lock().await.get(&id).unwrap().state {
|
||||||
if is_subkernel {
|
SubkernelState::Finished {
|
||||||
match SUBKERNELS.async_lock().await.get(&id).unwrap().state {
|
status: FinishStatus::CommLost,
|
||||||
SubkernelState::Finished {
|
} => return Err(Error::CommLost),
|
||||||
status: FinishStatus::CommLost,
|
SubkernelState::Running | SubkernelState::Finished { .. } => (),
|
||||||
} => return Err(Error::CommLost),
|
_ => return Err(Error::IncorrectState),
|
||||||
SubkernelState::Running | SubkernelState::Finished { .. } => (),
|
|
||||||
_ => return Err(Error::IncorrectState),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
let max_time = timer.get_time() + Milliseconds(timeout as u64);
|
let max_time = timer.get_time() + Milliseconds(timeout);
|
||||||
while timeout < 0 || (timeout > 0 && timer.get_time() < max_time) {
|
while timer.get_time() < max_time {
|
||||||
{
|
{
|
||||||
let mut message_queue = MESSAGE_QUEUE.async_lock().await;
|
let mut message_queue = MESSAGE_QUEUE.async_lock().await;
|
||||||
for i in 0..message_queue.len() {
|
for i in 0..message_queue.len() {
|
||||||
|
@ -297,17 +269,6 @@ pub async fn message_await(id: u32, timeout: i64, timer: GlobalTimer) -> Result<
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if is_subkernel {
|
|
||||||
match SUBKERNELS.async_lock().await.get(&id).unwrap().state {
|
|
||||||
SubkernelState::Finished {
|
|
||||||
status: FinishStatus::CommLost,
|
|
||||||
} => return Err(Error::CommLost),
|
|
||||||
SubkernelState::Finished {
|
|
||||||
status: FinishStatus::Exception(_),
|
|
||||||
} => return Err(Error::SubkernelException),
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
task::r#yield().await;
|
task::r#yield().await;
|
||||||
}
|
}
|
||||||
Err(Error::Timeout)
|
Err(Error::Timeout)
|
||||||
|
@ -318,8 +279,9 @@ pub async fn message_send<'a>(
|
||||||
routing_table: &RoutingTable,
|
routing_table: &RoutingTable,
|
||||||
timer: GlobalTimer,
|
timer: GlobalTimer,
|
||||||
id: u32,
|
id: u32,
|
||||||
destination: u8,
|
|
||||||
message: Vec<u8>,
|
message: Vec<u8>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
|
let destination = SUBKERNELS.async_lock().await.get(&id).unwrap().destination;
|
||||||
|
// rpc data prepared by the kernel core already
|
||||||
Ok(drtio::subkernel_send_message(aux_mutex, routing_table, timer, id, destination, &message).await?)
|
Ok(drtio::subkernel_send_message(aux_mutex, routing_table, timer, id, destination, &message).await?)
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,6 @@ build = "build.rs"
|
||||||
[features]
|
[features]
|
||||||
target_zc706 = ["libboard_zynq/target_zc706", "libsupport_zynq/target_zc706", "libconfig/target_zc706", "libboard_artiq/target_zc706"]
|
target_zc706 = ["libboard_zynq/target_zc706", "libsupport_zynq/target_zc706", "libconfig/target_zc706", "libboard_artiq/target_zc706"]
|
||||||
target_kasli_soc = ["libboard_zynq/target_kasli_soc", "libsupport_zynq/target_kasli_soc", "libconfig/target_kasli_soc", "libboard_artiq/target_kasli_soc"]
|
target_kasli_soc = ["libboard_zynq/target_kasli_soc", "libsupport_zynq/target_kasli_soc", "libconfig/target_kasli_soc", "libboard_artiq/target_kasli_soc"]
|
||||||
calibrate_wrpll_skew = ["libboard_artiq/calibrate_wrpll_skew"]
|
|
||||||
default = ["target_zc706", ]
|
default = ["target_zc706", ]
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
|
|
|
@ -1,13 +1,7 @@
|
||||||
use alloc::{collections::btree_map::BTreeMap, string::String, vec::Vec};
|
use alloc::{collections::btree_map::BTreeMap, vec::Vec};
|
||||||
use core::mem;
|
|
||||||
|
|
||||||
use ksupport::kernel::DmaRecorder;
|
use libboard_artiq::pl::csr;
|
||||||
use libboard_artiq::{drtio_routing::RoutingTable,
|
|
||||||
drtioaux_proto::{Packet, PayloadStatus, MASTER_PAYLOAD_MAX_SIZE},
|
|
||||||
pl::csr};
|
|
||||||
use libcortex_a9::cache::dcci_slice;
|
use libcortex_a9::cache::dcci_slice;
|
||||||
use routing::{Router, Sliceable};
|
|
||||||
use subkernel::Manager as KernelManager;
|
|
||||||
|
|
||||||
const ALIGNMENT: usize = 64;
|
const ALIGNMENT: usize = 64;
|
||||||
|
|
||||||
|
@ -18,20 +12,16 @@ enum ManagerState {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct RtioStatus {
|
pub struct RtioStatus {
|
||||||
pub source: u8,
|
|
||||||
pub id: u32,
|
pub id: u32,
|
||||||
pub error: u8,
|
pub error: u8,
|
||||||
pub channel: u32,
|
pub channel: u32,
|
||||||
pub timestamp: u64,
|
pub timestamp: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
IdNotFound,
|
IdNotFound,
|
||||||
PlaybackInProgress,
|
PlaybackInProgress,
|
||||||
EntryNotComplete,
|
EntryNotComplete,
|
||||||
MasterDmaFound,
|
|
||||||
UploadFail,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -39,228 +29,13 @@ struct Entry {
|
||||||
trace: Vec<u8>,
|
trace: Vec<u8>,
|
||||||
padding_len: usize,
|
padding_len: usize,
|
||||||
complete: bool,
|
complete: bool,
|
||||||
duration: i64, // relevant for local DMA
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Entry {
|
|
||||||
pub fn from_vec(data: Vec<u8>, duration: i64) -> Entry {
|
|
||||||
let mut entry = Entry {
|
|
||||||
trace: data,
|
|
||||||
padding_len: 0,
|
|
||||||
complete: true,
|
|
||||||
duration: duration,
|
|
||||||
};
|
|
||||||
entry.realign();
|
|
||||||
entry
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn id(&self) -> u32 {
|
|
||||||
self.trace[self.padding_len..].as_ptr() as u32
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn realign(&mut self) {
|
|
||||||
self.trace.push(0);
|
|
||||||
let data_len = self.trace.len();
|
|
||||||
|
|
||||||
self.trace.reserve(ALIGNMENT - 1);
|
|
||||||
let padding = ALIGNMENT - self.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
|
|
||||||
self.trace.push(0)
|
|
||||||
}
|
|
||||||
for i in 1..data_len + 1 {
|
|
||||||
self.trace[data_len + padding - i] = self.trace[data_len - i]
|
|
||||||
}
|
|
||||||
self.complete = true;
|
|
||||||
self.padding_len = padding;
|
|
||||||
|
|
||||||
dcci_slice(&self.trace);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
enum RemoteTraceState {
|
|
||||||
Unsent,
|
|
||||||
Sending(usize),
|
|
||||||
Ready,
|
|
||||||
Running(usize),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct RemoteTraces {
|
|
||||||
remote_traces: BTreeMap<u8, Sliceable>,
|
|
||||||
state: RemoteTraceState,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RemoteTraces {
|
|
||||||
pub fn new(traces: BTreeMap<u8, Sliceable>) -> RemoteTraces {
|
|
||||||
RemoteTraces {
|
|
||||||
remote_traces: traces,
|
|
||||||
state: RemoteTraceState::Unsent,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// on subkernel request
|
|
||||||
pub fn upload_traces(
|
|
||||||
&mut self,
|
|
||||||
id: u32,
|
|
||||||
router: &mut Router,
|
|
||||||
rank: u8,
|
|
||||||
self_destination: u8,
|
|
||||||
routing_table: &RoutingTable,
|
|
||||||
) -> usize {
|
|
||||||
let len = self.remote_traces.len();
|
|
||||||
if len > 0 {
|
|
||||||
self.state = RemoteTraceState::Sending(self.remote_traces.len());
|
|
||||||
for (dest, trace) in self.remote_traces.iter_mut() {
|
|
||||||
// queue up the first packet for all destinations, rest will be sent after first ACK
|
|
||||||
let mut data_slice: [u8; MASTER_PAYLOAD_MAX_SIZE] = [0; MASTER_PAYLOAD_MAX_SIZE];
|
|
||||||
let meta = trace.get_slice_master(&mut data_slice);
|
|
||||||
router.route(
|
|
||||||
Packet::DmaAddTraceRequest {
|
|
||||||
source: self_destination,
|
|
||||||
destination: *dest,
|
|
||||||
id: id,
|
|
||||||
status: meta.status,
|
|
||||||
length: meta.len,
|
|
||||||
trace: data_slice,
|
|
||||||
},
|
|
||||||
routing_table,
|
|
||||||
rank,
|
|
||||||
self_destination,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
len
|
|
||||||
}
|
|
||||||
|
|
||||||
// on incoming Packet::DmaAddTraceReply
|
|
||||||
pub fn ack_upload(
|
|
||||||
&mut self,
|
|
||||||
kernel_manager: &mut KernelManager,
|
|
||||||
source: u8,
|
|
||||||
id: u32,
|
|
||||||
succeeded: bool,
|
|
||||||
router: &mut Router,
|
|
||||||
rank: u8,
|
|
||||||
self_destination: u8,
|
|
||||||
routing_table: &RoutingTable,
|
|
||||||
) {
|
|
||||||
if let RemoteTraceState::Sending(count) = self.state {
|
|
||||||
if let Some(trace) = self.remote_traces.get_mut(&source) {
|
|
||||||
if trace.at_end() {
|
|
||||||
if count - 1 == 0 {
|
|
||||||
self.state = RemoteTraceState::Ready;
|
|
||||||
if let Some((id, timestamp)) = kernel_manager.ddma_remote_uploaded(succeeded) {
|
|
||||||
self.playback(id, timestamp, router, rank, self_destination, routing_table);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
self.state = RemoteTraceState::Sending(count - 1);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// send next slice
|
|
||||||
let mut data_slice: [u8; MASTER_PAYLOAD_MAX_SIZE] = [0; MASTER_PAYLOAD_MAX_SIZE];
|
|
||||||
let meta = trace.get_slice_master(&mut data_slice);
|
|
||||||
router.route(
|
|
||||||
Packet::DmaAddTraceRequest {
|
|
||||||
source: self_destination,
|
|
||||||
destination: meta.destination,
|
|
||||||
id: id,
|
|
||||||
status: meta.status,
|
|
||||||
length: meta.len,
|
|
||||||
trace: data_slice,
|
|
||||||
},
|
|
||||||
routing_table,
|
|
||||||
rank,
|
|
||||||
self_destination,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// on subkernel request
|
|
||||||
pub fn playback(
|
|
||||||
&mut self,
|
|
||||||
id: u32,
|
|
||||||
timestamp: u64,
|
|
||||||
router: &mut Router,
|
|
||||||
rank: u8,
|
|
||||||
self_destination: u8,
|
|
||||||
routing_table: &RoutingTable,
|
|
||||||
) {
|
|
||||||
// route all the playback requests
|
|
||||||
// remote traces (local trace runs on core1 unlike mainline firmware)
|
|
||||||
self.state = RemoteTraceState::Running(self.remote_traces.len());
|
|
||||||
for (dest, _) in self.remote_traces.iter() {
|
|
||||||
router.route(
|
|
||||||
Packet::DmaPlaybackRequest {
|
|
||||||
source: self_destination,
|
|
||||||
destination: *dest,
|
|
||||||
id: id,
|
|
||||||
timestamp: timestamp,
|
|
||||||
},
|
|
||||||
routing_table,
|
|
||||||
rank,
|
|
||||||
self_destination,
|
|
||||||
);
|
|
||||||
// response will be ignored (succeeded = false handled by the main thread)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// on incoming Packet::DmaPlaybackDone
|
|
||||||
pub fn remote_finished(&mut self, kernel_manager: &mut KernelManager, error: u8, channel: u32, timestamp: u64) {
|
|
||||||
if let RemoteTraceState::Running(count) = self.state {
|
|
||||||
if error != 0 || count - 1 == 0 {
|
|
||||||
// notify the kernel about a DDMA error or finish
|
|
||||||
kernel_manager.ddma_finished(error, channel, timestamp);
|
|
||||||
self.state = RemoteTraceState::Ready;
|
|
||||||
// further messages will be ignored (if there was an error)
|
|
||||||
} else {
|
|
||||||
// no error and not the last one awaited
|
|
||||||
self.state = RemoteTraceState::Running(count - 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn erase(
|
|
||||||
&mut self,
|
|
||||||
id: u32,
|
|
||||||
router: &mut Router,
|
|
||||||
rank: u8,
|
|
||||||
self_destination: u8,
|
|
||||||
routing_table: &RoutingTable,
|
|
||||||
) {
|
|
||||||
for (dest, _) in self.remote_traces.iter() {
|
|
||||||
router.route(
|
|
||||||
Packet::DmaRemoveTraceRequest {
|
|
||||||
source: self_destination,
|
|
||||||
destination: *dest,
|
|
||||||
id: id,
|
|
||||||
},
|
|
||||||
routing_table,
|
|
||||||
rank,
|
|
||||||
self_destination,
|
|
||||||
);
|
|
||||||
// response will be ignored as this object will stop existing too
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn has_remote_traces(&self) -> bool {
|
|
||||||
self.remote_traces.len() > 0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Manager {
|
pub struct Manager {
|
||||||
entries: BTreeMap<(u8, u32), Entry>,
|
entries: BTreeMap<u32, Entry>,
|
||||||
state: ManagerState,
|
state: ManagerState,
|
||||||
current_id: u32,
|
currentid: u32,
|
||||||
current_source: u8,
|
|
||||||
|
|
||||||
remote_entries: BTreeMap<u32, RemoteTraces>,
|
|
||||||
name_map: BTreeMap<String, u32>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Manager {
|
impl Manager {
|
||||||
|
@ -270,238 +45,79 @@ impl Manager {
|
||||||
unsafe { while csr::rtio_dma::enable_read() != 0 {} }
|
unsafe { while csr::rtio_dma::enable_read() != 0 {} }
|
||||||
Manager {
|
Manager {
|
||||||
entries: BTreeMap::new(),
|
entries: BTreeMap::new(),
|
||||||
current_id: 0,
|
currentid: 0,
|
||||||
current_source: 0,
|
|
||||||
state: ManagerState::Idle,
|
state: ManagerState::Idle,
|
||||||
remote_entries: BTreeMap::new(),
|
|
||||||
name_map: BTreeMap::new(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add(
|
pub fn add(&mut self, id: u32, last: bool, trace: &[u8], trace_len: usize) -> Result<(), Error> {
|
||||||
&mut self,
|
let entry = match self.entries.get_mut(&id) {
|
||||||
source: u8,
|
|
||||||
id: u32,
|
|
||||||
status: PayloadStatus,
|
|
||||||
trace: &[u8],
|
|
||||||
trace_len: usize,
|
|
||||||
) -> Result<(), Error> {
|
|
||||||
let entry = match self.entries.get_mut(&(source, id)) {
|
|
||||||
Some(entry) => {
|
Some(entry) => {
|
||||||
if entry.complete || status.is_first() {
|
if entry.complete {
|
||||||
// replace entry
|
// replace entry
|
||||||
self.entries.remove(&(source, id));
|
self.entries.remove(&id);
|
||||||
self.entries.insert(
|
self.entries.insert(
|
||||||
(source, id),
|
id,
|
||||||
Entry {
|
Entry {
|
||||||
trace: Vec::new(),
|
trace: Vec::new(),
|
||||||
padding_len: 0,
|
padding_len: 0,
|
||||||
complete: false,
|
complete: false,
|
||||||
duration: 0,
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
self.entries.get_mut(&(source, id)).unwrap()
|
self.entries.get_mut(&id).unwrap()
|
||||||
} else {
|
} else {
|
||||||
entry
|
entry
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
self.entries.insert(
|
self.entries.insert(
|
||||||
(source, id),
|
id,
|
||||||
Entry {
|
Entry {
|
||||||
trace: Vec::new(),
|
trace: Vec::new(),
|
||||||
padding_len: 0,
|
padding_len: 0,
|
||||||
complete: false,
|
complete: false,
|
||||||
duration: 0,
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
self.entries.get_mut(&(source, id)).unwrap()
|
self.entries.get_mut(&id).unwrap()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
entry.trace.extend(&trace[0..trace_len]);
|
entry.trace.extend(&trace[0..trace_len]);
|
||||||
|
|
||||||
if status.is_last() {
|
if last {
|
||||||
entry.realign();
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
// api for DRTIO
|
pub fn erase(&mut self, id: u32) -> Result<(), Error> {
|
||||||
pub fn erase(&mut self, source: u8, id: u32) -> Result<(), Error> {
|
match self.entries.remove(&id) {
|
||||||
match self.entries.remove(&(source, id)) {
|
|
||||||
Some(_) => Ok(()),
|
Some(_) => Ok(()),
|
||||||
None => Err(Error::IdNotFound),
|
None => Err(Error::IdNotFound),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// API for subkernel
|
pub fn playback(&mut self, id: u32, timestamp: u64) -> Result<(), Error> {
|
||||||
pub fn erase_name(
|
|
||||||
&mut self,
|
|
||||||
name: &str,
|
|
||||||
router: &mut Router,
|
|
||||||
rank: u8,
|
|
||||||
self_destination: u8,
|
|
||||||
routing_table: &RoutingTable,
|
|
||||||
) {
|
|
||||||
if let Some(id) = self.name_map.get(name) {
|
|
||||||
if let Some(traces) = self.remote_entries.get_mut(&id) {
|
|
||||||
traces.erase(*id, router, rank, self_destination, routing_table);
|
|
||||||
self.remote_entries.remove(&id);
|
|
||||||
}
|
|
||||||
self.entries.remove(&(self_destination, *id));
|
|
||||||
self.name_map.remove(name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn remote_finished(
|
|
||||||
&mut self,
|
|
||||||
kernel_manager: &mut KernelManager,
|
|
||||||
id: u32,
|
|
||||||
error: u8,
|
|
||||||
channel: u32,
|
|
||||||
timestamp: u64,
|
|
||||||
) {
|
|
||||||
if let Some(entry) = self.remote_entries.get_mut(&id) {
|
|
||||||
entry.remote_finished(kernel_manager, error, channel, timestamp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn ack_upload(
|
|
||||||
&mut self,
|
|
||||||
kernel_manager: &mut KernelManager,
|
|
||||||
source: u8,
|
|
||||||
id: u32,
|
|
||||||
succeeded: bool,
|
|
||||||
router: &mut Router,
|
|
||||||
rank: u8,
|
|
||||||
self_destination: u8,
|
|
||||||
routing_table: &RoutingTable,
|
|
||||||
) {
|
|
||||||
if let Some(entry) = self.remote_entries.get_mut(&id) {
|
|
||||||
entry.ack_upload(
|
|
||||||
kernel_manager,
|
|
||||||
source,
|
|
||||||
id,
|
|
||||||
succeeded,
|
|
||||||
router,
|
|
||||||
rank,
|
|
||||||
self_destination,
|
|
||||||
routing_table,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// API for subkernel
|
|
||||||
pub fn upload_traces(
|
|
||||||
&mut self,
|
|
||||||
id: u32,
|
|
||||||
router: &mut Router,
|
|
||||||
rank: u8,
|
|
||||||
self_destination: u8,
|
|
||||||
routing_table: &RoutingTable,
|
|
||||||
) -> Result<usize, Error> {
|
|
||||||
let remote_traces = self.remote_entries.get_mut(&id);
|
|
||||||
let mut len = 0;
|
|
||||||
if let Some(traces) = remote_traces {
|
|
||||||
len = traces.upload_traces(id, router, rank, self_destination, routing_table);
|
|
||||||
}
|
|
||||||
Ok(len)
|
|
||||||
}
|
|
||||||
|
|
||||||
// API for subkernel
|
|
||||||
pub fn playback_remote(
|
|
||||||
&mut self,
|
|
||||||
id: u32,
|
|
||||||
timestamp: u64,
|
|
||||||
router: &mut Router,
|
|
||||||
rank: u8,
|
|
||||||
self_destination: u8,
|
|
||||||
routing_table: &RoutingTable,
|
|
||||||
) -> Result<(), Error> {
|
|
||||||
if let Some(traces) = self.remote_entries.get_mut(&id) {
|
|
||||||
traces.playback(id, timestamp, router, rank, self_destination, routing_table);
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(Error::IdNotFound)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// API for subkernel
|
|
||||||
pub fn cleanup(&mut self, router: &mut Router, rank: u8, self_destination: u8, routing_table: &RoutingTable) {
|
|
||||||
// after subkernel ends, remove all self-generated traces
|
|
||||||
for (_, id) in self.name_map.iter_mut() {
|
|
||||||
if let Some(traces) = self.remote_entries.get_mut(&id) {
|
|
||||||
traces.erase(*id, router, rank, self_destination, routing_table);
|
|
||||||
self.remote_entries.remove(&id);
|
|
||||||
}
|
|
||||||
self.entries.remove(&(self_destination, *id));
|
|
||||||
}
|
|
||||||
self.name_map.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
// API for subkernel
|
|
||||||
pub fn retrieve(&self, self_destination: u8, name: &String) -> Option<(i32, i64, bool)> {
|
|
||||||
let id = self.name_map.get(name)?;
|
|
||||||
let duration = self.entries.get(&(self_destination, *id))?.duration;
|
|
||||||
let uses_ddma = self.has_remote_traces(*id);
|
|
||||||
Some((*id as i32, duration, uses_ddma))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn has_remote_traces(&self, id: u32) -> bool {
|
|
||||||
match self.remote_entries.get(&id) {
|
|
||||||
Some(traces) => traces.has_remote_traces(),
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn put_record(&mut self, mut recorder: DmaRecorder, self_destination: u8) -> Result<u32, Error> {
|
|
||||||
let mut remote_traces: BTreeMap<u8, Sliceable> = BTreeMap::new();
|
|
||||||
|
|
||||||
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 {
|
|
||||||
return Err(Error::MasterDmaFound);
|
|
||||||
} else if destination == self_destination {
|
|
||||||
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,
|
|
||||||
Sliceable::new(destination, recorder.buffer[ptr..ptr + len].to_vec()),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// and jump to the next event
|
|
||||||
ptr += len;
|
|
||||||
}
|
|
||||||
let local_entry = Entry::from_vec(local_trace, recorder.duration);
|
|
||||||
|
|
||||||
let id = local_entry.id();
|
|
||||||
self.entries.insert((self_destination, id), local_entry);
|
|
||||||
self.remote_entries.insert(id, RemoteTraces::new(remote_traces));
|
|
||||||
let mut name = String::new();
|
|
||||||
mem::swap(&mut recorder.name, &mut name);
|
|
||||||
self.name_map.insert(name, id);
|
|
||||||
|
|
||||||
Ok(id)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn playback(&mut self, source: u8, id: u32, timestamp: u64) -> Result<(), Error> {
|
|
||||||
if self.state != ManagerState::Idle {
|
if self.state != ManagerState::Idle {
|
||||||
return Err(Error::PlaybackInProgress);
|
return Err(Error::PlaybackInProgress);
|
||||||
}
|
}
|
||||||
|
|
||||||
let entry = match self.entries.get(&(source, id)) {
|
let entry = match self.entries.get(&id) {
|
||||||
Some(entry) => entry,
|
Some(entry) => entry,
|
||||||
None => {
|
None => {
|
||||||
return Err(Error::IdNotFound);
|
return Err(Error::IdNotFound);
|
||||||
|
@ -514,8 +130,7 @@ impl Manager {
|
||||||
assert!(ptr as u32 % 64 == 0);
|
assert!(ptr as u32 % 64 == 0);
|
||||||
|
|
||||||
self.state = ManagerState::Playback;
|
self.state = ManagerState::Playback;
|
||||||
self.current_id = id;
|
self.currentid = id;
|
||||||
self.current_source = source;
|
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
csr::rtio_dma::base_address_write(ptr as u32);
|
csr::rtio_dma::base_address_write(ptr as u32);
|
||||||
|
@ -547,8 +162,7 @@ impl Manager {
|
||||||
csr::rtio_dma::error_write(1);
|
csr::rtio_dma::error_write(1);
|
||||||
}
|
}
|
||||||
return Some(RtioStatus {
|
return Some(RtioStatus {
|
||||||
source: self.current_source,
|
id: self.currentid,
|
||||||
id: self.current_id,
|
|
||||||
error: error,
|
error: error,
|
||||||
channel: channel,
|
channel: channel,
|
||||||
timestamp: timestamp,
|
timestamp: timestamp,
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -6,7 +6,6 @@ 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;
|
use libboard_zynq::timer::GlobalTimer;
|
||||||
use routing::Router;
|
|
||||||
|
|
||||||
#[cfg(has_drtio_routing)]
|
#[cfg(has_drtio_routing)]
|
||||||
fn rep_link_rx_up(repno: u8) -> bool {
|
fn rep_link_rx_up(repno: u8) -> bool {
|
||||||
|
@ -54,14 +53,7 @@ impl Repeater {
|
||||||
self.state == RepeaterState::Up
|
self.state == RepeaterState::Up
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn service(
|
pub fn service(&mut self, routing_table: &drtio_routing::RoutingTable, rank: u8, timer: &mut GlobalTimer) {
|
||||||
&mut self,
|
|
||||||
routing_table: &drtio_routing::RoutingTable,
|
|
||||||
rank: u8,
|
|
||||||
destination: u8,
|
|
||||||
router: &mut Router,
|
|
||||||
timer: &mut GlobalTimer,
|
|
||||||
) {
|
|
||||||
self.process_local_errors();
|
self.process_local_errors();
|
||||||
|
|
||||||
match self.state {
|
match self.state {
|
||||||
|
@ -87,10 +79,6 @@ impl Repeater {
|
||||||
if rep_link_rx_up(self.repno) {
|
if rep_link_rx_up(self.repno) {
|
||||||
if let Ok(Some(drtioaux::Packet::EchoReply)) = drtioaux::recv(self.auxno) {
|
if let Ok(Some(drtioaux::Packet::EchoReply)) = drtioaux::recv(self.auxno) {
|
||||||
info!("[REP#{}] remote replied after {} packets", self.repno, ping_count);
|
info!("[REP#{}] remote replied after {} packets", self.repno, ping_count);
|
||||||
let max_time = timer.get_time() + Milliseconds(200);
|
|
||||||
while timer.get_time() < max_time {
|
|
||||||
let _ = drtioaux::recv(self.auxno);
|
|
||||||
}
|
|
||||||
self.state = RepeaterState::Up;
|
self.state = RepeaterState::Up;
|
||||||
if let Err(e) = self.sync_tsc(timer) {
|
if let Err(e) = self.sync_tsc(timer) {
|
||||||
error!("[REP#{}] failed to sync TSC ({:?})", self.repno, e);
|
error!("[REP#{}] failed to sync TSC ({:?})", self.repno, e);
|
||||||
|
@ -123,7 +111,7 @@ impl Repeater {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
RepeaterState::Up => {
|
RepeaterState::Up => {
|
||||||
self.process_unsolicited_aux(routing_table, rank, destination, router);
|
self.process_unsolicited_aux();
|
||||||
if !rep_link_rx_up(self.repno) {
|
if !rep_link_rx_up(self.repno) {
|
||||||
info!("[REP#{}] link is down", self.repno);
|
info!("[REP#{}] link is down", self.repno);
|
||||||
self.state = RepeaterState::Down;
|
self.state = RepeaterState::Down;
|
||||||
|
@ -138,15 +126,9 @@ impl Repeater {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_unsolicited_aux(
|
fn process_unsolicited_aux(&self) {
|
||||||
&self,
|
|
||||||
routing_table: &drtio_routing::RoutingTable,
|
|
||||||
rank: u8,
|
|
||||||
destination: u8,
|
|
||||||
router: &mut Router,
|
|
||||||
) {
|
|
||||||
match drtioaux::recv(self.auxno) {
|
match drtioaux::recv(self.auxno) {
|
||||||
Ok(Some(packet)) => router.route(packet, routing_table, rank, destination),
|
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),
|
||||||
}
|
}
|
||||||
|
@ -208,45 +190,14 @@ impl Repeater {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn aux_forward(
|
pub fn aux_forward(&self, request: &drtioaux::Packet, timer: &mut GlobalTimer) -> Result<(), drtioaux::Error> {
|
||||||
&self,
|
|
||||||
request: &drtioaux::Packet,
|
|
||||||
router: &mut Router,
|
|
||||||
routing_table: &drtio_routing::RoutingTable,
|
|
||||||
rank: u8,
|
|
||||||
self_destination: u8,
|
|
||||||
timer: &mut GlobalTimer,
|
|
||||||
) -> Result<(), drtioaux::Error> {
|
|
||||||
self.aux_send(request)?;
|
|
||||||
loop {
|
|
||||||
let reply = self.recv_aux_timeout(200, timer)?;
|
|
||||||
match reply {
|
|
||||||
// async/locally requested packets to be consumed or routed
|
|
||||||
// these may come while a packet would be forwarded
|
|
||||||
drtioaux::Packet::DmaPlaybackStatus { .. }
|
|
||||||
| drtioaux::Packet::SubkernelFinished { .. }
|
|
||||||
| drtioaux::Packet::SubkernelMessage { .. }
|
|
||||||
| drtioaux::Packet::SubkernelMessageAck { .. }
|
|
||||||
| drtioaux::Packet::SubkernelLoadRunReply { .. }
|
|
||||||
| drtioaux::Packet::SubkernelException { .. }
|
|
||||||
| drtioaux::Packet::DmaAddTraceReply { .. }
|
|
||||||
| drtioaux::Packet::DmaPlaybackReply { .. } => {
|
|
||||||
router.route(reply, routing_table, rank, self_destination);
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
drtioaux::send(0, &reply).unwrap();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn aux_send(&self, request: &drtioaux::Packet) -> Result<(), drtioaux::Error> {
|
|
||||||
if self.state != RepeaterState::Up {
|
if self.state != RepeaterState::Up {
|
||||||
return Err(drtioaux::Error::LinkDown);
|
return Err(drtioaux::Error::LinkDown);
|
||||||
}
|
}
|
||||||
drtioaux::send(self.auxno, request)
|
drtioaux::send(self.auxno, request).unwrap();
|
||||||
|
let reply = self.recv_aux_timeout(200, timer)?;
|
||||||
|
drtioaux::send(0, &reply).unwrap();
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sync_tsc(&self, timer: &mut GlobalTimer) -> Result<(), drtioaux::Error> {
|
pub fn sync_tsc(&self, timer: &mut GlobalTimer) -> Result<(), drtioaux::Error> {
|
||||||
|
@ -351,15 +302,7 @@ impl Repeater {
|
||||||
Repeater::default()
|
Repeater::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn service(
|
pub fn service(&self, _routing_table: &drtio_routing::RoutingTable, _rank: u8, _timer: &mut GlobalTimer) {}
|
||||||
&self,
|
|
||||||
_routing_table: &drtio_routing::RoutingTable,
|
|
||||||
_rank: u8,
|
|
||||||
_destination: u8,
|
|
||||||
_router: &mut Router,
|
|
||||||
_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(())
|
||||||
|
|
|
@ -1,173 +0,0 @@
|
||||||
use alloc::{collections::vec_deque::VecDeque, vec::Vec};
|
|
||||||
use core::cmp::min;
|
|
||||||
|
|
||||||
#[cfg(has_drtio_routing)]
|
|
||||||
use libboard_artiq::pl::csr;
|
|
||||||
use libboard_artiq::{drtio_routing, drtioaux,
|
|
||||||
drtioaux_proto::{PayloadStatus, MASTER_PAYLOAD_MAX_SIZE}};
|
|
||||||
|
|
||||||
pub struct SliceMeta {
|
|
||||||
pub destination: u8,
|
|
||||||
pub len: u16,
|
|
||||||
pub status: PayloadStatus,
|
|
||||||
}
|
|
||||||
|
|
||||||
/* represents data that has to be sent to Master */
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Sliceable {
|
|
||||||
it: usize,
|
|
||||||
data: Vec<u8>,
|
|
||||||
destination: u8,
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! get_slice_fn {
|
|
||||||
($name:tt, $size:expr) => {
|
|
||||||
pub fn $name(&mut self, data_slice: &mut [u8; $size]) -> SliceMeta {
|
|
||||||
let first = self.it == 0;
|
|
||||||
let len = min($size, self.data.len() - self.it);
|
|
||||||
let last = self.it + len == self.data.len();
|
|
||||||
let status = PayloadStatus::from_status(first, last);
|
|
||||||
|
|
||||||
data_slice[..len].clone_from_slice(&self.data[self.it..self.it + len]);
|
|
||||||
self.it += len;
|
|
||||||
|
|
||||||
SliceMeta {
|
|
||||||
destination: self.destination,
|
|
||||||
len: len as u16,
|
|
||||||
status: status,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Sliceable {
|
|
||||||
pub fn new(destination: u8, data: Vec<u8>) -> Sliceable {
|
|
||||||
Sliceable {
|
|
||||||
it: 0,
|
|
||||||
data: data,
|
|
||||||
destination: destination,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn at_end(&self) -> bool {
|
|
||||||
self.it == self.data.len()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn extend(&mut self, data: &[u8]) {
|
|
||||||
self.data.extend(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
get_slice_fn!(get_slice_master, MASTER_PAYLOAD_MAX_SIZE);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Packets from downstream (further satellites) are received and routed appropriately.
|
|
||||||
// they're passed as soon as possible downstream (within the subtree), or sent upstream,
|
|
||||||
// which is notified about pending packets.
|
|
||||||
// for rank 1 (connected to master) satellites, these packets are passed as an answer to DestinationStatusRequest;
|
|
||||||
// for higher ranks, after getting a notification, it will transact with downstream to get the pending packets.
|
|
||||||
|
|
||||||
// forward! macro is not deprecated, as routable packets are only these that can originate
|
|
||||||
// from both master and satellite, e.g. DDMA and Subkernel.
|
|
||||||
|
|
||||||
pub struct Router {
|
|
||||||
upstream_queue: VecDeque<drtioaux::Packet>,
|
|
||||||
local_queue: VecDeque<drtioaux::Packet>,
|
|
||||||
#[cfg(has_drtio_routing)]
|
|
||||||
downstream_queue: VecDeque<(usize, drtioaux::Packet)>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Router {
|
|
||||||
pub fn new() -> Router {
|
|
||||||
Router {
|
|
||||||
upstream_queue: VecDeque::new(),
|
|
||||||
local_queue: VecDeque::new(),
|
|
||||||
#[cfg(has_drtio_routing)]
|
|
||||||
downstream_queue: VecDeque::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Called by local sources (DDMA, kernel) and by repeaters on receiving async data;
|
|
||||||
// messages are always buffered for both upstream and downstream
|
|
||||||
pub fn route(
|
|
||||||
&mut self,
|
|
||||||
packet: drtioaux::Packet,
|
|
||||||
_routing_table: &drtio_routing::RoutingTable,
|
|
||||||
_rank: u8,
|
|
||||||
self_destination: u8,
|
|
||||||
) {
|
|
||||||
let destination = packet.routable_destination();
|
|
||||||
#[cfg(has_drtio_routing)]
|
|
||||||
{
|
|
||||||
if let Some(destination) = destination {
|
|
||||||
let hop = _routing_table.0[destination as usize][_rank as usize] as usize;
|
|
||||||
if destination == self_destination {
|
|
||||||
self.local_queue.push_back(packet);
|
|
||||||
} else if hop > 0 && hop < csr::DRTIOREP.len() {
|
|
||||||
let repno = (hop - 1) as usize;
|
|
||||||
self.downstream_queue.push_back((repno, packet));
|
|
||||||
} else {
|
|
||||||
self.upstream_queue.push_back(packet);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
error!("Received an unroutable packet: {:?}", packet);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[cfg(not(has_drtio_routing))]
|
|
||||||
{
|
|
||||||
if destination == Some(self_destination) {
|
|
||||||
self.local_queue.push_back(packet);
|
|
||||||
} else {
|
|
||||||
self.upstream_queue.push_back(packet);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sends a packet to a required destination, routing if necessary
|
|
||||||
pub fn send(
|
|
||||||
&mut self,
|
|
||||||
packet: drtioaux::Packet,
|
|
||||||
_routing_table: &drtio_routing::RoutingTable,
|
|
||||||
_rank: u8,
|
|
||||||
_destination: u8,
|
|
||||||
) -> Result<(), drtioaux::Error> {
|
|
||||||
#[cfg(has_drtio_routing)]
|
|
||||||
{
|
|
||||||
let destination = packet.routable_destination();
|
|
||||||
if let Some(destination) = destination {
|
|
||||||
let hop = _routing_table.0[destination as usize][_rank as usize] as usize;
|
|
||||||
if destination == 0 {
|
|
||||||
// response is needed immediately if master required it
|
|
||||||
drtioaux::send(0, &packet)?;
|
|
||||||
} else if !(hop > 0 && hop < csr::DRTIOREP.len()) {
|
|
||||||
// higher rank can wait
|
|
||||||
self.upstream_queue.push_back(packet);
|
|
||||||
} else {
|
|
||||||
let repno = (hop - 1) as usize;
|
|
||||||
// transaction will occur at closest possible opportunity
|
|
||||||
self.downstream_queue.push_back((repno, packet));
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
// packet not supported in routing, fallback - sent directly
|
|
||||||
drtioaux::send(0, &packet)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[cfg(not(has_drtio_routing))]
|
|
||||||
{
|
|
||||||
drtioaux::send(0, &packet)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_upstream_packet(&mut self) -> Option<drtioaux::Packet> {
|
|
||||||
self.upstream_queue.pop_front()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(has_drtio_routing)]
|
|
||||||
pub fn get_downstream_packet(&mut self) -> Option<(usize, drtioaux::Packet)> {
|
|
||||||
self.downstream_queue.pop_front()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_local_packet(&mut self) -> Option<drtioaux::Packet> {
|
|
||||||
self.local_queue.pop_front()
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,55 +1,26 @@
|
||||||
use alloc::{collections::BTreeMap,
|
use alloc::{collections::{BTreeMap, VecDeque},
|
||||||
format,
|
format,
|
||||||
string::{String, ToString},
|
string::{String, ToString},
|
||||||
vec::Vec};
|
vec::Vec};
|
||||||
use core::{option::NoneError, slice, str};
|
use core::{cmp::min, option::NoneError, slice, str};
|
||||||
|
|
||||||
use core_io::{Error as IoError, Write};
|
use core_io::{Error as IoError, Write};
|
||||||
use cslice::AsCSlice;
|
use cslice::AsCSlice;
|
||||||
use dma::{Error as DmaError, Manager as DmaManager};
|
|
||||||
use io::{Cursor, ProtoWrite};
|
use io::{Cursor, ProtoWrite};
|
||||||
use ksupport::{eh_artiq, kernel, rpc};
|
use ksupport::{eh_artiq, kernel, rpc};
|
||||||
use libboard_artiq::{drtio_routing::RoutingTable,
|
use libboard_artiq::{drtioaux_proto::{MASTER_PAYLOAD_MAX_SIZE, SAT_PAYLOAD_MAX_SIZE},
|
||||||
drtioaux,
|
|
||||||
drtioaux_proto::{PayloadStatus, MASTER_PAYLOAD_MAX_SIZE},
|
|
||||||
pl::csr};
|
pl::csr};
|
||||||
use libboard_zynq::{time::Milliseconds, timer::GlobalTimer};
|
use libboard_zynq::{time::Milliseconds, timer::GlobalTimer};
|
||||||
use libcortex_a9::sync_channel::Receiver;
|
use libcortex_a9::sync_channel::Receiver;
|
||||||
use log::warn;
|
use log::warn;
|
||||||
use routing::{Router, SliceMeta, Sliceable};
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
enum KernelState {
|
enum KernelState {
|
||||||
Absent,
|
Absent,
|
||||||
Loaded,
|
Loaded,
|
||||||
Running,
|
Running,
|
||||||
MsgAwait {
|
MsgAwait(Milliseconds, Vec<u8>),
|
||||||
max_time: Option<Milliseconds>,
|
|
||||||
id: u32,
|
|
||||||
tags: Vec<u8>,
|
|
||||||
},
|
|
||||||
MsgSending,
|
MsgSending,
|
||||||
SubkernelAwaitLoad,
|
|
||||||
SubkernelAwaitFinish {
|
|
||||||
max_time: Option<Milliseconds>,
|
|
||||||
id: u32,
|
|
||||||
},
|
|
||||||
DmaUploading,
|
|
||||||
DmaPendingPlayback {
|
|
||||||
id: u32,
|
|
||||||
timestamp: u64,
|
|
||||||
},
|
|
||||||
DmaPendingAwait {
|
|
||||||
id: u32,
|
|
||||||
timestamp: u64,
|
|
||||||
max_time: Milliseconds,
|
|
||||||
},
|
|
||||||
DmaAwait {
|
|
||||||
max_time: Milliseconds,
|
|
||||||
},
|
|
||||||
SubkernelRetrievingException {
|
|
||||||
destination: u8,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -60,9 +31,7 @@ pub enum Error {
|
||||||
NoMessage,
|
NoMessage,
|
||||||
AwaitingMessage,
|
AwaitingMessage,
|
||||||
SubkernelIoError,
|
SubkernelIoError,
|
||||||
DrtioError,
|
|
||||||
KernelException(Sliceable),
|
KernelException(Sliceable),
|
||||||
DmaError(DmaError),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<NoneError> for Error {
|
impl From<NoneError> for Error {
|
||||||
|
@ -77,38 +46,33 @@ impl From<IoError> for Error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<DmaError> for Error {
|
|
||||||
fn from(value: DmaError) -> Error {
|
|
||||||
Error::DmaError(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<()> for Error {
|
impl From<()> for Error {
|
||||||
fn from(_: ()) -> Error {
|
fn from(_: ()) -> Error {
|
||||||
Error::NoMessage
|
Error::NoMessage
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<drtioaux::Error> for Error {
|
|
||||||
fn from(_value: drtioaux::Error) -> Error {
|
|
||||||
Error::DrtioError
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! unexpected {
|
macro_rules! unexpected {
|
||||||
($($arg:tt)*) => (return Err(Error::Unexpected(format!($($arg)*))));
|
($($arg:tt)*) => (return Err(Error::Unexpected(format!($($arg)*))));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* represents data that has to be sent to Master */
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Sliceable {
|
||||||
|
it: usize,
|
||||||
|
data: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
/* represents interkernel messages */
|
/* represents interkernel messages */
|
||||||
struct Message {
|
struct Message {
|
||||||
count: u8,
|
count: u8,
|
||||||
id: u32,
|
|
||||||
data: Vec<u8>,
|
data: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq)]
|
#[derive(PartialEq)]
|
||||||
enum OutMessageState {
|
enum OutMessageState {
|
||||||
NoMessage,
|
NoMessage,
|
||||||
|
MessageReady,
|
||||||
MessageBeingSent,
|
MessageBeingSent,
|
||||||
MessageSent,
|
MessageSent,
|
||||||
MessageAcknowledged,
|
MessageAcknowledged,
|
||||||
|
@ -118,7 +82,7 @@ enum OutMessageState {
|
||||||
struct MessageManager {
|
struct MessageManager {
|
||||||
out_message: Option<Sliceable>,
|
out_message: Option<Sliceable>,
|
||||||
out_state: OutMessageState,
|
out_state: OutMessageState,
|
||||||
in_queue: Vec<Message>,
|
in_queue: VecDeque<Message>,
|
||||||
in_buffer: Option<Message>,
|
in_buffer: Option<Message>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,11 +90,8 @@ struct MessageManager {
|
||||||
struct Session {
|
struct Session {
|
||||||
id: u32,
|
id: u32,
|
||||||
kernel_state: KernelState,
|
kernel_state: KernelState,
|
||||||
last_exception: Option<Sliceable>, // exceptions raised locally
|
last_exception: Option<Sliceable>,
|
||||||
external_exception: Option<Vec<u8>>, // exceptions from sub-subkernels
|
|
||||||
messages: MessageManager,
|
messages: MessageManager,
|
||||||
source: u8, // which destination requested running the kernel
|
|
||||||
subkernels_finished: Vec<(u32, Option<u8>)>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Session {
|
impl Session {
|
||||||
|
@ -139,17 +100,14 @@ impl Session {
|
||||||
id: id,
|
id: id,
|
||||||
kernel_state: KernelState::Absent,
|
kernel_state: KernelState::Absent,
|
||||||
last_exception: None,
|
last_exception: None,
|
||||||
external_exception: None,
|
|
||||||
messages: MessageManager::new(),
|
messages: MessageManager::new(),
|
||||||
source: 0,
|
|
||||||
subkernels_finished: Vec::new(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn running(&self) -> bool {
|
fn running(&self) -> bool {
|
||||||
match self.kernel_state {
|
match self.kernel_state {
|
||||||
KernelState::Absent | KernelState::Loaded => false,
|
KernelState::Absent | KernelState::Loaded => false,
|
||||||
_ => true,
|
KernelState::Running | KernelState::MsgAwait { .. } | KernelState::MsgSending => true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -171,8 +129,40 @@ pub struct Manager<'a> {
|
||||||
pub struct SubkernelFinished {
|
pub struct SubkernelFinished {
|
||||||
pub id: u32,
|
pub id: u32,
|
||||||
pub with_exception: bool,
|
pub with_exception: bool,
|
||||||
pub exception_source: u8,
|
}
|
||||||
pub source: u8,
|
|
||||||
|
pub struct SliceMeta {
|
||||||
|
pub len: u16,
|
||||||
|
pub last: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! get_slice_fn {
|
||||||
|
($name:tt, $size:expr) => {
|
||||||
|
pub fn $name(&mut self, data_slice: &mut [u8; $size]) -> SliceMeta {
|
||||||
|
if self.data.len() == 0 {
|
||||||
|
return SliceMeta { len: 0, last: true };
|
||||||
|
}
|
||||||
|
let len = min($size, self.data.len() - self.it);
|
||||||
|
let last = self.it + len == self.data.len();
|
||||||
|
|
||||||
|
data_slice[..len].clone_from_slice(&self.data[self.it..self.it + len]);
|
||||||
|
self.it += len;
|
||||||
|
|
||||||
|
SliceMeta {
|
||||||
|
len: len as u16,
|
||||||
|
last: last,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sliceable {
|
||||||
|
pub fn new(data: Vec<u8>) -> Sliceable {
|
||||||
|
Sliceable { it: 0, data: data }
|
||||||
|
}
|
||||||
|
|
||||||
|
get_slice_fn!(get_slice_sat, SAT_PAYLOAD_MAX_SIZE);
|
||||||
|
get_slice_fn!(get_slice_master, MASTER_PAYLOAD_MAX_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MessageManager {
|
impl MessageManager {
|
||||||
|
@ -180,35 +170,36 @@ impl MessageManager {
|
||||||
MessageManager {
|
MessageManager {
|
||||||
out_message: None,
|
out_message: None,
|
||||||
out_state: OutMessageState::NoMessage,
|
out_state: OutMessageState::NoMessage,
|
||||||
in_queue: Vec::new(),
|
in_queue: VecDeque::new(),
|
||||||
in_buffer: None,
|
in_buffer: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_incoming(
|
pub fn handle_incoming(&mut self, last: bool, length: usize, data: &[u8; MASTER_PAYLOAD_MAX_SIZE]) {
|
||||||
&mut self,
|
|
||||||
status: PayloadStatus,
|
|
||||||
id: u32,
|
|
||||||
length: usize,
|
|
||||||
data: &[u8; MASTER_PAYLOAD_MAX_SIZE],
|
|
||||||
) {
|
|
||||||
// called when receiving a message from master
|
// called when receiving a message from master
|
||||||
if status.is_first() {
|
|
||||||
self.in_buffer = None;
|
|
||||||
}
|
|
||||||
match self.in_buffer.as_mut() {
|
match self.in_buffer.as_mut() {
|
||||||
Some(message) => message.data.extend(&data[..length]),
|
Some(message) => message.data.extend(&data[..length]),
|
||||||
None => {
|
None => {
|
||||||
self.in_buffer = Some(Message {
|
self.in_buffer = Some(Message {
|
||||||
count: data[0],
|
count: data[0],
|
||||||
id: id,
|
|
||||||
data: data[1..length].to_vec(),
|
data: data[1..length].to_vec(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if status.is_last() {
|
if last {
|
||||||
// when done, remove from working queue
|
// when done, remove from working queue
|
||||||
self.in_queue.push(self.in_buffer.take().unwrap());
|
self.in_queue.push_back(self.in_buffer.take().unwrap());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_outgoing_ready(&mut self) -> bool {
|
||||||
|
// called by main loop, to see if there's anything to send, will send it afterwards
|
||||||
|
match self.out_state {
|
||||||
|
OutMessageState::MessageReady => {
|
||||||
|
self.out_state = OutMessageState::MessageBeingSent;
|
||||||
|
true
|
||||||
|
}
|
||||||
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -227,7 +218,7 @@ impl MessageManager {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let meta = self.out_message.as_mut()?.get_slice_master(data_slice);
|
let meta = self.out_message.as_mut()?.get_slice_master(data_slice);
|
||||||
if meta.status.is_last() {
|
if meta.last {
|
||||||
// clear the message slot
|
// clear the message slot
|
||||||
self.out_message = None;
|
self.out_message = None;
|
||||||
// notify kernel with a flag that message is sent
|
// notify kernel with a flag that message is sent
|
||||||
|
@ -251,44 +242,15 @@ impl MessageManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn accept_outgoing(
|
pub fn accept_outgoing(&mut self, message: Vec<u8>) -> Result<(), Error> {
|
||||||
&mut self,
|
// service tag skipped in kernel
|
||||||
id: u32,
|
self.out_message = Some(Sliceable::new(message));
|
||||||
self_destination: u8,
|
self.out_state = OutMessageState::MessageReady;
|
||||||
destination: u8,
|
|
||||||
message: Vec<u8>,
|
|
||||||
routing_table: &RoutingTable,
|
|
||||||
rank: u8,
|
|
||||||
router: &mut Router,
|
|
||||||
) -> Result<(), Error> {
|
|
||||||
self.out_message = Some(Sliceable::new(destination, message));
|
|
||||||
|
|
||||||
let mut data_slice: [u8; MASTER_PAYLOAD_MAX_SIZE] = [0; MASTER_PAYLOAD_MAX_SIZE];
|
|
||||||
self.out_state = OutMessageState::MessageBeingSent;
|
|
||||||
let meta = self.get_outgoing_slice(&mut data_slice).unwrap();
|
|
||||||
router.route(
|
|
||||||
drtioaux::Packet::SubkernelMessage {
|
|
||||||
source: self_destination,
|
|
||||||
destination: destination,
|
|
||||||
id: id,
|
|
||||||
status: meta.status,
|
|
||||||
length: meta.len as u16,
|
|
||||||
data: data_slice,
|
|
||||||
},
|
|
||||||
routing_table,
|
|
||||||
rank,
|
|
||||||
self_destination,
|
|
||||||
);
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_incoming(&mut self, id: u32) -> Option<Message> {
|
pub fn get_incoming(&mut self) -> Option<Message> {
|
||||||
for i in 0..self.in_queue.len() {
|
self.in_queue.pop_front()
|
||||||
if self.in_queue[i].id == id {
|
|
||||||
return Some(self.in_queue.remove(i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -303,10 +265,10 @@ impl<'a> Manager<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add(&mut self, id: u32, status: PayloadStatus, data: &[u8], data_len: usize) -> Result<(), Error> {
|
pub fn add(&mut self, id: u32, last: bool, data: &[u8], data_len: usize) -> Result<(), Error> {
|
||||||
let kernel = match self.kernels.get_mut(&id) {
|
let kernel = match self.kernels.get_mut(&id) {
|
||||||
Some(kernel) => {
|
Some(kernel) => {
|
||||||
if kernel.complete || status.is_first() {
|
if kernel.complete {
|
||||||
// replace entry
|
// replace entry
|
||||||
self.kernels.remove(&id);
|
self.kernels.remove(&id);
|
||||||
self.kernels.insert(
|
self.kernels.insert(
|
||||||
|
@ -334,7 +296,7 @@ impl<'a> Manager<'_> {
|
||||||
};
|
};
|
||||||
kernel.library.extend(&data[0..data_len]);
|
kernel.library.extend(&data[0..data_len]);
|
||||||
|
|
||||||
kernel.complete = status.is_last();
|
kernel.complete = last;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -349,12 +311,12 @@ impl<'a> Manager<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run(&mut self, source: u8, id: u32) -> Result<(), Error> {
|
pub fn run(&mut self, id: u32) -> Result<(), Error> {
|
||||||
|
info!("starting subkernel #{}", id);
|
||||||
if self.session.kernel_state != KernelState::Loaded || self.session.id != id {
|
if self.session.kernel_state != KernelState::Loaded || self.session.id != id {
|
||||||
self.load(id)?;
|
self.load(id)?;
|
||||||
}
|
}
|
||||||
self.session.kernel_state = KernelState::Running;
|
self.session.kernel_state = KernelState::Running;
|
||||||
self.session.source = source;
|
|
||||||
unsafe {
|
unsafe {
|
||||||
csr::cri_con::selected_write(2);
|
csr::cri_con::selected_write(2);
|
||||||
}
|
}
|
||||||
|
@ -363,17 +325,11 @@ impl<'a> Manager<'_> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn message_handle_incoming(
|
pub fn message_handle_incoming(&mut self, last: bool, length: usize, slice: &[u8; MASTER_PAYLOAD_MAX_SIZE]) {
|
||||||
&mut self,
|
|
||||||
status: PayloadStatus,
|
|
||||||
id: u32,
|
|
||||||
length: usize,
|
|
||||||
slice: &[u8; MASTER_PAYLOAD_MAX_SIZE],
|
|
||||||
) {
|
|
||||||
if !self.running() {
|
if !self.running() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
self.session.messages.handle_incoming(status, id, length, slice);
|
self.session.messages.handle_incoming(last, length, slice);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn message_get_slice(&mut self, slice: &mut [u8; MASTER_PAYLOAD_MAX_SIZE]) -> Option<SliceMeta> {
|
pub fn message_get_slice(&mut self, slice: &mut [u8; MASTER_PAYLOAD_MAX_SIZE]) -> Option<SliceMeta> {
|
||||||
|
@ -391,6 +347,10 @@ impl<'a> Manager<'_> {
|
||||||
self.session.messages.ack_slice()
|
self.session.messages.ack_slice()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn message_is_ready(&mut self) -> bool {
|
||||||
|
self.session.messages.is_outgoing_ready()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn load(&mut self, id: u32) -> Result<(), Error> {
|
pub fn load(&mut self, id: u32) -> Result<(), Error> {
|
||||||
if self.session.id == id && self.session.kernel_state == KernelState::Loaded {
|
if self.session.id == id && self.session.kernel_state == KernelState::Loaded {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
@ -415,17 +375,17 @@ impl<'a> Manager<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn exception_get_slice(&mut self, data_slice: &mut [u8; MASTER_PAYLOAD_MAX_SIZE]) -> SliceMeta {
|
pub fn exception_get_slice(&mut self, data_slice: &mut [u8; SAT_PAYLOAD_MAX_SIZE]) -> SliceMeta {
|
||||||
match self.session.last_exception.as_mut() {
|
match self.session.last_exception.as_mut() {
|
||||||
Some(exception) => exception.get_slice_master(data_slice),
|
Some(exception) => exception.get_slice_sat(data_slice),
|
||||||
None => SliceMeta {
|
None => SliceMeta { len: 0, last: true },
|
||||||
destination: 0,
|
|
||||||
len: 0,
|
|
||||||
status: PayloadStatus::FirstAndLast,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_last_finished(&mut self) -> Option<SubkernelFinished> {
|
||||||
|
self.last_finished.take()
|
||||||
|
}
|
||||||
|
|
||||||
fn kernel_stop(&mut self) {
|
fn kernel_stop(&mut self) {
|
||||||
self.session.kernel_state = KernelState::Absent;
|
self.session.kernel_state = KernelState::Absent;
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -455,97 +415,18 @@ impl<'a> Manager<'_> {
|
||||||
&[],
|
&[],
|
||||||
0,
|
0,
|
||||||
) {
|
) {
|
||||||
Ok(_) => self.session.last_exception = Some(Sliceable::new(0, writer.into_inner())),
|
Ok(_) => self.session.last_exception = Some(Sliceable::new(writer.into_inner())),
|
||||||
Err(_) => error!("Error writing exception data"),
|
Err(_) => error!("Error writing exception data"),
|
||||||
}
|
}
|
||||||
self.kernel_stop();
|
self.kernel_stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ddma_finished(&mut self, error: u8, channel: u32, timestamp: u64) {
|
pub fn process_kern_requests(&mut self, rank: u8, timer: GlobalTimer) {
|
||||||
if let KernelState::DmaAwait { .. } = self.session.kernel_state {
|
|
||||||
self.control.tx.send(kernel::Message::DmaAwaitRemoteReply {
|
|
||||||
timeout: false,
|
|
||||||
error: error,
|
|
||||||
channel: channel,
|
|
||||||
timestamp: timestamp,
|
|
||||||
});
|
|
||||||
self.session.kernel_state = KernelState::Running;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn ddma_nack(&mut self) {
|
|
||||||
// for simplicity treat it as a timeout...
|
|
||||||
if let KernelState::DmaAwait { .. } = self.session.kernel_state {
|
|
||||||
self.control.tx.send(kernel::Message::DmaAwaitRemoteReply {
|
|
||||||
timeout: true,
|
|
||||||
error: 0,
|
|
||||||
channel: 0,
|
|
||||||
timestamp: 0,
|
|
||||||
});
|
|
||||||
self.session.kernel_state = KernelState::Running;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn ddma_remote_uploaded(&mut self, succeeded: bool) -> Option<(u32, u64)> {
|
|
||||||
// returns a tuple of id, timestamp in case a playback needs to be started immediately
|
|
||||||
if !succeeded {
|
|
||||||
self.kernel_stop();
|
|
||||||
self.runtime_exception(Error::DmaError(DmaError::UploadFail));
|
|
||||||
}
|
|
||||||
let res = match self.session.kernel_state {
|
|
||||||
KernelState::DmaPendingPlayback { id, timestamp } => {
|
|
||||||
self.session.kernel_state = KernelState::Running;
|
|
||||||
Some((id, timestamp))
|
|
||||||
}
|
|
||||||
KernelState::DmaPendingAwait {
|
|
||||||
id,
|
|
||||||
timestamp,
|
|
||||||
max_time,
|
|
||||||
} => {
|
|
||||||
self.session.kernel_state = KernelState::DmaAwait { max_time: max_time };
|
|
||||||
Some((id, timestamp))
|
|
||||||
}
|
|
||||||
KernelState::DmaUploading => {
|
|
||||||
self.session.kernel_state = KernelState::Running;
|
|
||||||
None
|
|
||||||
}
|
|
||||||
_ => None,
|
|
||||||
};
|
|
||||||
res
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn process_kern_requests(
|
|
||||||
&mut self,
|
|
||||||
router: &mut Router,
|
|
||||||
routing_table: &RoutingTable,
|
|
||||||
rank: u8,
|
|
||||||
destination: u8,
|
|
||||||
dma_manager: &mut DmaManager,
|
|
||||||
timer: &GlobalTimer,
|
|
||||||
) {
|
|
||||||
if let Some(subkernel_finished) = self.last_finished.take() {
|
|
||||||
info!(
|
|
||||||
"subkernel {} finished, with exception: {}",
|
|
||||||
subkernel_finished.id, subkernel_finished.with_exception
|
|
||||||
);
|
|
||||||
router.route(
|
|
||||||
drtioaux::Packet::SubkernelFinished {
|
|
||||||
destination: subkernel_finished.source,
|
|
||||||
id: subkernel_finished.id,
|
|
||||||
with_exception: subkernel_finished.with_exception,
|
|
||||||
exception_src: subkernel_finished.exception_source,
|
|
||||||
},
|
|
||||||
&routing_table,
|
|
||||||
rank,
|
|
||||||
destination,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if !self.running() {
|
if !self.running() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
match self.process_external_messages(router, routing_table, rank, destination, timer) {
|
match self.process_external_messages(timer) {
|
||||||
Ok(()) => (),
|
Ok(()) => (),
|
||||||
Err(Error::AwaitingMessage) => return, // kernel still waiting, do not process kernel messages
|
Err(Error::AwaitingMessage) => return, // kernel still waiting, do not process kernel messages
|
||||||
Err(Error::KernelException(exception)) => {
|
Err(Error::KernelException(exception)) => {
|
||||||
|
@ -553,8 +434,6 @@ impl<'a> Manager<'_> {
|
||||||
self.last_finished = Some(SubkernelFinished {
|
self.last_finished = Some(SubkernelFinished {
|
||||||
id: self.session.id,
|
id: self.session.id,
|
||||||
with_exception: true,
|
with_exception: true,
|
||||||
exception_source: destination,
|
|
||||||
source: self.session.source,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
@ -563,19 +442,15 @@ impl<'a> Manager<'_> {
|
||||||
self.last_finished = Some(SubkernelFinished {
|
self.last_finished = Some(SubkernelFinished {
|
||||||
id: self.session.id,
|
id: self.session.id,
|
||||||
with_exception: true,
|
with_exception: true,
|
||||||
exception_source: destination,
|
|
||||||
source: self.session.source,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
match self.process_kern_message(router, routing_table, rank, destination, dma_manager, timer) {
|
match self.process_kern_message(rank, timer) {
|
||||||
Ok(true) => {
|
Ok(true) => {
|
||||||
self.last_finished = Some(SubkernelFinished {
|
self.last_finished = Some(SubkernelFinished {
|
||||||
id: self.session.id,
|
id: self.session.id,
|
||||||
with_exception: false,
|
with_exception: false,
|
||||||
exception_source: 0,
|
|
||||||
source: self.session.source,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Ok(false) | Err(Error::NoMessage) => (),
|
Ok(false) | Err(Error::NoMessage) => (),
|
||||||
|
@ -584,8 +459,6 @@ impl<'a> Manager<'_> {
|
||||||
self.last_finished = Some(SubkernelFinished {
|
self.last_finished = Some(SubkernelFinished {
|
||||||
id: self.session.id,
|
id: self.session.id,
|
||||||
with_exception: true,
|
with_exception: true,
|
||||||
exception_source: destination,
|
|
||||||
source: self.session.source,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
@ -594,117 +467,16 @@ impl<'a> Manager<'_> {
|
||||||
self.last_finished = Some(SubkernelFinished {
|
self.last_finished = Some(SubkernelFinished {
|
||||||
id: self.session.id,
|
id: self.session.id,
|
||||||
with_exception: true,
|
with_exception: true,
|
||||||
exception_source: destination,
|
|
||||||
source: self.session.source,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_finished_kernels(
|
fn process_kern_message(&mut self, rank: u8, timer: GlobalTimer) -> Result<bool, Error> {
|
||||||
&mut self,
|
|
||||||
id: u32,
|
|
||||||
router: &mut Router,
|
|
||||||
routing_table: &RoutingTable,
|
|
||||||
rank: u8,
|
|
||||||
self_destination: u8,
|
|
||||||
) {
|
|
||||||
for (i, (status, exception_source)) in self.session.subkernels_finished.iter().enumerate() {
|
|
||||||
if *status == id {
|
|
||||||
if exception_source.is_none() {
|
|
||||||
self.control.tx.send(kernel::Message::SubkernelAwaitFinishReply);
|
|
||||||
self.session.kernel_state = KernelState::Running;
|
|
||||||
self.session.subkernels_finished.swap_remove(i);
|
|
||||||
} else {
|
|
||||||
let destination = exception_source.unwrap();
|
|
||||||
self.session.external_exception = Some(Vec::new());
|
|
||||||
self.session.kernel_state = KernelState::SubkernelRetrievingException {
|
|
||||||
destination: destination,
|
|
||||||
};
|
|
||||||
router.route(
|
|
||||||
drtioaux::Packet::SubkernelExceptionRequest {
|
|
||||||
source: self_destination,
|
|
||||||
destination: destination,
|
|
||||||
},
|
|
||||||
&routing_table,
|
|
||||||
rank,
|
|
||||||
self_destination,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn subkernel_load_run_reply(&mut self, succeeded: bool) {
|
|
||||||
if self.session.kernel_state == KernelState::SubkernelAwaitLoad {
|
|
||||||
self.control
|
|
||||||
.tx
|
|
||||||
.send(kernel::Message::SubkernelLoadRunReply { succeeded: succeeded });
|
|
||||||
self.session.kernel_state = KernelState::Running;
|
|
||||||
} else {
|
|
||||||
warn!("received unsolicited SubkernelLoadRunReply");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn remote_subkernel_finished(&mut self, id: u32, with_exception: bool, exception_source: u8) {
|
|
||||||
let exception_src = if with_exception { Some(exception_source) } else { None };
|
|
||||||
self.session.subkernels_finished.push((id, exception_src));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn received_exception(
|
|
||||||
&mut self,
|
|
||||||
exception_data: &[u8],
|
|
||||||
last: bool,
|
|
||||||
router: &mut Router,
|
|
||||||
routing_table: &RoutingTable,
|
|
||||||
rank: u8,
|
|
||||||
self_destination: u8,
|
|
||||||
) {
|
|
||||||
if let KernelState::SubkernelRetrievingException { destination } = self.session.kernel_state {
|
|
||||||
self.session
|
|
||||||
.external_exception
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.extend_from_slice(exception_data);
|
|
||||||
if last {
|
|
||||||
self.control
|
|
||||||
.tx
|
|
||||||
.send(kernel::Message::SubkernelError(kernel::SubkernelStatus::Exception(
|
|
||||||
self.session.external_exception.take().unwrap(),
|
|
||||||
)));
|
|
||||||
self.session.kernel_state = KernelState::Running;
|
|
||||||
} else {
|
|
||||||
/* fetch another slice */
|
|
||||||
router.route(
|
|
||||||
drtioaux::Packet::SubkernelExceptionRequest {
|
|
||||||
source: self_destination,
|
|
||||||
destination: destination,
|
|
||||||
},
|
|
||||||
routing_table,
|
|
||||||
rank,
|
|
||||||
self_destination,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
warn!("Received unsolicited exception data");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn process_kern_message(
|
|
||||||
&mut self,
|
|
||||||
router: &mut Router,
|
|
||||||
routing_table: &RoutingTable,
|
|
||||||
rank: u8,
|
|
||||||
self_destination: u8,
|
|
||||||
dma_manager: &mut DmaManager,
|
|
||||||
timer: &GlobalTimer,
|
|
||||||
) -> Result<bool, Error> {
|
|
||||||
let reply = self.control.rx.try_recv()?;
|
let reply = self.control.rx.try_recv()?;
|
||||||
match reply {
|
match reply {
|
||||||
kernel::Message::KernelFinished(_async_errors) => {
|
kernel::Message::KernelFinished(_async_errors) => {
|
||||||
self.kernel_stop();
|
self.kernel_stop();
|
||||||
dma_manager.cleanup(router, rank, self_destination, routing_table);
|
|
||||||
return Ok(true);
|
return Ok(true);
|
||||||
}
|
}
|
||||||
kernel::Message::KernelException(exceptions, stack_pointers, backtrace, async_errors) => {
|
kernel::Message::KernelException(exceptions, stack_pointers, backtrace, async_errors) => {
|
||||||
|
@ -721,7 +493,7 @@ impl<'a> Manager<'_> {
|
||||||
Err(_) => error!("Error writing exception data"),
|
Err(_) => error!("Error writing exception data"),
|
||||||
}
|
}
|
||||||
self.kernel_stop();
|
self.kernel_stop();
|
||||||
return Err(Error::KernelException(Sliceable::new(0, writer.into_inner())));
|
return Err(Error::KernelException(Sliceable::new(writer.into_inner())));
|
||||||
}
|
}
|
||||||
kernel::Message::CachePutRequest(key, value) => {
|
kernel::Message::CachePutRequest(key, value) => {
|
||||||
self.cache.insert(key, value);
|
self.cache.insert(key, value);
|
||||||
|
@ -731,117 +503,18 @@ impl<'a> Manager<'_> {
|
||||||
let value = self.cache.get(&key).unwrap_or(&DEFAULT).clone();
|
let value = self.cache.get(&key).unwrap_or(&DEFAULT).clone();
|
||||||
self.control.tx.send(kernel::Message::CacheGetReply(value));
|
self.control.tx.send(kernel::Message::CacheGetReply(value));
|
||||||
}
|
}
|
||||||
|
kernel::Message::SubkernelMsgSend { id: _, data } => {
|
||||||
kernel::Message::DmaPutRequest(recorder) => {
|
self.session.messages.accept_outgoing(data)?;
|
||||||
// ddma is always used on satellites
|
|
||||||
if let Ok(id) = dma_manager.put_record(recorder, self_destination) {
|
|
||||||
dma_manager.upload_traces(id, router, rank, self_destination, routing_table)?;
|
|
||||||
self.session.kernel_state = KernelState::DmaUploading;
|
|
||||||
} else {
|
|
||||||
unexpected!("DMAError: found an unsupported call to RTIO devices on master")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
kernel::Message::DmaEraseRequest(name) => {
|
|
||||||
dma_manager.erase_name(&name, router, rank, self_destination, routing_table);
|
|
||||||
}
|
|
||||||
kernel::Message::DmaGetRequest(name) => {
|
|
||||||
let dma_meta = dma_manager.retrieve(self_destination, &name);
|
|
||||||
self.control.tx.send(kernel::Message::DmaGetReply(dma_meta));
|
|
||||||
}
|
|
||||||
kernel::Message::DmaStartRemoteRequest { id, timestamp } => {
|
|
||||||
if self.session.kernel_state != KernelState::DmaUploading {
|
|
||||||
dma_manager.playback_remote(
|
|
||||||
id as u32,
|
|
||||||
timestamp as u64,
|
|
||||||
router,
|
|
||||||
rank,
|
|
||||||
self_destination,
|
|
||||||
routing_table,
|
|
||||||
)?;
|
|
||||||
} else {
|
|
||||||
self.session.kernel_state = KernelState::DmaPendingPlayback {
|
|
||||||
id: id as u32,
|
|
||||||
timestamp: timestamp as u64,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
kernel::Message::DmaAwaitRemoteRequest(_id) => {
|
|
||||||
let max_time = timer.get_time() + Milliseconds(10000);
|
|
||||||
self.session.kernel_state = match self.session.kernel_state {
|
|
||||||
// if we are still waiting for the traces to be uploaded, extend the state by timeout
|
|
||||||
KernelState::DmaPendingPlayback { id, timestamp } => KernelState::DmaPendingAwait {
|
|
||||||
id: id,
|
|
||||||
timestamp: timestamp,
|
|
||||||
max_time: max_time,
|
|
||||||
},
|
|
||||||
_ => KernelState::DmaAwait { max_time: max_time },
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
kernel::Message::SubkernelMsgSend {
|
|
||||||
id: _id,
|
|
||||||
destination: msg_dest,
|
|
||||||
data,
|
|
||||||
} => {
|
|
||||||
let msg_dest = msg_dest.or(Some(self.session.source)).unwrap();
|
|
||||||
self.session.messages.accept_outgoing(
|
|
||||||
self.session.id,
|
|
||||||
self_destination,
|
|
||||||
msg_dest,
|
|
||||||
data,
|
|
||||||
routing_table,
|
|
||||||
rank,
|
|
||||||
router,
|
|
||||||
)?;
|
|
||||||
self.session.kernel_state = KernelState::MsgSending;
|
self.session.kernel_state = KernelState::MsgSending;
|
||||||
}
|
}
|
||||||
kernel::Message::SubkernelMsgRecvRequest { id, timeout, tags } => {
|
kernel::Message::SubkernelMsgRecvRequest { id: _, timeout, tags } => {
|
||||||
let id = if id == -1 { self.session.id } else { id as u32 };
|
let max_time = timer.get_time() + Milliseconds(timeout);
|
||||||
let max_time = if timeout > 0 {
|
self.session.kernel_state = KernelState::MsgAwait(max_time, tags);
|
||||||
Some(timer.get_time() + Milliseconds(timeout as u64))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
self.session.kernel_state = KernelState::MsgAwait {
|
|
||||||
max_time: max_time,
|
|
||||||
id: id,
|
|
||||||
tags: tags,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
kernel::Message::SubkernelLoadRunRequest {
|
|
||||||
id,
|
|
||||||
destination: sk_destination,
|
|
||||||
run,
|
|
||||||
} => {
|
|
||||||
self.session.kernel_state = KernelState::SubkernelAwaitLoad;
|
|
||||||
router.route(
|
|
||||||
drtioaux::Packet::SubkernelLoadRunRequest {
|
|
||||||
source: self_destination,
|
|
||||||
destination: sk_destination,
|
|
||||||
id: id,
|
|
||||||
run: run,
|
|
||||||
},
|
|
||||||
routing_table,
|
|
||||||
rank,
|
|
||||||
self_destination,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
kernel::Message::SubkernelAwaitFinishRequest { id, timeout } => {
|
|
||||||
let max_time = if timeout > 0 {
|
|
||||||
Some(timer.get_time() + Milliseconds(timeout as u64))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
self.session.kernel_state = KernelState::SubkernelAwaitFinish {
|
|
||||||
max_time: max_time,
|
|
||||||
id: id,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
kernel::Message::UpDestinationsRequest(destination) => {
|
kernel::Message::UpDestinationsRequest(destination) => {
|
||||||
self.control.tx.send(kernel::Message::UpDestinationsReply(
|
self.control
|
||||||
destination == (self_destination as i32),
|
.tx
|
||||||
));
|
.send(kernel::Message::UpDestinationsReply(destination == (rank as i32)));
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
unexpected!("unexpected message from core1 while kernel was running: {:?}", reply);
|
unexpected!("unexpected message from core1 while kernel was running: {:?}", reply);
|
||||||
|
@ -850,35 +523,26 @@ impl<'a> Manager<'_> {
|
||||||
Ok(false)
|
Ok(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_external_messages(
|
fn process_external_messages(&mut self, timer: GlobalTimer) -> Result<(), Error> {
|
||||||
&mut self,
|
|
||||||
router: &mut Router,
|
|
||||||
routing_table: &RoutingTable,
|
|
||||||
rank: u8,
|
|
||||||
self_destination: u8,
|
|
||||||
timer: &GlobalTimer,
|
|
||||||
) -> Result<(), Error> {
|
|
||||||
match &self.session.kernel_state {
|
match &self.session.kernel_state {
|
||||||
KernelState::MsgAwait { max_time, id, tags } => {
|
KernelState::MsgAwait(timeout, tags) => {
|
||||||
if let Some(max_time) = *max_time {
|
if timer.get_time() > *timeout {
|
||||||
if timer.get_time() > max_time {
|
self.control.tx.send(kernel::Message::SubkernelMsgRecvReply {
|
||||||
self.control
|
status: kernel::SubkernelStatus::Timeout,
|
||||||
.tx
|
count: 0,
|
||||||
.send(kernel::Message::SubkernelError(kernel::SubkernelStatus::Timeout));
|
});
|
||||||
self.session.kernel_state = KernelState::Running;
|
self.session.kernel_state = KernelState::Running;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if let Some(message) = self.session.messages.get_incoming(*id) {
|
if let Some(message) = self.session.messages.get_incoming() {
|
||||||
self.control
|
self.control.tx.send(kernel::Message::SubkernelMsgRecvReply {
|
||||||
.tx
|
status: kernel::SubkernelStatus::NoError,
|
||||||
.send(kernel::Message::SubkernelMsgRecvReply { count: message.count });
|
count: message.count,
|
||||||
|
});
|
||||||
let tags = tags.clone();
|
let tags = tags.clone();
|
||||||
self.session.kernel_state = KernelState::Running;
|
self.session.kernel_state = KernelState::Running;
|
||||||
self.pass_message_to_kernel(&message, tags, timer)
|
self.pass_message_to_kernel(&message, tags, timer)
|
||||||
} else {
|
} else {
|
||||||
let id = *id;
|
|
||||||
self.check_finished_kernels(id, router, routing_table, rank, self_destination);
|
|
||||||
Err(Error::AwaitingMessage)
|
Err(Error::AwaitingMessage)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -891,38 +555,11 @@ impl<'a> Manager<'_> {
|
||||||
Err(Error::AwaitingMessage)
|
Err(Error::AwaitingMessage)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
KernelState::SubkernelAwaitFinish { max_time, id } => {
|
|
||||||
if let Some(max_time) = *max_time {
|
|
||||||
if timer.get_time() > max_time {
|
|
||||||
self.control
|
|
||||||
.tx
|
|
||||||
.send(kernel::Message::SubkernelError(kernel::SubkernelStatus::Timeout));
|
|
||||||
self.session.kernel_state = KernelState::Running;
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let id = *id;
|
|
||||||
self.check_finished_kernels(id, router, routing_table, rank, self_destination);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
KernelState::SubkernelRetrievingException { .. } => Err(Error::AwaitingMessage),
|
|
||||||
KernelState::DmaAwait { max_time } | KernelState::DmaPendingAwait { max_time, .. } => {
|
|
||||||
if timer.get_time() > *max_time {
|
|
||||||
self.control.tx.send(kernel::Message::DmaAwaitRemoteReply {
|
|
||||||
timeout: true,
|
|
||||||
error: 0,
|
|
||||||
channel: 0,
|
|
||||||
timestamp: 0,
|
|
||||||
});
|
|
||||||
self.session.kernel_state = KernelState::Running;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
_ => Ok(()),
|
_ => Ok(()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pass_message_to_kernel(&mut self, message: &Message, tags: Vec<u8>, timer: &GlobalTimer) -> Result<(), Error> {
|
fn pass_message_to_kernel(&mut self, message: &Message, tags: Vec<u8>, timer: GlobalTimer) -> Result<(), Error> {
|
||||||
let mut reader = Cursor::new(&message.data);
|
let mut reader = Cursor::new(&message.data);
|
||||||
let mut current_tags: &[u8] = &tags;
|
let mut current_tags: &[u8] = &tags;
|
||||||
let mut i = message.count;
|
let mut i = message.count;
|
||||||
|
@ -945,7 +582,7 @@ impl<'a> Manager<'_> {
|
||||||
let mut writer = Cursor::new(buf);
|
let mut writer = Cursor::new(buf);
|
||||||
match write_exception(&mut writer, exceptions, stack_pointers, backtrace, async_errors) {
|
match write_exception(&mut writer, exceptions, stack_pointers, backtrace, async_errors) {
|
||||||
Ok(()) => {
|
Ok(()) => {
|
||||||
exception = Some(Sliceable::new(0, writer.into_inner()));
|
exception = Some(Sliceable::new(writer.into_inner()));
|
||||||
}
|
}
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
unexpected = Some("Error writing exception data".to_string());
|
unexpected = Some("Error writing exception data".to_string());
|
||||||
|
@ -1039,7 +676,7 @@ where
|
||||||
|
|
||||||
fn recv_w_timeout(
|
fn recv_w_timeout(
|
||||||
rx: &mut Receiver<'_, kernel::Message>,
|
rx: &mut Receiver<'_, kernel::Message>,
|
||||||
timer: &GlobalTimer,
|
timer: GlobalTimer,
|
||||||
timeout: u64,
|
timeout: u64,
|
||||||
) -> Result<kernel::Message, Error> {
|
) -> Result<kernel::Message, Error> {
|
||||||
let max_time = timer.get_time() + Milliseconds(timeout);
|
let max_time = timer.get_time() + Milliseconds(timeout);
|
||||||
|
|
Loading…
Reference in New Issue