forked from M-Labs/artiq-zynq
Compare commits
44 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c65b130275 | |||
| efd45316e7 | |||
| 1f8c9c3ee3 | |||
| 4a1dc628d9 | |||
| 72407a19a3 | |||
| d9871ed0a7 | |||
| 90db06a9e1 | |||
| 446384d787 | |||
|
|
f3d4793fcb | ||
|
|
00c4d48211 | ||
| fd1b2453d7 | |||
| 6ff895c0bf | |||
|
|
b55f629486 | ||
| 61dbb6a0f1 | |||
| 159987a64b | |||
| 3be9250978 | |||
| b88bb90139 | |||
| 3b0b52ef2c | |||
| 982828bde1 | |||
| db0231956e | |||
| d9bf878d03 | |||
| beb98b52fd | |||
| d57f308765 | |||
| d9f2f84480 | |||
| c317b3a0ac | |||
| 54ce700fde | |||
| 7f28167279 | |||
| 307ced4585 | |||
| 3f497e08a4 | |||
|
|
9a816e1d5b | ||
| 7cceda9353 | |||
| a325d5ce78 | |||
| 40f1c94ecf | |||
| 92c586d266 | |||
| 96928b7d0d | |||
| 59266fd141 | |||
| 78080eae2b | |||
| f1e79310ec | |||
| 3a65d6c2a5 | |||
| 734fd11ad6 | |||
| 5843138a8e | |||
| 1ab755838a | |||
| e21873d227 | |||
| 767b725db7 |
@ -2,7 +2,7 @@
|
||||
"target": "kasli_soc",
|
||||
"variant": "demo",
|
||||
"hw_rev": "v1.0",
|
||||
"base": "standalone",
|
||||
"drtio_role": "standalone",
|
||||
"peripherals": [
|
||||
{
|
||||
"type": "coaxpress_sfp"
|
||||
|
||||
148
flake.lock
generated
148
flake.lock
generated
@ -12,11 +12,11 @@
|
||||
"src-pythonparser": "src-pythonparser"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1752484307,
|
||||
"narHash": "sha256-KJ56ujYOMpOl487npaFSeu1e7gpsS+2V3ZpdQLZ1OOE=",
|
||||
"lastModified": 1763779050,
|
||||
"narHash": "sha256-GOCiPuuPTR7KR0CT9H8zboUqk7J8Xdu9ud6djW7xNBQ=",
|
||||
"ref": "refs/heads/master",
|
||||
"rev": "cb5727c1ee1c6f4a81f25ee62557c3957b1a622b",
|
||||
"revCount": 9290,
|
||||
"rev": "9aa0c7ec5b80e1bd6bf726c38c3dc5cc69b8cd49",
|
||||
"revCount": 9556,
|
||||
"type": "git",
|
||||
"url": "https://github.com/m-labs/artiq.git"
|
||||
},
|
||||
@ -38,11 +38,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1748847424,
|
||||
"narHash": "sha256-BXpxu3fowHV0u6DVTYn6efQ8X3PV6qC4TgiuCsSy3/0=",
|
||||
"lastModified": 1756451104,
|
||||
"narHash": "sha256-Tm0q98QcQnYxQoQVLVY5wKQv3ZHs0dUMPAEc4/RO7+M=",
|
||||
"owner": "m-labs",
|
||||
"repo": "artiq-comtools",
|
||||
"rev": "5552bf9b5e6e150dafbaf5cd20bd68c82949ac9a",
|
||||
"rev": "f837afcdab5af70c2ca7554538f812890717cc59",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@ -51,6 +51,52 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"fenix": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"artiq",
|
||||
"naersk",
|
||||
"nixpkgs"
|
||||
],
|
||||
"rust-analyzer-src": "rust-analyzer-src"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1752475459,
|
||||
"narHash": "sha256-z6QEu4ZFuHiqdOPbYss4/Q8B0BFhacR8ts6jO/F/aOU=",
|
||||
"owner": "nix-community",
|
||||
"repo": "fenix",
|
||||
"rev": "bf0d6f70f4c9a9cf8845f992105652173f4b617f",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"repo": "fenix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"fenix_2": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"zynq-rs",
|
||||
"naersk",
|
||||
"nixpkgs"
|
||||
],
|
||||
"rust-analyzer-src": "rust-analyzer-src_2"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1752475459,
|
||||
"narHash": "sha256-z6QEu4ZFuHiqdOPbYss4/Q8B0BFhacR8ts6jO/F/aOU=",
|
||||
"owner": "nix-community",
|
||||
"repo": "fenix",
|
||||
"rev": "bf0d6f70f4c9a9cf8845f992105652173f4b617f",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"repo": "fenix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils": {
|
||||
"inputs": {
|
||||
"systems": "systems"
|
||||
@ -71,17 +117,18 @@
|
||||
},
|
||||
"naersk": {
|
||||
"inputs": {
|
||||
"fenix": "fenix",
|
||||
"nixpkgs": [
|
||||
"artiq",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1745925850,
|
||||
"narHash": "sha256-cyAAMal0aPrlb1NgzMxZqeN1mAJ2pJseDhm2m6Um8T0=",
|
||||
"lastModified": 1763384566,
|
||||
"narHash": "sha256-r+wgI+WvNaSdxQmqaM58lVNvJYJ16zoq+tKN20cLst4=",
|
||||
"owner": "nix-community",
|
||||
"repo": "naersk",
|
||||
"rev": "38bc60bbc157ae266d4a0c96671c6c742ee17a5f",
|
||||
"rev": "d4155d6ebb70fbe2314959842f744aa7cabbbf6a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@ -92,17 +139,18 @@
|
||||
},
|
||||
"naersk_2": {
|
||||
"inputs": {
|
||||
"fenix": "fenix_2",
|
||||
"nixpkgs": [
|
||||
"zynq-rs",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1745925850,
|
||||
"narHash": "sha256-cyAAMal0aPrlb1NgzMxZqeN1mAJ2pJseDhm2m6Um8T0=",
|
||||
"lastModified": 1763384566,
|
||||
"narHash": "sha256-r+wgI+WvNaSdxQmqaM58lVNvJYJ16zoq+tKN20cLst4=",
|
||||
"owner": "nix-community",
|
||||
"repo": "naersk",
|
||||
"rev": "38bc60bbc157ae266d4a0c96671c6c742ee17a5f",
|
||||
"rev": "d4155d6ebb70fbe2314959842f744aa7cabbbf6a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@ -113,11 +161,11 @@
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1750741721,
|
||||
"narHash": "sha256-Z0djmTa1YmnGMfE9jEe05oO4zggjDmxOGKwt844bUhE=",
|
||||
"lastModified": 1763421233,
|
||||
"narHash": "sha256-Stk9ZYRkGrnnpyJ4eqt9eQtdFWRRIvMxpNRf4sIegnw=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "4b1164c3215f018c4442463a27689d973cffd750",
|
||||
"rev": "89c2b2330e733d6cdb5eae7b899326930c2c0648",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@ -133,6 +181,40 @@
|
||||
"zynq-rs": "zynq-rs"
|
||||
}
|
||||
},
|
||||
"rust-analyzer-src": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1752428706,
|
||||
"narHash": "sha256-EJcdxw3aXfP8Ex1Nm3s0awyH9egQvB2Gu+QEnJn2Sfg=",
|
||||
"owner": "rust-lang",
|
||||
"repo": "rust-analyzer",
|
||||
"rev": "591e3b7624be97e4443ea7b5542c191311aa141d",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "rust-lang",
|
||||
"ref": "nightly",
|
||||
"repo": "rust-analyzer",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"rust-analyzer-src_2": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1752428706,
|
||||
"narHash": "sha256-EJcdxw3aXfP8Ex1Nm3s0awyH9egQvB2Gu+QEnJn2Sfg=",
|
||||
"owner": "rust-lang",
|
||||
"repo": "rust-analyzer",
|
||||
"rev": "591e3b7624be97e4443ea7b5542c191311aa141d",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "rust-lang",
|
||||
"ref": "nightly",
|
||||
"repo": "rust-analyzer",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"rust-overlay": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
@ -163,11 +245,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1750041667,
|
||||
"narHash": "sha256-/8F9L6T9w/Fx1D6L+BtWIXg5m9F6jwOFg6uhZpKnM/0=",
|
||||
"lastModified": 1763433504,
|
||||
"narHash": "sha256-cVid5UNpk88sPYHkLAA5aZEHOFQXSB/2L1vl18Aq7IM=",
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"rev": "d72bd8c9fda03c9834ea89d7a5a21c7880b79277",
|
||||
"rev": "42ce16c6d8318a654d53f047c9400b7d902d6e61",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@ -184,11 +266,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1752168638,
|
||||
"narHash": "sha256-wH+RiSaALa9Y4DVW2kDOTXUAjCmREIjq3oN9GuA6L70=",
|
||||
"lastModified": 1763777988,
|
||||
"narHash": "sha256-8illczV5ipynJytjQZ+6aLWhWLbvRDJrcqnbYSJvmRQ=",
|
||||
"owner": "m-labs",
|
||||
"repo": "sipyco",
|
||||
"rev": "01f2e37ea13cb7f297321104319428b1ddf546fc",
|
||||
"rev": "1f1722fb309bad00f384907769fb4f54db850222",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@ -200,11 +282,11 @@
|
||||
"src-migen": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1749544952,
|
||||
"narHash": "sha256-NshlPiORBHWljSUP5bB7YBxe7k8dW0t8UXOsIq2EK8I=",
|
||||
"lastModified": 1759465137,
|
||||
"narHash": "sha256-gRAvl5cUvrjq4t7htXsDBt4F8MEbHXFZoS0jbhrEs1I=",
|
||||
"owner": "m-labs",
|
||||
"repo": "migen",
|
||||
"rev": "6e3a9e150fb006dabc4b55043d3af18dbfecd7e8",
|
||||
"rev": "147f003fb7076ac4c7cf76a9a5ce152dc10e0ca6",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@ -216,11 +298,11 @@
|
||||
"src-misoc": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1747128843,
|
||||
"narHash": "sha256-TCFPoaQFaFCg3my3wyl3Gkz4ZnyzWa/ZXbcZG/OEsCU=",
|
||||
"lastModified": 1761903947,
|
||||
"narHash": "sha256-cI5alXIU1bEpvZ2NTSbfYevz/UngtPLMU9f2XeYYTq4=",
|
||||
"ref": "refs/heads/master",
|
||||
"rev": "9e07cf5f3b7d4949d3b775d4d946ca22900ab528",
|
||||
"revCount": 2498,
|
||||
"rev": "89051eeb63b7bee98432594f933de230eecf929d",
|
||||
"revCount": 2507,
|
||||
"submodules": true,
|
||||
"type": "git",
|
||||
"url": "https://github.com/m-labs/misoc.git"
|
||||
@ -272,11 +354,11 @@
|
||||
"rust-overlay": "rust-overlay_2"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1752558724,
|
||||
"narHash": "sha256-bOrhgijeSPQoUDs6jy/lw40pJK9dv/jjcVeIQPyobdk=",
|
||||
"lastModified": 1763461295,
|
||||
"narHash": "sha256-LDLrz81hlcSjQUS5mSwoMV4ZEol5wOtJ0xhsjAGJQEc=",
|
||||
"ref": "refs/heads/master",
|
||||
"rev": "e3f2c44dd9f9eaa522ca06a493064fccb1a7a6f3",
|
||||
"revCount": 722,
|
||||
"rev": "20975fc812d6b4e28b9fe6011344373054581c94",
|
||||
"revCount": 734,
|
||||
"type": "git",
|
||||
"url": "https://git.m-labs.hk/m-labs/zynq-rs"
|
||||
},
|
||||
|
||||
353
flake.nix
353
flake.nix
@ -5,9 +5,15 @@
|
||||
inputs.zynq-rs.url = git+https://git.m-labs.hk/m-labs/zynq-rs;
|
||||
inputs.zynq-rs.inputs.nixpkgs.follows = "artiq/nixpkgs";
|
||||
|
||||
outputs = { self, zynq-rs, artiq }:
|
||||
let
|
||||
pkgs = import artiq.inputs.nixpkgs { system = "x86_64-linux"; overlays = [ (import zynq-rs.inputs.rust-overlay) ]; };
|
||||
outputs = {
|
||||
self,
|
||||
zynq-rs,
|
||||
artiq,
|
||||
}: let
|
||||
pkgs = import artiq.inputs.nixpkgs {
|
||||
system = "x86_64-linux";
|
||||
overlays = [(import zynq-rs.inputs.rust-overlay)];
|
||||
};
|
||||
zynqpkgs = zynq-rs.packages.x86_64-linux;
|
||||
artiqpkgs = artiq.packages.x86_64-linux;
|
||||
zynqRev = self.sourceInfo.rev or "unknown";
|
||||
@ -23,6 +29,8 @@
|
||||
inherit pname version;
|
||||
sha256 = "sha256-4JLTP4uVwxcaL7NOV57+DFSwKQ3X+W/6onYkN2AdkKc=";
|
||||
};
|
||||
pyproject = true;
|
||||
build-system = [pkgs.python3Packages.setuptools];
|
||||
};
|
||||
|
||||
artiq-netboot = pkgs.python3Packages.buildPythonPackage rec {
|
||||
@ -34,6 +42,8 @@
|
||||
rev = "04f69eb07df73abe4b89fde2c24084f7664f2104";
|
||||
sha256 = "0ql4fr8m8gpb2yql8aqsdqsssxb8zqd6l65kl1f6s9845zy7shs9";
|
||||
};
|
||||
pyproject = true;
|
||||
build-system = [pkgs.python3Packages.setuptools];
|
||||
};
|
||||
|
||||
ramda = pkgs.python3Packages.buildPythonPackage {
|
||||
@ -46,11 +56,13 @@
|
||||
rev = "d315a9717ebd639366bf3fe26bad9e3d08ec3c49";
|
||||
sha256 = "sha256-bmSt/IHDnULsZjsC6edELnNH7LoJSVF4L4XhwBAXRkY=";
|
||||
};
|
||||
pyproject = true;
|
||||
build-system = [pkgs.python3Packages.setuptools];
|
||||
|
||||
nativeBuildInputs = with pkgs.python3Packages; [ pbr ];
|
||||
propagatedBuildInputs = with pkgs.python3Packages; [ fastnumbers ];
|
||||
nativeBuildInputs = with pkgs.python3Packages; [pbr];
|
||||
propagatedBuildInputs = with pkgs.python3Packages; [fastnumbers];
|
||||
|
||||
checkInputs = with pkgs.python3Packages; [ pytest ];
|
||||
checkInputs = with pkgs.python3Packages; [pytest];
|
||||
checkPhase = "pytest";
|
||||
doCheck = false;
|
||||
|
||||
@ -69,12 +81,12 @@
|
||||
rev = "98649a92ed7d4e43f75231e6ef9753e1212fab41";
|
||||
sha256 = "sha256-0kEHK+l6gZW750tq89fHRxIh3Gnj5EP2GZX/neWaWzU=";
|
||||
};
|
||||
pyproject = true;
|
||||
build-system = [pkgs.python3Packages.setuptools];
|
||||
|
||||
format = "pyproject";
|
||||
propagatedBuildInputs = with pkgs.python3Packages; [setuptools click numpy toolz jinja2 ramda artiqpkgs.migen artiqpkgs.misoc];
|
||||
|
||||
propagatedBuildInputs = with pkgs.python3Packages; [ setuptools click numpy toolz jinja2 ramda artiqpkgs.migen artiqpkgs.misoc ];
|
||||
|
||||
checkInputs = with pkgs.python3Packages; [ pytestCheckHook pytest-timeout ];
|
||||
checkInputs = with pkgs.python3Packages; [pytestCheckHook pytest-timeout];
|
||||
|
||||
# migen/misoc version checks are broken with pyproject for some reason
|
||||
postPatch = ''
|
||||
@ -87,22 +99,29 @@
|
||||
substituteInPlace setup.cfg --replace '--flake8' ""
|
||||
'';
|
||||
};
|
||||
binutils = { platform, target, zlib }: pkgs.stdenv.mkDerivation rec {
|
||||
basename = "binutils";
|
||||
version = "2.30";
|
||||
name = "${basename}-${platform}-${version}";
|
||||
src = pkgs.fetchurl {
|
||||
url = "https://ftp.gnu.org/gnu/binutils/binutils-${version}.tar.bz2";
|
||||
sha256 = "028cklfqaab24glva1ks2aqa1zxa6w6xmc8q34zs1sb7h22dxspg";
|
||||
binutils = {
|
||||
platform,
|
||||
target,
|
||||
zlib,
|
||||
}:
|
||||
pkgs.stdenv.mkDerivation rec {
|
||||
basename = "binutils";
|
||||
version = "2.30";
|
||||
name = "${basename}-${platform}-${version}";
|
||||
src = pkgs.fetchurl {
|
||||
url = "https://ftp.gnu.org/gnu/binutils/binutils-${version}.tar.bz2";
|
||||
sha256 = "028cklfqaab24glva1ks2aqa1zxa6w6xmc8q34zs1sb7h22dxspg";
|
||||
};
|
||||
configureFlags = ["--enable-shared" "--enable-deterministic-archives" "--target=${target}"];
|
||||
outputs = ["out" "info" "man"];
|
||||
depsBuildBuild = [pkgs.buildPackages.stdenv.cc];
|
||||
buildInputs = [zlib];
|
||||
enableParallelBuilding = true;
|
||||
};
|
||||
configureFlags =
|
||||
[ "--enable-shared" "--enable-deterministic-archives" "--target=${target}"];
|
||||
outputs = [ "out" "info" "man" ];
|
||||
depsBuildBuild = [ pkgs.buildPackages.stdenv.cc ];
|
||||
buildInputs = [ zlib ];
|
||||
enableParallelBuilding = true;
|
||||
binutils-arm = pkgs.callPackage binutils {
|
||||
platform = "arm";
|
||||
target = "armv7-unknown-linux-gnueabihf";
|
||||
};
|
||||
binutils-arm = pkgs.callPackage binutils { platform = "arm"; target = "armv7-unknown-linux-gnueabihf"; };
|
||||
|
||||
# FSBL configuration supplied by Vivado 2020.1 for these boards:
|
||||
fsblTargets = ["zc702" "zc706" "zed"];
|
||||
@ -110,13 +129,26 @@
|
||||
# kasli-soc satellite variants
|
||||
"satellite"
|
||||
# zc706 satellite variants
|
||||
"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"
|
||||
"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"
|
||||
];
|
||||
board-package-set = { target, variant, json ? null }: let
|
||||
board-package-set = {
|
||||
target,
|
||||
variant,
|
||||
json ? null,
|
||||
}: let
|
||||
szl = zynqpkgs."${target}-szl";
|
||||
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";
|
||||
|
||||
firmware = naerskLib.buildPackage rec {
|
||||
name = "firmware";
|
||||
@ -126,7 +158,7 @@
|
||||
|
||||
nativeBuildInputs = [
|
||||
pkgs.gnumake
|
||||
(pkgs.python3.withPackages(ps: [ ps.jsonschema artiqpkgs.migen migen-axi artiqpkgs.misoc artiqpkgs.artiq ]))
|
||||
(pkgs.python3.withPackages (ps: [artiqpkgs.migen migen-axi artiqpkgs.misoc artiqpkgs.artiq-build]))
|
||||
pkgs.llvmPackages_20.llvm
|
||||
pkgs.llvmPackages_20.clang-unwrapped
|
||||
];
|
||||
@ -136,7 +168,11 @@
|
||||
export ZYNQ_REV=${zynqRev}
|
||||
export CLANG_EXTRA_INCLUDE_DIR="${pkgs.llvmPackages_20.clang-unwrapped.lib}/lib/clang/20/include"
|
||||
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}
|
||||
'';
|
||||
|
||||
installPhase = ''
|
||||
@ -151,32 +187,39 @@
|
||||
dontFixup = true;
|
||||
};
|
||||
};
|
||||
gateware = pkgs.runCommand "${target}-${variant}-gateware"
|
||||
gateware =
|
||||
pkgs.runCommand "${target}-${variant}-gateware"
|
||||
{
|
||||
nativeBuildInputs = [
|
||||
(pkgs.python3.withPackages(ps: [ ps.jsonschema artiqpkgs.migen migen-axi artiqpkgs.misoc artiqpkgs.artiq ]))
|
||||
nativeBuildInputs = [
|
||||
(pkgs.python3.withPackages (ps: [artiqpkgs.migen migen-axi artiqpkgs.misoc artiqpkgs.artiq-build]))
|
||||
artiqpkgs.vivado
|
||||
];
|
||||
}
|
||||
''
|
||||
export ZYNQ_REV=${zynqRev}
|
||||
python ${./src/gateware}/${target}.py -g build ${if json == null then "-V ${variant}" else json}
|
||||
python ${./src/gateware}/${target}.py -g build ${
|
||||
if json == null
|
||||
then "-V ${variant}"
|
||||
else json
|
||||
}
|
||||
mkdir -p $out $out/nix-support
|
||||
cp build/top.bit $out
|
||||
echo file binary-dist $out/top.bit >> $out/nix-support/hydra-build-products
|
||||
'';
|
||||
|
||||
# SZL startup
|
||||
jtag = pkgs.runCommand "${target}-${variant}-jtag" {}
|
||||
jtag =
|
||||
pkgs.runCommand "${target}-${variant}-jtag" {}
|
||||
''
|
||||
mkdir $out
|
||||
ln -s ${szl}/szl.elf $out
|
||||
ln -s ${firmware}/${fwtype}.bin $out
|
||||
ln -s ${gateware}/top.bit $out
|
||||
'';
|
||||
sd = pkgs.runCommand "${target}-${variant}-sd"
|
||||
sd =
|
||||
pkgs.runCommand "${target}-${variant}-sd"
|
||||
{
|
||||
buildInputs = [ zynqpkgs.mkbootimage ];
|
||||
buildInputs = [zynqpkgs.mkbootimage];
|
||||
}
|
||||
''
|
||||
# Do not use "long" paths in boot.bif, because embedded developers
|
||||
@ -200,9 +243,10 @@
|
||||
'';
|
||||
|
||||
# FSBL startup
|
||||
fsbl-sd = pkgs.runCommand "${target}-${variant}-fsbl-sd"
|
||||
fsbl-sd =
|
||||
pkgs.runCommand "${target}-${variant}-fsbl-sd"
|
||||
{
|
||||
buildInputs = [ zynqpkgs.mkbootimage ];
|
||||
buildInputs = [zynqpkgs.mkbootimage];
|
||||
}
|
||||
''
|
||||
bifdir=`mktemp -d`
|
||||
@ -222,33 +266,34 @@
|
||||
mkbootimage boot.bif $out/boot.bin
|
||||
echo file binary-dist $out/boot.bin >> $out/nix-support/hydra-build-products
|
||||
'';
|
||||
in {
|
||||
"${target}-${variant}-firmware" = firmware;
|
||||
"${target}-${variant}-gateware" = gateware;
|
||||
"${target}-${variant}-jtag" = jtag;
|
||||
"${target}-${variant}-sd" = sd;
|
||||
} // (
|
||||
if builtins.elem target fsblTargets
|
||||
then {
|
||||
"${target}-${variant}-fsbl-sd" = fsbl-sd;
|
||||
in
|
||||
{
|
||||
"${target}-${variant}-firmware" = firmware;
|
||||
"${target}-${variant}-gateware" = gateware;
|
||||
"${target}-${variant}-jtag" = jtag;
|
||||
"${target}-${variant}-sd" = sd;
|
||||
}
|
||||
else {}
|
||||
);
|
||||
// (
|
||||
if builtins.elem target fsblTargets
|
||||
then {
|
||||
"${target}-${variant}-fsbl-sd" = fsbl-sd;
|
||||
}
|
||||
else {}
|
||||
);
|
||||
|
||||
gateware-sim = pkgs.stdenv.mkDerivation {
|
||||
name = "gateware-sim";
|
||||
|
||||
nativeBuildInputs = [
|
||||
(pkgs.python3.withPackages(ps: [ artiqpkgs.migen migen-axi artiqpkgs.artiq ]))
|
||||
|
||||
nativeBuildInputs = [
|
||||
(pkgs.python3.withPackages (ps: [artiqpkgs.migen migen-axi artiqpkgs.artiq-build]))
|
||||
];
|
||||
|
||||
phases = [ "buildPhase" ];
|
||||
phases = ["buildPhase"];
|
||||
|
||||
buildPhase =
|
||||
''
|
||||
buildPhase = ''
|
||||
python -m unittest discover ${self}/src/gateware -v
|
||||
touch $out
|
||||
'';
|
||||
'';
|
||||
};
|
||||
|
||||
fmt-check = pkgs.stdenvNoCC.mkDerivation {
|
||||
@ -256,35 +301,45 @@
|
||||
|
||||
src = ./src;
|
||||
|
||||
nativeBuildInputs = [ rust pkgs.gnumake ];
|
||||
nativeBuildInputs = [rust pkgs.gnumake];
|
||||
|
||||
phases = [ "unpackPhase" "buildPhase" ];
|
||||
phases = ["unpackPhase" "buildPhase"];
|
||||
|
||||
buildPhase =
|
||||
''
|
||||
buildPhase = ''
|
||||
export ZYNQ_RS=${zynq-rs}
|
||||
make manifests
|
||||
cargo fmt -- --check
|
||||
touch $out
|
||||
'';
|
||||
'';
|
||||
};
|
||||
|
||||
# for hitl-tests
|
||||
zc706-nist_qc2 = (board-package-set { target = "zc706"; variant = "nist_qc2"; });
|
||||
zc706-hitl-tests = pkgs.stdenv.mkDerivation {
|
||||
name = "zc706-hitl-tests";
|
||||
zc706-nist_qc2 = board-package-set {
|
||||
target = "zc706";
|
||||
variant = "nist_qc2";
|
||||
};
|
||||
zc706-acpki_nist_qc2 = board-package-set {
|
||||
target = "zc706";
|
||||
variant = "acpki_nist_qc2";
|
||||
};
|
||||
make-zc706-hitl-tests = { name, board-package }: pkgs.stdenv.mkDerivation {
|
||||
name = "zc706-hitl-tests-${name}";
|
||||
|
||||
__networked = true; # compatibility with old patched Nix
|
||||
__networked = true; # compatibility with old patched Nix
|
||||
# breaks hydra, https://github.com/NixOS/hydra/issues/1216
|
||||
#__impure = true; # Nix 2.8+
|
||||
|
||||
buildInputs = [
|
||||
pkgs.netcat pkgs.openssh pkgs.rsync artiqpkgs.artiq artiq-netboot zynqpkgs.zc706-szl
|
||||
pkgs.netcat
|
||||
pkgs.openssh
|
||||
pkgs.rsync
|
||||
artiqpkgs.artiq
|
||||
artiq-netboot
|
||||
zynqpkgs.zc706-szl
|
||||
];
|
||||
phases = [ "buildPhase" ];
|
||||
phases = ["buildPhase"];
|
||||
|
||||
buildPhase =
|
||||
''
|
||||
buildPhase = ''
|
||||
export NIX_SSHOPTS="-F /dev/null -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o LogLevel=ERROR -i /opt/hydra_id_ed25519"
|
||||
LOCKCTL=$(mktemp -d)
|
||||
mkfifo $LOCKCTL/lockctl
|
||||
@ -310,7 +365,7 @@
|
||||
export USER=hydra
|
||||
export OPENOCD_ZYNQ=${zynq-rs}/openocd
|
||||
export SZL=${zynqpkgs.szl}
|
||||
bash ${self}/remote_run.sh -h rpi-4 -o "$NIX_SSHOPTS" -d ${zc706-nist_qc2.zc706-nist_qc2-jtag}
|
||||
bash ${self}/remote_run.sh -h rpi-4 -o "$NIX_SSHOPTS" -d ${board-package}
|
||||
|
||||
echo Waiting for the firmware to boot...
|
||||
sleep 15
|
||||
@ -330,40 +385,130 @@
|
||||
(echo b; sleep 5) | nc -N -w6 192.168.1.31 3131
|
||||
echo Board powered off
|
||||
)
|
||||
'';
|
||||
'';
|
||||
};
|
||||
zc706-hitl-tests = make-zc706-hitl-tests { name = "nist_qc2"; board-package = zc706-nist_qc2.zc706-nist_qc2-jtag; };
|
||||
zc706-acpki-hitl-tests = make-zc706-hitl-tests { name = "acpki_nist_qc2"; board-package = zc706-acpki_nist_qc2.zc706-acpki_nist_qc2-jtag; };
|
||||
|
||||
in rec {
|
||||
packages.x86_64-linux =
|
||||
{
|
||||
inherit fastnumbers artiq-netboot ramda migen-axi binutils-arm;
|
||||
} //
|
||||
(board-package-set { target = "zc706"; variant = "cxp_4r_fmc"; }) //
|
||||
(board-package-set { target = "zc706"; variant = "nist_clock"; }) //
|
||||
(board-package-set { target = "zc706"; variant = "nist_clock_master"; }) //
|
||||
(board-package-set { target = "zc706"; variant = "nist_clock_master_100mhz"; }) //
|
||||
(board-package-set { target = "zc706"; variant = "nist_clock_satellite"; }) //
|
||||
(board-package-set { target = "zc706"; variant = "nist_clock_satellite_100mhz"; }) //
|
||||
(board-package-set { target = "zc706"; variant = "nist_qc2"; }) //
|
||||
(board-package-set { target = "zc706"; variant = "nist_qc2_master"; }) //
|
||||
(board-package-set { target = "zc706"; variant = "nist_qc2_master_100mhz"; }) //
|
||||
(board-package-set { target = "zc706"; variant = "nist_qc2_satellite"; }) //
|
||||
(board-package-set { target = "zc706"; variant = "nist_qc2_satellite_100mhz"; }) //
|
||||
(board-package-set { target = "zc706"; variant = "acpki_nist_clock"; }) //
|
||||
(board-package-set { target = "zc706"; variant = "acpki_nist_clock_master"; }) //
|
||||
(board-package-set { target = "zc706"; variant = "acpki_nist_clock_master_100mhz"; }) //
|
||||
(board-package-set { target = "zc706"; variant = "acpki_nist_clock_satellite"; }) //
|
||||
(board-package-set { target = "zc706"; variant = "acpki_nist_clock_satellite_100mhz"; }) //
|
||||
(board-package-set { target = "zc706"; variant = "acpki_nist_qc2"; }) //
|
||||
(board-package-set { target = "zc706"; variant = "acpki_nist_qc2_master"; }) //
|
||||
(board-package-set { target = "zc706"; variant = "acpki_nist_qc2_master_100mhz"; }) //
|
||||
(board-package-set { target = "zc706"; variant = "acpki_nist_qc2_satellite"; }) //
|
||||
(board-package-set { target = "zc706"; variant = "acpki_nist_qc2_satellite_100mhz"; }) //
|
||||
(board-package-set { target = "kasli_soc"; variant = "demo"; json = ./demo.json; }) //
|
||||
(board-package-set { target = "kasli_soc"; variant = "master"; json = ./kasli-soc-master.json; }) //
|
||||
(board-package-set { target = "kasli_soc"; variant = "satellite"; json = ./kasli-soc-satellite.json; }) //
|
||||
(board-package-set { target = "ebaz4205"; variant = "base"; });
|
||||
}
|
||||
// (board-package-set {
|
||||
target = "zc706";
|
||||
variant = "cxp_4r_fmc";
|
||||
})
|
||||
// (board-package-set {
|
||||
target = "zc706";
|
||||
variant = "nist_clock";
|
||||
})
|
||||
// (board-package-set {
|
||||
target = "zc706";
|
||||
variant = "nist_clock_master";
|
||||
})
|
||||
// (board-package-set {
|
||||
target = "zc706";
|
||||
variant = "nist_clock_master_100mhz";
|
||||
})
|
||||
// (board-package-set {
|
||||
target = "zc706";
|
||||
variant = "nist_clock_satellite";
|
||||
})
|
||||
// (board-package-set {
|
||||
target = "zc706";
|
||||
variant = "nist_clock_satellite_100mhz";
|
||||
})
|
||||
// (board-package-set {
|
||||
target = "zc706";
|
||||
variant = "nist_qc2";
|
||||
})
|
||||
// (board-package-set {
|
||||
target = "zc706";
|
||||
variant = "nist_qc2_master";
|
||||
})
|
||||
// (board-package-set {
|
||||
target = "zc706";
|
||||
variant = "nist_qc2_master_100mhz";
|
||||
})
|
||||
// (board-package-set {
|
||||
target = "zc706";
|
||||
variant = "nist_qc2_satellite";
|
||||
})
|
||||
// (board-package-set {
|
||||
target = "zc706";
|
||||
variant = "nist_qc2_satellite_100mhz";
|
||||
})
|
||||
// (board-package-set {
|
||||
target = "zc706";
|
||||
variant = "acpki_nist_clock";
|
||||
})
|
||||
// (board-package-set {
|
||||
target = "zc706";
|
||||
variant = "acpki_nist_clock_master";
|
||||
})
|
||||
// (board-package-set {
|
||||
target = "zc706";
|
||||
variant = "acpki_nist_clock_master_100mhz";
|
||||
})
|
||||
// (board-package-set {
|
||||
target = "zc706";
|
||||
variant = "acpki_nist_clock_satellite";
|
||||
})
|
||||
// (board-package-set {
|
||||
target = "zc706";
|
||||
variant = "acpki_nist_clock_satellite_100mhz";
|
||||
})
|
||||
// (board-package-set {
|
||||
target = "zc706";
|
||||
variant = "acpki_nist_qc2";
|
||||
})
|
||||
// (board-package-set {
|
||||
target = "zc706";
|
||||
variant = "acpki_nist_qc2_master";
|
||||
})
|
||||
// (board-package-set {
|
||||
target = "zc706";
|
||||
variant = "acpki_nist_qc2_master_100mhz";
|
||||
})
|
||||
// (board-package-set {
|
||||
target = "zc706";
|
||||
variant = "acpki_nist_qc2_satellite";
|
||||
})
|
||||
// (board-package-set {
|
||||
target = "zc706";
|
||||
variant = "acpki_nist_qc2_satellite_100mhz";
|
||||
})
|
||||
// (board-package-set {
|
||||
target = "kasli_soc";
|
||||
variant = "demo";
|
||||
json = ./demo.json;
|
||||
})
|
||||
// (board-package-set {
|
||||
target = "kasli_soc";
|
||||
variant = "master";
|
||||
json = ./kasli-soc-master.json;
|
||||
})
|
||||
// (board-package-set {
|
||||
target = "kasli_soc";
|
||||
variant = "satellite";
|
||||
json = ./kasli-soc-satellite.json;
|
||||
})
|
||||
// (board-package-set {
|
||||
target = "ebaz4205";
|
||||
variant = "base";
|
||||
});
|
||||
|
||||
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 zc706-acpki-hitl-tests;
|
||||
inherit gateware-sim;
|
||||
inherit fmt-check;
|
||||
};
|
||||
|
||||
formatter.x86_64-linux = pkgs.alejandra;
|
||||
|
||||
devShell.x86_64-linux = pkgs.mkShell {
|
||||
name = "artiq-zynq-dev-shell";
|
||||
@ -374,15 +519,16 @@
|
||||
gnumake
|
||||
cacert
|
||||
zynqpkgs.mkbootimage
|
||||
openocd
|
||||
openssh rsync
|
||||
(python3.withPackages(ps: (with artiqpkgs; [ migen migen-axi misoc artiq artiq-netboot ps.jsonschema ps.pyftdi ])))
|
||||
openocd
|
||||
openssh
|
||||
rsync
|
||||
(python3.withPackages (ps: (with artiqpkgs; [migen migen-axi misoc artiq artiq-netboot ps.jsonschema ps.pyftdi])))
|
||||
artiqpkgs.artiq
|
||||
artiqpkgs.vivado
|
||||
binutils-arm
|
||||
pre-commit
|
||||
];
|
||||
ZYNQ_REV="${zynqRev}";
|
||||
ZYNQ_REV = "${zynqRev}";
|
||||
CLANG_EXTRA_INCLUDE_DIR = "${pkgs.llvmPackages_20.clang-unwrapped.lib}/lib/clang/20/include";
|
||||
ZYNQ_RS = "${zynq-rs}";
|
||||
OPENOCD_ZYNQ = "${zynq-rs}/openocd";
|
||||
@ -390,6 +536,5 @@
|
||||
};
|
||||
|
||||
makeArtiqZynqPackage = board-package-set;
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
"target": "kasli_soc",
|
||||
"variant": "master",
|
||||
"hw_rev": "v1.0",
|
||||
"base": "master",
|
||||
"drtio_role": "master",
|
||||
"peripherals": [
|
||||
{
|
||||
"type": "coaxpress_sfp"
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
"target": "kasli_soc",
|
||||
"variant": "satellite",
|
||||
"hw_rev": "v1.0",
|
||||
"base": "satellite",
|
||||
"drtio_role": "satellite",
|
||||
"peripherals": [
|
||||
{
|
||||
"type": "coaxpress_sfp"
|
||||
|
||||
@ -13,7 +13,7 @@ if [ -z "$SZL" ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
target_host="rpi-4.m-labs.hk"
|
||||
target_host="rpi-4"
|
||||
impure=0
|
||||
pure_dir="result"
|
||||
impure_dir="build"
|
||||
|
||||
4
src/Cargo.lock
generated
4
src/Cargo.lock
generated
@ -244,7 +244,6 @@ dependencies = [
|
||||
"log",
|
||||
"log_buffer",
|
||||
"nalgebra",
|
||||
"nb 0.1.3",
|
||||
"unwind",
|
||||
"vcell",
|
||||
"void",
|
||||
@ -255,6 +254,7 @@ name = "libasync"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"embedded-hal",
|
||||
"libcortex_a9",
|
||||
"nb 1.0.0",
|
||||
"smoltcp",
|
||||
]
|
||||
@ -311,6 +311,7 @@ dependencies = [
|
||||
"core_io",
|
||||
"fatfs",
|
||||
"libboard_zynq",
|
||||
"libcortex_a9",
|
||||
"log",
|
||||
]
|
||||
|
||||
@ -523,6 +524,7 @@ dependencies = [
|
||||
"libsupport_zynq",
|
||||
"log",
|
||||
"log_buffer",
|
||||
"nb 0.1.3",
|
||||
"num-derive",
|
||||
"num-traits",
|
||||
"tar-no-std",
|
||||
|
||||
@ -14,6 +14,7 @@ IN_BURST_LEN = 4
|
||||
class Engine(Module, AutoCSR):
|
||||
def __init__(self, bus, user):
|
||||
self.addr_base = CSRStorage(32)
|
||||
# statistics (unused)
|
||||
self.trig_count = CSRStatus(32)
|
||||
self.write_count = CSRStatus(32)
|
||||
|
||||
@ -21,8 +22,8 @@ class Engine(Module, AutoCSR):
|
||||
|
||||
# Dout : Data received from CPU, output by DMA module
|
||||
# Din : Data driven into DMA module, written into CPU
|
||||
# When stb assert, index shows word being read/written, dout/din holds
|
||||
# data
|
||||
# When stb is asserted, index shows word being read/written,
|
||||
# dout/din holds data
|
||||
#
|
||||
# Cycle:
|
||||
# trigger_stb pulsed at start
|
||||
@ -53,8 +54,8 @@ class Engine(Module, AutoCSR):
|
||||
self.dout.eq(r.data),
|
||||
r.ready.eq(1),
|
||||
ar.burst.eq(axi.Burst.incr.value),
|
||||
ar.len.eq(OUT_BURST_LEN-1), # Number of transfers in burst (0->1 transfer, 1->2 transfers...)
|
||||
ar.size.eq(3), # Width of burst: 3 = 8 bytes = 64 bits
|
||||
ar.len.eq(OUT_BURST_LEN-1), # Number of transfers in burst (0->1 transfer, 1->2 transfers...)
|
||||
ar.size.eq(3), # Width of burst: 3 = 8 bytes = 64 bits
|
||||
ar.cache.eq(0xf),
|
||||
]
|
||||
|
||||
@ -86,9 +87,8 @@ class Engine(Module, AutoCSR):
|
||||
self.sync += [
|
||||
If(read_fsm.ongoing("IDLE"),
|
||||
self.dout_index.eq(0)
|
||||
).Else(If(r.valid & read_fsm.ongoing("READ"),
|
||||
self.dout_index.eq(self.dout_index+1)
|
||||
)
|
||||
).Elif(r.valid & read_fsm.ongoing("READ"),
|
||||
self.dout_index.eq(self.dout_index+1)
|
||||
)
|
||||
]
|
||||
|
||||
@ -100,8 +100,8 @@ class Engine(Module, AutoCSR):
|
||||
aw.addr.eq(self.addr_base.storage+96),
|
||||
w.strb.eq(0xff),
|
||||
aw.burst.eq(axi.Burst.incr.value),
|
||||
aw.len.eq(IN_BURST_LEN-1), # Number of transfers in burst minus 1
|
||||
aw.size.eq(3), # Width of burst: 3 = 8 bytes = 64 bits
|
||||
aw.len.eq(IN_BURST_LEN-1), # Number of transfers in burst minus 1
|
||||
aw.size.eq(3), # Width of burst: 3 = 8 bytes = 64 bits
|
||||
aw.cache.eq(0xf),
|
||||
b.ready.eq(1),
|
||||
]
|
||||
@ -113,7 +113,7 @@ class Engine(Module, AutoCSR):
|
||||
aw.valid.eq(0),
|
||||
If(self.trigger_stb,
|
||||
aw.valid.eq(1),
|
||||
If(aw.ready, # assumes aw.ready is not randomly deasserted
|
||||
If(aw.ready, # assumes aw.ready is not deasserted from now on
|
||||
NextState("DATA_WAIT")
|
||||
).Else(
|
||||
NextState("AW_READY_WAIT")
|
||||
@ -140,9 +140,9 @@ class Engine(Module, AutoCSR):
|
||||
)
|
||||
)
|
||||
|
||||
self.sync += If(w.ready & w.valid, self.write_count.status.eq(self.write_count.status+1))
|
||||
|
||||
self.sync += [
|
||||
If(w.ready & w.valid,
|
||||
self.write_count.status.eq(self.write_count.status+1)),
|
||||
If(write_fsm.ongoing("IDLE"),
|
||||
self.din_index.eq(0)
|
||||
),
|
||||
@ -150,17 +150,15 @@ class Engine(Module, AutoCSR):
|
||||
]
|
||||
|
||||
self.comb += [
|
||||
w.last.eq(0),
|
||||
If(self.din_index==aw.len, w.last.eq(1))
|
||||
w.last.eq(self.din_index==aw.len),
|
||||
self.din_stb.eq(w.valid & w.ready)
|
||||
]
|
||||
|
||||
self.comb += self.din_stb.eq(w.valid & w.ready)
|
||||
|
||||
|
||||
|
||||
class KernelInitiator(Module, AutoCSR):
|
||||
def __init__(self, tsc, bus, user, evento):
|
||||
# Core is disabled upon reset to avoid spurious triggering if evento toggles from e.g. boot code.
|
||||
# Should be also reset between kernels (?)
|
||||
self.enable = CSRStorage()
|
||||
|
||||
self.counter = CSRStatus(64)
|
||||
@ -186,26 +184,33 @@ class KernelInitiator(Module, AutoCSR):
|
||||
cmd_write = Signal()
|
||||
cmd_read = Signal()
|
||||
self.comb += [
|
||||
cmd_write.eq(cmd == 0),
|
||||
cmd_read.eq(cmd == 1)
|
||||
cmd_write.eq(cmd == 0), # rtio output
|
||||
cmd_read.eq(cmd == 1) # rtio input
|
||||
]
|
||||
|
||||
out_len = Signal(8)
|
||||
dout_cases = {}
|
||||
# request_cmd: i8
|
||||
# data_width: i8
|
||||
# padding0: [i8; 2]
|
||||
# request_target: i32
|
||||
dout_cases[0] = [
|
||||
cmd.eq(self.engine.dout[:8]),
|
||||
out_len.eq(self.engine.dout[8:16]),
|
||||
cri.o_address.eq(self.engine.dout[32:40]),
|
||||
cri.chan_sel.eq(self.engine.dout[40:]),
|
||||
cri.o_address.eq(self.engine.dout[32:40])
|
||||
]
|
||||
for i in range(8):
|
||||
target = cri.o_data[i*64:(i+1)*64]
|
||||
dout_cases[0] += [If(i >= self.engine.dout[8:16], target.eq(0))]
|
||||
|
||||
# request_timestamp: i64
|
||||
dout_cases[1] = [
|
||||
cri.o_timestamp.eq(self.engine.dout),
|
||||
cri.i_timeout.eq(self.engine.dout)
|
||||
]
|
||||
# request_data: [i32; 16]
|
||||
# packed into 64 bit * 8 here?
|
||||
for i in range(8):
|
||||
target = cri.o_data[i*64:(i+1)*64]
|
||||
dout_cases[i+2] = [target.eq(self.engine.dout)]
|
||||
@ -221,8 +226,8 @@ class KernelInitiator(Module, AutoCSR):
|
||||
)
|
||||
]
|
||||
|
||||
# If input event, wait for response before allow input data to be
|
||||
# sampled
|
||||
# If input event, wait for response before
|
||||
# allowing the input data to be sampled
|
||||
# TODO: If output, wait for wait flag clear
|
||||
RTIO_I_STATUS_WAIT_STATUS = 4
|
||||
RTIO_O_STATUS_WAIT = 1
|
||||
@ -230,24 +235,24 @@ class KernelInitiator(Module, AutoCSR):
|
||||
self.submodules.fsm = fsm = FSM(reset_state="IDLE")
|
||||
|
||||
fsm.act("IDLE",
|
||||
If(self.engine.trigger_stb, NextState("WAIT_OUT_CYCLE"))
|
||||
If(self.engine.trigger_stb,
|
||||
NextState("WAIT_OUT_CYCLE")),
|
||||
)
|
||||
fsm.act("WAIT_OUT_CYCLE",
|
||||
self.engine.din_ready.eq(0),
|
||||
If(self.engine.dout_stb & cmd_write & (self.engine.dout_index == out_len + 2),
|
||||
NextState("WAIT_READY")
|
||||
If(self.engine.dout_stb & cmd_write & (self.engine.dout_index == out_len + 3),
|
||||
NextState("WAIT_READY")
|
||||
),
|
||||
# for some reason read requires some delay until the next state
|
||||
If(self.engine.dout_stb & cmd_read & (self.engine.dout_index == out_len + 3),
|
||||
NextState("WAIT_READY")
|
||||
)
|
||||
)
|
||||
fsm.act("WAIT_READY",
|
||||
If(cmd_read & (cri.i_status & RTIO_I_STATUS_WAIT_STATUS == 0) \
|
||||
| cmd_write & ~(cri.o_status & RTIO_O_STATUS_WAIT),
|
||||
| cmd_write & (cri.o_status & RTIO_O_STATUS_WAIT == 0),
|
||||
self.engine.din_ready.eq(1),
|
||||
NextState("IDLE")
|
||||
)
|
||||
),
|
||||
)
|
||||
|
||||
din_cases_cmdwrite = {
|
||||
@ -255,7 +260,9 @@ class KernelInitiator(Module, AutoCSR):
|
||||
1: [self.engine.din.eq(0)],
|
||||
}
|
||||
din_cases_cmdread = {
|
||||
# reply_status: VolatileCell<i32>, reply_data: VolatileCell<i32>
|
||||
0: [self.engine.din[:32].eq((1<<16) | cri.i_status), self.engine.din[32:].eq(cri.i_data)],
|
||||
# reply_timestamp: VolatileCell<i64>,
|
||||
1: [self.engine.din.eq(cri.i_timestamp)]
|
||||
}
|
||||
|
||||
|
||||
@ -44,6 +44,7 @@ eem_iostandard_dict = {
|
||||
11: "LVDS",
|
||||
}
|
||||
|
||||
DRTIO_EEM_PERIPHERALS = ["shuttler", "phaser_drtio"]
|
||||
|
||||
def eem_iostandard(eem):
|
||||
return IOStandard(eem_iostandard_dict[eem])
|
||||
@ -273,7 +274,7 @@ class GenericMaster(SoCCore):
|
||||
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"] in DRTIO_EEM_PERIPHERALS for peripheral in description["peripherals"])
|
||||
self.acpki = acpki
|
||||
|
||||
platform = kasli_soc.Platform()
|
||||
@ -497,7 +498,7 @@ class GenericSatellite(SoCCore):
|
||||
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"] in DRTIO_EEM_PERIPHERALS for peripheral in description["peripherals"])
|
||||
self.acpki = acpki
|
||||
|
||||
platform = kasli_soc.Platform()
|
||||
@ -782,6 +783,10 @@ def main():
|
||||
else:
|
||||
raise ValueError("Invalid DRTIO role")
|
||||
|
||||
for peripheral in description["peripherals"]:
|
||||
if peripheral["type"] in DRTIO_EEM_PERIPHERALS and description["drtio_role"] == "standalone":
|
||||
raise ValueError("{} requires DRTIO, please switch role to master or satellite".format(peripheral["type"]))
|
||||
|
||||
soc = cls(description, acpki=args.acpki)
|
||||
soc.finalize()
|
||||
|
||||
|
||||
@ -303,14 +303,6 @@ pub enum Packet {
|
||||
CoreMgmtClearLogRequest {
|
||||
destination: u8,
|
||||
},
|
||||
CoreMgmtSetLogLevelRequest {
|
||||
destination: u8,
|
||||
log_level: u8,
|
||||
},
|
||||
CoreMgmtSetUartLogLevelRequest {
|
||||
destination: u8,
|
||||
log_level: u8,
|
||||
},
|
||||
CoreMgmtConfigReadRequest {
|
||||
destination: u8,
|
||||
length: u16,
|
||||
@ -689,15 +681,7 @@ impl Packet {
|
||||
0xd1 => Packet::CoreMgmtClearLogRequest {
|
||||
destination: reader.read_u8()?,
|
||||
},
|
||||
0xd2 => Packet::CoreMgmtSetLogLevelRequest {
|
||||
destination: reader.read_u8()?,
|
||||
log_level: reader.read_u8()?,
|
||||
},
|
||||
0xd3 => Packet::CoreMgmtSetUartLogLevelRequest {
|
||||
destination: reader.read_u8()?,
|
||||
log_level: reader.read_u8()?,
|
||||
},
|
||||
0xd4 => {
|
||||
0xd2 => {
|
||||
let destination = reader.read_u8()?;
|
||||
let length = reader.read_u16::<NativeEndian>()?;
|
||||
let mut key: [u8; MASTER_PAYLOAD_MAX_SIZE] = [0; MASTER_PAYLOAD_MAX_SIZE];
|
||||
@ -708,10 +692,10 @@ impl Packet {
|
||||
key: key,
|
||||
}
|
||||
}
|
||||
0xd5 => Packet::CoreMgmtConfigReadContinue {
|
||||
0xd3 => Packet::CoreMgmtConfigReadContinue {
|
||||
destination: reader.read_u8()?,
|
||||
},
|
||||
0xd6 => {
|
||||
0xd4 => {
|
||||
let destination = reader.read_u8()?;
|
||||
let last = reader.read_bool()?;
|
||||
let length = reader.read_u16::<NativeEndian>()?;
|
||||
@ -724,7 +708,7 @@ impl Packet {
|
||||
data: data,
|
||||
}
|
||||
}
|
||||
0xd7 => {
|
||||
0xd5 => {
|
||||
let destination = reader.read_u8()?;
|
||||
let length = reader.read_u16::<NativeEndian>()?;
|
||||
let mut key: [u8; MASTER_PAYLOAD_MAX_SIZE] = [0; MASTER_PAYLOAD_MAX_SIZE];
|
||||
@ -735,20 +719,20 @@ impl Packet {
|
||||
key: key,
|
||||
}
|
||||
}
|
||||
0xd8 => Packet::CoreMgmtConfigEraseRequest {
|
||||
0xd6 => Packet::CoreMgmtConfigEraseRequest {
|
||||
destination: reader.read_u8()?,
|
||||
},
|
||||
0xd9 => Packet::CoreMgmtRebootRequest {
|
||||
0xd7 => Packet::CoreMgmtRebootRequest {
|
||||
destination: reader.read_u8()?,
|
||||
},
|
||||
0xda => Packet::CoreMgmtAllocatorDebugRequest {
|
||||
0xd8 => Packet::CoreMgmtAllocatorDebugRequest {
|
||||
destination: reader.read_u8()?,
|
||||
},
|
||||
0xdb => Packet::CoreMgmtFlashRequest {
|
||||
0xd9 => Packet::CoreMgmtFlashRequest {
|
||||
destination: reader.read_u8()?,
|
||||
payload_length: reader.read_u32::<NativeEndian>()?,
|
||||
},
|
||||
0xdc => {
|
||||
0xda => {
|
||||
let destination = reader.read_u8()?;
|
||||
let last = reader.read_bool()?;
|
||||
let length = reader.read_u16::<NativeEndian>()?;
|
||||
@ -761,11 +745,11 @@ impl Packet {
|
||||
data: data,
|
||||
}
|
||||
}
|
||||
0xdd => Packet::CoreMgmtDropLinkAck {
|
||||
0xdb => Packet::CoreMgmtDropLinkAck {
|
||||
destination: reader.read_u8()?,
|
||||
},
|
||||
0xde => Packet::CoreMgmtDropLink,
|
||||
0xdf => {
|
||||
0xdc => Packet::CoreMgmtDropLink,
|
||||
0xdd => {
|
||||
let last = reader.read_bool()?;
|
||||
let length = reader.read_u16::<NativeEndian>()?;
|
||||
let mut data: [u8; SAT_PAYLOAD_MAX_SIZE] = [0; SAT_PAYLOAD_MAX_SIZE];
|
||||
@ -776,7 +760,7 @@ impl Packet {
|
||||
data: data,
|
||||
}
|
||||
}
|
||||
0xe0 => {
|
||||
0xde => {
|
||||
let last = reader.read_bool()?;
|
||||
let length = reader.read_u16::<NativeEndian>()?;
|
||||
let mut value: [u8; SAT_PAYLOAD_MAX_SIZE] = [0; SAT_PAYLOAD_MAX_SIZE];
|
||||
@ -787,45 +771,45 @@ impl Packet {
|
||||
value: value,
|
||||
}
|
||||
}
|
||||
0xe1 => Packet::CoreMgmtReply {
|
||||
0xdf => Packet::CoreMgmtReply {
|
||||
succeeded: reader.read_bool()?,
|
||||
},
|
||||
0xe2 => {
|
||||
0xe0 => {
|
||||
let length = reader.read_u16::<NativeEndian>()?;
|
||||
let mut message: [u8; CXP_PAYLOAD_MAX_SIZE] = [0; CXP_PAYLOAD_MAX_SIZE];
|
||||
reader.read_exact(&mut message[0..length as usize])?;
|
||||
Packet::CXPError { length, message }
|
||||
}
|
||||
0xe3 => Self::CXPWaitReply,
|
||||
0xe4 => Packet::CXPReadRequest {
|
||||
0xe1 => Self::CXPWaitReply,
|
||||
0xe2 => Packet::CXPReadRequest {
|
||||
destination: reader.read_u8()?,
|
||||
address: reader.read_u32::<NativeEndian>()?,
|
||||
length: reader.read_u16::<NativeEndian>()?,
|
||||
},
|
||||
0xe5 => {
|
||||
0xe3 => {
|
||||
let length = reader.read_u16::<NativeEndian>()?;
|
||||
let mut data: [u8; CXP_PAYLOAD_MAX_SIZE] = [0; CXP_PAYLOAD_MAX_SIZE];
|
||||
reader.read_exact(&mut data[0..length as usize])?;
|
||||
Packet::CXPReadReply { length, data }
|
||||
}
|
||||
0xe6 => Packet::CXPWrite32Request {
|
||||
0xe4 => Packet::CXPWrite32Request {
|
||||
destination: reader.read_u8()?,
|
||||
address: reader.read_u32::<NativeEndian>()?,
|
||||
value: reader.read_u32::<NativeEndian>()?,
|
||||
},
|
||||
0xe7 => Packet::CXPWrite32Reply,
|
||||
0xe8 => Packet::CXPROIViewerSetupRequest {
|
||||
0xe5 => Packet::CXPWrite32Reply,
|
||||
0xe6 => Packet::CXPROIViewerSetupRequest {
|
||||
destination: reader.read_u8()?,
|
||||
x0: reader.read_u16::<NativeEndian>()?,
|
||||
y0: reader.read_u16::<NativeEndian>()?,
|
||||
x1: reader.read_u16::<NativeEndian>()?,
|
||||
y1: reader.read_u16::<NativeEndian>()?,
|
||||
},
|
||||
0xe9 => Packet::CXPROIViewerSetupReply,
|
||||
0xea => Packet::CXPROIViewerDataRequest {
|
||||
0xe7 => Packet::CXPROIViewerSetupReply,
|
||||
0xe8 => Packet::CXPROIViewerDataRequest {
|
||||
destination: reader.read_u8()?,
|
||||
},
|
||||
0xeb => {
|
||||
0xe9 => {
|
||||
let length = reader.read_u16::<NativeEndian>()?;
|
||||
let mut data: [u64; CXP_PAYLOAD_MAX_SIZE / 8] = [0; CXP_PAYLOAD_MAX_SIZE / 8];
|
||||
for i in 0..length as usize {
|
||||
@ -833,7 +817,7 @@ impl Packet {
|
||||
}
|
||||
Packet::CXPROIViewerPixelDataReply { length, data }
|
||||
}
|
||||
0xec => Packet::CXPROIViewerFrameDataReply {
|
||||
0xea => Packet::CXPROIViewerFrameDataReply {
|
||||
width: reader.read_u16::<NativeEndian>()?,
|
||||
height: reader.read_u16::<NativeEndian>()?,
|
||||
pixel_code: reader.read_u16::<NativeEndian>()?,
|
||||
@ -1224,28 +1208,18 @@ impl Packet {
|
||||
writer.write_u8(0xd1)?;
|
||||
writer.write_u8(destination)?;
|
||||
}
|
||||
Packet::CoreMgmtSetLogLevelRequest { destination, log_level } => {
|
||||
writer.write_u8(0xd2)?;
|
||||
writer.write_u8(destination)?;
|
||||
writer.write_u8(log_level)?;
|
||||
}
|
||||
Packet::CoreMgmtSetUartLogLevelRequest { destination, log_level } => {
|
||||
writer.write_u8(0xd3)?;
|
||||
writer.write_u8(destination)?;
|
||||
writer.write_u8(log_level)?;
|
||||
}
|
||||
Packet::CoreMgmtConfigReadRequest {
|
||||
destination,
|
||||
length,
|
||||
key,
|
||||
} => {
|
||||
writer.write_u8(0xd4)?;
|
||||
writer.write_u8(0xd2)?;
|
||||
writer.write_u8(destination)?;
|
||||
writer.write_u16::<NativeEndian>(length)?;
|
||||
writer.write_all(&key[0..length as usize])?;
|
||||
}
|
||||
Packet::CoreMgmtConfigReadContinue { destination } => {
|
||||
writer.write_u8(0xd5)?;
|
||||
writer.write_u8(0xd3)?;
|
||||
writer.write_u8(destination)?;
|
||||
}
|
||||
Packet::CoreMgmtConfigWriteRequest {
|
||||
@ -1254,7 +1228,7 @@ impl Packet {
|
||||
length,
|
||||
data,
|
||||
} => {
|
||||
writer.write_u8(0xd6)?;
|
||||
writer.write_u8(0xd4)?;
|
||||
writer.write_u8(destination)?;
|
||||
writer.write_bool(last)?;
|
||||
writer.write_u16::<NativeEndian>(length)?;
|
||||
@ -1265,28 +1239,28 @@ impl Packet {
|
||||
length,
|
||||
key,
|
||||
} => {
|
||||
writer.write_u8(0xd7)?;
|
||||
writer.write_u8(0xd5)?;
|
||||
writer.write_u8(destination)?;
|
||||
writer.write_u16::<NativeEndian>(length)?;
|
||||
writer.write_all(&key[0..length as usize])?;
|
||||
}
|
||||
Packet::CoreMgmtConfigEraseRequest { destination } => {
|
||||
writer.write_u8(0xd8)?;
|
||||
writer.write_u8(0xd6)?;
|
||||
writer.write_u8(destination)?;
|
||||
}
|
||||
Packet::CoreMgmtRebootRequest { destination } => {
|
||||
writer.write_u8(0xd9)?;
|
||||
writer.write_u8(0xd7)?;
|
||||
writer.write_u8(destination)?;
|
||||
}
|
||||
Packet::CoreMgmtAllocatorDebugRequest { destination } => {
|
||||
writer.write_u8(0xda)?;
|
||||
writer.write_u8(0xd8)?;
|
||||
writer.write_u8(destination)?;
|
||||
}
|
||||
Packet::CoreMgmtFlashRequest {
|
||||
destination,
|
||||
payload_length,
|
||||
} => {
|
||||
writer.write_u8(0xdb)?;
|
||||
writer.write_u8(0xd9)?;
|
||||
writer.write_u8(destination)?;
|
||||
writer.write_u32::<NativeEndian>(payload_length)?;
|
||||
}
|
||||
@ -1296,53 +1270,53 @@ impl Packet {
|
||||
length,
|
||||
data,
|
||||
} => {
|
||||
writer.write_u8(0xdc)?;
|
||||
writer.write_u8(0xda)?;
|
||||
writer.write_u8(destination)?;
|
||||
writer.write_bool(last)?;
|
||||
writer.write_u16::<NativeEndian>(length)?;
|
||||
writer.write_all(&data[..length as usize])?;
|
||||
}
|
||||
Packet::CoreMgmtDropLinkAck { destination } => {
|
||||
writer.write_u8(0xdd)?;
|
||||
writer.write_u8(0xdb)?;
|
||||
writer.write_u8(destination)?;
|
||||
}
|
||||
Packet::CoreMgmtDropLink => writer.write_u8(0xde)?,
|
||||
Packet::CoreMgmtDropLink => writer.write_u8(0xdc)?,
|
||||
Packet::CoreMgmtGetLogReply { last, length, data } => {
|
||||
writer.write_u8(0xdf)?;
|
||||
writer.write_u8(0xdd)?;
|
||||
writer.write_bool(last)?;
|
||||
writer.write_u16::<NativeEndian>(length)?;
|
||||
writer.write_all(&data[0..length as usize])?;
|
||||
}
|
||||
Packet::CoreMgmtConfigReadReply { last, length, value } => {
|
||||
writer.write_u8(0xe0)?;
|
||||
writer.write_u8(0xde)?;
|
||||
writer.write_bool(last)?;
|
||||
writer.write_u16::<NativeEndian>(length)?;
|
||||
writer.write_all(&value[0..length as usize])?;
|
||||
}
|
||||
Packet::CoreMgmtReply { succeeded } => {
|
||||
writer.write_u8(0xe1)?;
|
||||
writer.write_u8(0xdf)?;
|
||||
writer.write_bool(succeeded)?;
|
||||
}
|
||||
Packet::CXPError { length, message } => {
|
||||
writer.write_u8(0xe2)?;
|
||||
writer.write_u8(0xe0)?;
|
||||
writer.write_u16::<NativeEndian>(length)?;
|
||||
writer.write_all(&message[0..length as usize])?;
|
||||
}
|
||||
Packet::CXPWaitReply => {
|
||||
writer.write_u8(0xe3)?;
|
||||
writer.write_u8(0xe1)?;
|
||||
}
|
||||
Packet::CXPReadRequest {
|
||||
destination,
|
||||
address,
|
||||
length,
|
||||
} => {
|
||||
writer.write_u8(0xe4)?;
|
||||
writer.write_u8(0xe2)?;
|
||||
writer.write_u8(destination)?;
|
||||
writer.write_u32::<NativeEndian>(address)?;
|
||||
writer.write_u16::<NativeEndian>(length)?;
|
||||
}
|
||||
Packet::CXPReadReply { length, data } => {
|
||||
writer.write_u8(0xe5)?;
|
||||
writer.write_u8(0xe3)?;
|
||||
writer.write_u16::<NativeEndian>(length)?;
|
||||
writer.write_all(&data[0..length as usize])?;
|
||||
}
|
||||
@ -1351,13 +1325,13 @@ impl Packet {
|
||||
address,
|
||||
value,
|
||||
} => {
|
||||
writer.write_u8(0xe6)?;
|
||||
writer.write_u8(0xe4)?;
|
||||
writer.write_u8(destination)?;
|
||||
writer.write_u32::<NativeEndian>(address)?;
|
||||
writer.write_u32::<NativeEndian>(value)?;
|
||||
}
|
||||
Packet::CXPWrite32Reply => {
|
||||
writer.write_u8(0xe7)?;
|
||||
writer.write_u8(0xe5)?;
|
||||
}
|
||||
Packet::CXPROIViewerSetupRequest {
|
||||
destination,
|
||||
@ -1366,7 +1340,7 @@ impl Packet {
|
||||
x1,
|
||||
y1,
|
||||
} => {
|
||||
writer.write_u8(0xe8)?;
|
||||
writer.write_u8(0xe6)?;
|
||||
writer.write_u8(destination)?;
|
||||
writer.write_u16::<NativeEndian>(x0)?;
|
||||
writer.write_u16::<NativeEndian>(y0)?;
|
||||
@ -1374,14 +1348,14 @@ impl Packet {
|
||||
writer.write_u16::<NativeEndian>(y1)?;
|
||||
}
|
||||
Packet::CXPROIViewerSetupReply => {
|
||||
writer.write_u8(0xe9)?;
|
||||
writer.write_u8(0xe7)?;
|
||||
}
|
||||
Packet::CXPROIViewerDataRequest { destination } => {
|
||||
writer.write_u8(0xea)?;
|
||||
writer.write_u8(0xe8)?;
|
||||
writer.write_u8(destination)?;
|
||||
}
|
||||
Packet::CXPROIViewerPixelDataReply { length, data } => {
|
||||
writer.write_u8(0xeb)?;
|
||||
writer.write_u8(0xe9)?;
|
||||
writer.write_u16::<NativeEndian>(length)?;
|
||||
for i in 0..length as usize {
|
||||
writer.write_u64::<NativeEndian>(data[i])?;
|
||||
@ -1392,7 +1366,7 @@ impl Packet {
|
||||
height,
|
||||
pixel_code,
|
||||
} => {
|
||||
writer.write_u8(0xec)?;
|
||||
writer.write_u8(0xea)?;
|
||||
writer.write_u16::<NativeEndian>(width)?;
|
||||
writer.write_u16::<NativeEndian>(height)?;
|
||||
writer.write_u16::<NativeEndian>(pixel_code)?;
|
||||
|
||||
@ -18,8 +18,10 @@ const IODIR_OUT_SFP_TX_DISABLE: u8 = 0x02;
|
||||
const IODIR_OUT_SFP_LED: u8 = 0x40;
|
||||
#[cfg(hw_rev = "v1.0")]
|
||||
const IODIR_OUT_SFP0_LED: u8 = 0x40;
|
||||
#[cfg(hw_rev = "v1.1")]
|
||||
#[cfg(any(hw_rev = "v1.1", hw_rev = "v1.2"))]
|
||||
const IODIR_OUT_SFP0_LED: u8 = 0x80;
|
||||
#[cfg(hw_rev = "v1.2")]
|
||||
const IODIR_OUT_EEM_PWR_EN: u8 = 0x80;
|
||||
#[cfg(has_si549)]
|
||||
const IODIR_CLK_SEL: u8 = 0x80; // out
|
||||
#[cfg(has_si5324)]
|
||||
@ -31,10 +33,16 @@ const IODIR0: [u8; 2] = [
|
||||
0xFF & !IODIR_OUT_SFP_TX_DISABLE & !IODIR_OUT_SFP_LED & !IODIR_CLK_SEL,
|
||||
];
|
||||
|
||||
#[cfg(not(hw_rev = "v1.2"))]
|
||||
const IODIR1: [u8; 2] = [
|
||||
0xFF & !IODIR_OUT_SFP_TX_DISABLE & !IODIR_OUT_SFP_LED,
|
||||
0xFF & !IODIR_OUT_SFP_TX_DISABLE & !IODIR_OUT_SFP_LED,
|
||||
];
|
||||
#[cfg(hw_rev = "v1.2")]
|
||||
const IODIR1: [u8; 2] = [
|
||||
0xFF & !IODIR_OUT_SFP_TX_DISABLE & !IODIR_OUT_SFP_LED & !IODIR_OUT_EEM_PWR_EN,
|
||||
0xFF & !IODIR_OUT_SFP_TX_DISABLE & !IODIR_OUT_SFP_LED,
|
||||
];
|
||||
|
||||
pub struct IoExpander {
|
||||
address: u8,
|
||||
@ -50,7 +58,7 @@ impl IoExpander {
|
||||
pub fn new(i2c: &mut i2c::I2c, index: u8) -> Result<Self, &'static str> {
|
||||
#[cfg(all(hw_rev = "v1.0", has_virtual_leds))]
|
||||
const VIRTUAL_LED_MAPPING0: [(u8, u8, u8); 2] = [(0, 0, 6), (1, 1, 6)];
|
||||
#[cfg(all(hw_rev = "v1.1", has_virtual_leds))]
|
||||
#[cfg(all(any(hw_rev = "v1.1", hw_rev = "v1.2"), has_virtual_leds))]
|
||||
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)];
|
||||
|
||||
@ -3,7 +3,6 @@
|
||||
#![feature(naked_functions)]
|
||||
#![allow(unexpected_cfgs)]
|
||||
|
||||
#[cfg(has_drtio_eem)]
|
||||
extern crate alloc;
|
||||
extern crate core_io;
|
||||
extern crate crc;
|
||||
@ -42,8 +41,14 @@ pub mod grabber;
|
||||
pub mod si5324;
|
||||
#[cfg(has_si549)]
|
||||
pub mod si549;
|
||||
use alloc::{collections::BTreeMap, string::String};
|
||||
use core::{cmp, str};
|
||||
|
||||
use byteorder::NativeEndian;
|
||||
use io::{Cursor, ProtoRead};
|
||||
use libcortex_a9::once_lock::OnceLock;
|
||||
use log::warn;
|
||||
|
||||
#[cfg(has_cxp_grabber)]
|
||||
pub mod cxp_camera_setup;
|
||||
#[cfg(has_cxp_grabber)]
|
||||
@ -57,6 +62,25 @@ pub mod cxp_packet;
|
||||
#[cfg(has_cxp_grabber)]
|
||||
pub mod cxp_phys;
|
||||
|
||||
#[allow(static_mut_refs)]
|
||||
pub mod i2c {
|
||||
use core::mem::MaybeUninit;
|
||||
|
||||
use libboard_zynq::i2c::I2c;
|
||||
|
||||
static mut I2C_BUS: MaybeUninit<I2c> = MaybeUninit::uninit();
|
||||
|
||||
pub fn init() {
|
||||
let mut i2c = I2c::i2c0();
|
||||
i2c.init().expect("I2C bus initialization failed");
|
||||
unsafe { I2C_BUS.write(i2c) };
|
||||
}
|
||||
|
||||
pub fn get_bus() -> &'static mut I2c {
|
||||
unsafe { I2C_BUS.assume_init_mut() }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn identifier_read(buf: &mut [u8]) -> &str {
|
||||
unsafe {
|
||||
pl::csr::identifier::address_write(0);
|
||||
@ -69,3 +93,50 @@ pub fn identifier_read(buf: &mut [u8]) -> &str {
|
||||
str::from_utf8_unchecked(&buf[..len as usize])
|
||||
}
|
||||
}
|
||||
|
||||
static RTIO_DEVICE_MAP: OnceLock<BTreeMap<u32, String>> = OnceLock::new();
|
||||
|
||||
fn read_device_map() -> BTreeMap<u32, String> {
|
||||
let mut device_map: BTreeMap<u32, String> = BTreeMap::new();
|
||||
let _ = libconfig::read("device_map")
|
||||
.and_then(|raw_bytes| {
|
||||
let mut bytes_cr = Cursor::new(raw_bytes);
|
||||
let size = bytes_cr.read_u32::<NativeEndian>().unwrap();
|
||||
for _ in 0..size {
|
||||
let channel = bytes_cr.read_u32::<NativeEndian>().unwrap();
|
||||
let device_name = bytes_cr.read_string::<NativeEndian>().unwrap();
|
||||
if let Some(old_entry) = device_map.insert(channel, device_name.clone()) {
|
||||
warn!(
|
||||
"conflicting device map entries for RTIO channel {}: '{}' and '{}'",
|
||||
channel, old_entry, device_name
|
||||
);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
.or_else(|err| {
|
||||
warn!(
|
||||
"error reading device map ({}), device names will not be available in RTIO error messages",
|
||||
err
|
||||
);
|
||||
Err(err)
|
||||
});
|
||||
device_map
|
||||
}
|
||||
|
||||
pub fn resolve_channel_name(channel: u32) -> String {
|
||||
match RTIO_DEVICE_MAP
|
||||
.get()
|
||||
.expect("cannot get device map before it is set up")
|
||||
.get(&channel)
|
||||
{
|
||||
Some(val) => val.clone(),
|
||||
None => String::from("unknown"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn setup_device_map() {
|
||||
RTIO_DEVICE_MAP
|
||||
.set(read_device_map())
|
||||
.expect("device map can only be initialized once");
|
||||
}
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
use core::{cell::Cell, fmt::Write, mem::MaybeUninit};
|
||||
use core::{cell::Cell, fmt::Write};
|
||||
|
||||
use libboard_zynq::{println, timer};
|
||||
use libcortex_a9::mutex::{Mutex, MutexGuard};
|
||||
use libboard_zynq::{println, stdio, timer};
|
||||
use libcortex_a9::{mutex::{Mutex, MutexGuard},
|
||||
once_lock::OnceLock};
|
||||
use log::{LevelFilter, Log};
|
||||
use log_buffer::LogBuffer;
|
||||
|
||||
@ -12,8 +13,8 @@ pub struct LogBufferRef<'a> {
|
||||
|
||||
impl<'a> LogBufferRef<'a> {
|
||||
fn new(buffer: MutexGuard<'a, LogBuffer<&'static mut [u8]>>) -> LogBufferRef<'a> {
|
||||
let old_log_level = log::max_level();
|
||||
log::set_max_level(LevelFilter::Off);
|
||||
let old_log_level = BufferLogger::get_logger().buffer_log_level();
|
||||
BufferLogger::get_logger().set_buffer_log_level(LevelFilter::Off);
|
||||
LogBufferRef { buffer, old_log_level }
|
||||
}
|
||||
|
||||
@ -32,7 +33,7 @@ impl<'a> LogBufferRef<'a> {
|
||||
|
||||
impl<'a> Drop for LogBufferRef<'a> {
|
||||
fn drop(&mut self) {
|
||||
log::set_max_level(self.old_log_level)
|
||||
BufferLogger::get_logger().set_buffer_log_level(self.old_log_level);
|
||||
}
|
||||
}
|
||||
|
||||
@ -42,28 +43,24 @@ pub struct BufferLogger {
|
||||
buffer_filter: Cell<LevelFilter>,
|
||||
}
|
||||
|
||||
static mut LOGGER: MaybeUninit<BufferLogger> = MaybeUninit::uninit();
|
||||
static LOGGER: OnceLock<BufferLogger> = OnceLock::new();
|
||||
|
||||
impl BufferLogger {
|
||||
pub fn new(buffer: &'static mut [u8]) -> BufferLogger {
|
||||
BufferLogger {
|
||||
buffer: Mutex::new(LogBuffer::new(buffer)),
|
||||
uart_filter: Cell::new(LevelFilter::Info),
|
||||
buffer_filter: Cell::new(LevelFilter::Trace),
|
||||
buffer_filter: Cell::new(LevelFilter::Info),
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(static_mut_refs)]
|
||||
pub fn register(self) {
|
||||
unsafe {
|
||||
LOGGER.write(self);
|
||||
log::set_logger(LOGGER.assume_init_ref()).expect("global logger can only be initialized once");
|
||||
}
|
||||
LOGGER.set(self).expect("LOGGER can only be initialized once");
|
||||
log::set_logger(LOGGER.get().unwrap()).expect("global logger can only be initialized once");
|
||||
}
|
||||
|
||||
#[allow(static_mut_refs)]
|
||||
pub fn get_logger() -> &'static mut BufferLogger {
|
||||
unsafe { LOGGER.assume_init_mut() }
|
||||
pub fn get_logger() -> &'static BufferLogger {
|
||||
LOGGER.get().expect("cannot get logger before it is initialized")
|
||||
}
|
||||
|
||||
pub fn buffer<'a>(&'a self) -> Option<LogBufferRef<'a>> {
|
||||
@ -75,7 +72,8 @@ impl BufferLogger {
|
||||
}
|
||||
|
||||
pub fn set_uart_log_level(&self, max_level: LevelFilter) {
|
||||
self.uart_filter.set(max_level)
|
||||
self.uart_filter.set(max_level);
|
||||
self.update_global_log_level()
|
||||
}
|
||||
|
||||
pub fn buffer_log_level(&self) -> LevelFilter {
|
||||
@ -84,7 +82,16 @@ impl BufferLogger {
|
||||
|
||||
/// this should be reserved for mgmt module
|
||||
pub fn set_buffer_log_level(&self, max_level: LevelFilter) {
|
||||
self.buffer_filter.set(max_level)
|
||||
self.buffer_filter.set(max_level);
|
||||
self.update_global_log_level()
|
||||
}
|
||||
|
||||
pub fn update_global_log_level(&self) {
|
||||
let uart_level = self.uart_filter.get();
|
||||
let buffer_level = self.buffer_filter.get();
|
||||
let global_level = core::cmp::max(uart_level, buffer_level);
|
||||
|
||||
log::set_max_level(global_level);
|
||||
}
|
||||
}
|
||||
|
||||
@ -129,5 +136,8 @@ impl Log for BufferLogger {
|
||||
}
|
||||
}
|
||||
|
||||
fn flush(&self) {}
|
||||
fn flush(&self) {
|
||||
let uart = stdio::get_uart();
|
||||
while !uart.tx_idle() {}
|
||||
}
|
||||
}
|
||||
|
||||
@ -81,15 +81,15 @@ mod i2c {
|
||||
sda_oe(dcxo, false);
|
||||
|
||||
// Check the I2C bus is ready
|
||||
half_period(timer);
|
||||
half_period(timer);
|
||||
half_period();
|
||||
half_period();
|
||||
if !sda_i(dcxo) {
|
||||
// Try toggling SCL a few times
|
||||
for _bit in 0..8 {
|
||||
scl_o(dcxo, false);
|
||||
half_period(timer);
|
||||
half_period();
|
||||
scl_o(dcxo, true);
|
||||
half_period(timer);
|
||||
half_period();
|
||||
}
|
||||
}
|
||||
|
||||
@ -102,21 +102,21 @@ mod i2c {
|
||||
pub fn start(dcxo: DCXO) {
|
||||
// Set SCL high then SDA low
|
||||
scl_o(dcxo, true);
|
||||
half_period(timer);
|
||||
half_period();
|
||||
sda_oe(dcxo, true);
|
||||
half_period(timer);
|
||||
half_period();
|
||||
}
|
||||
|
||||
pub fn stop(dcxo: DCXO) {
|
||||
// First, make sure SCL is low, so that the target releases the SDA line
|
||||
scl_o(dcxo, false);
|
||||
half_period(timer);
|
||||
half_period();
|
||||
// Set SCL high then SDA high
|
||||
sda_oe(dcxo, true);
|
||||
scl_o(dcxo, true);
|
||||
half_period(timer);
|
||||
half_period();
|
||||
sda_oe(dcxo, false);
|
||||
half_period(timer);
|
||||
half_period();
|
||||
}
|
||||
|
||||
pub fn write(dcxo: DCXO, data: u8) -> bool {
|
||||
@ -125,19 +125,19 @@ mod i2c {
|
||||
// Set SCL low and set our bit on SDA
|
||||
scl_o(dcxo, false);
|
||||
sda_oe(dcxo, data & (1 << bit) == 0);
|
||||
half_period(timer);
|
||||
half_period();
|
||||
// Set SCL high ; data is shifted on the rising edge of SCL
|
||||
scl_o(dcxo, true);
|
||||
half_period(timer);
|
||||
half_period();
|
||||
}
|
||||
// Check ack
|
||||
// Set SCL low, then release SDA so that the I2C target can respond
|
||||
scl_o(dcxo, false);
|
||||
half_period(timer);
|
||||
half_period();
|
||||
sda_oe(dcxo, false);
|
||||
// Set SCL high and check for ack
|
||||
scl_o(dcxo, true);
|
||||
half_period(timer);
|
||||
half_period();
|
||||
// returns true if acked (I2C target pulled SDA low)
|
||||
!sda_i(dcxo)
|
||||
}
|
||||
@ -146,7 +146,7 @@ mod i2c {
|
||||
// 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
|
||||
half_period(); // make sure SCL has settled low
|
||||
sda_oe(dcxo, false);
|
||||
|
||||
let mut data: u8 = 0;
|
||||
@ -154,10 +154,10 @@ mod i2c {
|
||||
// MSB first
|
||||
for bit in (0..8).rev() {
|
||||
scl_o(dcxo, false);
|
||||
half_period(timer);
|
||||
half_period();
|
||||
// Set SCL high and shift data
|
||||
scl_o(dcxo, true);
|
||||
half_period(timer);
|
||||
half_period();
|
||||
if sda_i(dcxo) {
|
||||
data |= 1 << bit
|
||||
}
|
||||
@ -168,78 +168,78 @@ mod i2c {
|
||||
if ack {
|
||||
sda_oe(dcxo, true)
|
||||
}
|
||||
half_period(timer);
|
||||
half_period();
|
||||
// then set SCL high
|
||||
scl_o(dcxo, true);
|
||||
half_period(timer);
|
||||
half_period();
|
||||
|
||||
data
|
||||
}
|
||||
}
|
||||
|
||||
fn write(dcxo: i2c::DCXO, reg: u8, val: u8) -> Result<(), &'static str> {
|
||||
i2c::start(dcxo, timer);
|
||||
if !i2c::write(dcxo, ADDRESS << 1, timer) {
|
||||
i2c::start(dcxo);
|
||||
if !i2c::write(dcxo, ADDRESS << 1) {
|
||||
return Err("Si549 failed to ack write address");
|
||||
}
|
||||
if !i2c::write(dcxo, reg, timer) {
|
||||
if !i2c::write(dcxo, reg) {
|
||||
return Err("Si549 failed to ack register");
|
||||
}
|
||||
if !i2c::write(dcxo, val, timer) {
|
||||
if !i2c::write(dcxo, val) {
|
||||
return Err("Si549 failed to ack value");
|
||||
}
|
||||
i2c::stop(dcxo, timer);
|
||||
i2c::stop(dcxo);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn read(dcxo: i2c::DCXO, reg: u8) -> Result<u8, &'static str> {
|
||||
i2c::start(dcxo, timer);
|
||||
if !i2c::write(dcxo, ADDRESS << 1, timer) {
|
||||
i2c::start(dcxo);
|
||||
if !i2c::write(dcxo, ADDRESS << 1) {
|
||||
return Err("Si549 failed to ack write address");
|
||||
}
|
||||
if !i2c::write(dcxo, reg, timer) {
|
||||
if !i2c::write(dcxo, reg) {
|
||||
return Err("Si549 failed to ack register");
|
||||
}
|
||||
i2c::stop(dcxo, timer);
|
||||
i2c::stop(dcxo);
|
||||
|
||||
i2c::start(dcxo, timer);
|
||||
if !i2c::write(dcxo, (ADDRESS << 1) | 1, timer) {
|
||||
i2c::start(dcxo);
|
||||
if !i2c::write(dcxo, (ADDRESS << 1) | 1) {
|
||||
return Err("Si549 failed to ack read address");
|
||||
}
|
||||
let val = i2c::read(dcxo, false, timer);
|
||||
i2c::stop(dcxo, timer);
|
||||
let val = i2c::read(dcxo, false);
|
||||
i2c::stop(dcxo);
|
||||
Ok(val)
|
||||
}
|
||||
|
||||
fn setup(dcxo: i2c::DCXO, config: &DividerConfig) -> Result<(), &'static str> {
|
||||
i2c::init(dcxo, timer)?;
|
||||
i2c::init(dcxo)?;
|
||||
|
||||
write(dcxo, 255, 0x00, timer)?; // PAGE
|
||||
write(dcxo, 69, 0x00, timer)?; // Disable FCAL override.
|
||||
write(dcxo, 17, 0x00, timer)?; // Synchronously disable output
|
||||
write(dcxo, 255, 0x00)?; // PAGE
|
||||
write(dcxo, 69, 0x00)?; // Disable FCAL override.
|
||||
write(dcxo, 17, 0x00)?; // 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)?;
|
||||
write(dcxo, 23, test_value)?;
|
||||
let readback = read(dcxo, 23)?;
|
||||
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, 23, config.hsdiv as u8)?;
|
||||
write(dcxo, 24, (config.hsdiv >> 8) as u8 | (config.lsdiv << 4))?;
|
||||
write(dcxo, 26, config.fbdiv as u8)?;
|
||||
write(dcxo, 27, (config.fbdiv >> 8) as u8)?;
|
||||
write(dcxo, 28, (config.fbdiv >> 16) as u8)?;
|
||||
write(dcxo, 29, (config.fbdiv >> 24) as u8)?;
|
||||
write(dcxo, 30, (config.fbdiv >> 32) as u8)?;
|
||||
write(dcxo, 31, (config.fbdiv >> 40) as u8)?;
|
||||
|
||||
write(dcxo, 7, 0x08, timer)?; // Start FCAL
|
||||
timer.delay_us(30_000); // Internal FCAL VCO calibration
|
||||
write(dcxo, 17, 0x01, timer)?; // Synchronously enable output
|
||||
write(dcxo, 7, 0x08)?; // Start FCAL
|
||||
timer::delay_us(30_000); // Internal FCAL VCO calibration
|
||||
write(dcxo, 17, 0x01)?; // Synchronously enable output
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -11,7 +11,6 @@ build_zynq = { path = "../libbuild_zynq" }
|
||||
[dependencies]
|
||||
cslice = "0.3"
|
||||
log = "0.4"
|
||||
nb = "0.1"
|
||||
core_io = { git = "https://git.m-labs.hk/M-Labs/rs-core_io.git", rev = "e9d3edf027", features = ["collections"] }
|
||||
byteorder = { version = "1.3", default-features = false }
|
||||
void = { version = "1", default-features = false }
|
||||
|
||||
@ -254,6 +254,18 @@ pub fn resolve(required: &[u8]) -> Option<u32> {
|
||||
fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32;
|
||||
}
|
||||
),
|
||||
api!(
|
||||
bcmp,
|
||||
extern "C" {
|
||||
fn bcmp(s1: *const u8, s2: *const u8, n: usize) -> i32;
|
||||
}
|
||||
),
|
||||
api!(
|
||||
strlen,
|
||||
extern "C" {
|
||||
fn strlen(s: *const core::ffi::c_char) -> usize;
|
||||
}
|
||||
),
|
||||
|
||||
// exceptions
|
||||
api!(_Unwind_Resume = unwind::_Unwind_Resume),
|
||||
@ -290,6 +302,12 @@ pub fn resolve(required: &[u8]) -> Option<u32> {
|
||||
api_libm_f64f64!(exp2),
|
||||
api_libm_f64f64!(exp10),
|
||||
api_libm_f64f64!(expm1),
|
||||
{
|
||||
extern "C" fn ldexp(arg: f64, exp: i32) -> f64 {
|
||||
libm::ldexp(arg, exp)
|
||||
}
|
||||
api!(ldexp = ldexp)
|
||||
},
|
||||
api_libm_f64f64!(fabs),
|
||||
api_libm_f64f64!(floor),
|
||||
{
|
||||
|
||||
@ -14,7 +14,7 @@ use log::{debug, error, info};
|
||||
|
||||
use super::{CHANNEL_0TO1, CHANNEL_1TO0, CHANNEL_SEM, INIT_LOCK, KERNEL_CHANNEL_0TO1, KERNEL_CHANNEL_1TO0,
|
||||
KERNEL_IMAGE, Message, api::resolve, dma, rpc::rpc_send_async};
|
||||
use crate::{eh_artiq, get_async_errors};
|
||||
use crate::eh_artiq;
|
||||
|
||||
// linker symbols
|
||||
extern "C" {
|
||||
@ -183,8 +183,7 @@ pub extern "C" fn main_core1() {
|
||||
}
|
||||
}
|
||||
info!("kernel finished");
|
||||
let async_errors = unsafe { get_async_errors() };
|
||||
core1_tx.send(Message::KernelFinished(async_errors));
|
||||
core1_tx.send(Message::KernelFinished);
|
||||
}
|
||||
_ => error!("Core1 received unexpected message: {:?}", message),
|
||||
}
|
||||
@ -199,8 +198,7 @@ pub fn terminate(
|
||||
) -> ! {
|
||||
{
|
||||
let core1_tx = unsafe { KERNEL_CHANNEL_1TO0.as_mut().unwrap() };
|
||||
let errors = unsafe { get_async_errors() };
|
||||
core1_tx.send(Message::KernelException(exceptions, stack_pointers, backtrace, errors));
|
||||
core1_tx.send(Message::KernelException(exceptions, stack_pointers, backtrace));
|
||||
}
|
||||
loop {}
|
||||
}
|
||||
|
||||
@ -1,192 +1,96 @@
|
||||
use core::mem::MaybeUninit;
|
||||
|
||||
use libboard_zynq::i2c::{Error, I2c};
|
||||
|
||||
#[cfg(has_drtio)]
|
||||
use super::{KERNEL_CHANNEL_0TO1, KERNEL_CHANNEL_1TO0, Message};
|
||||
use crate::artiq_raise;
|
||||
|
||||
static mut I2C_BUS: MaybeUninit<I2c> = MaybeUninit::uninit();
|
||||
|
||||
pub extern "C" fn start(busno: i32) {
|
||||
let _destination = (busno >> 16) as u8;
|
||||
#[cfg(has_drtio)]
|
||||
if _destination != 0 {
|
||||
let reply = unsafe {
|
||||
KERNEL_CHANNEL_1TO0
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.send(Message::I2cStartRequest(busno as u32));
|
||||
KERNEL_CHANNEL_0TO1.as_mut().unwrap().recv()
|
||||
};
|
||||
match reply {
|
||||
Message::I2cBasicReply(true) => return,
|
||||
Message::I2cBasicReply(false) => artiq_raise!("I2CError", "I2C remote start fail"),
|
||||
msg => panic!("Expected I2cBasicReply for I2cStartRequest, got: {:?}", msg),
|
||||
}
|
||||
}
|
||||
if busno > 0 {
|
||||
artiq_raise!("I2CError", "I2C bus could not be accessed");
|
||||
}
|
||||
if get_bus().start().is_err() {
|
||||
artiq_raise!("I2CError", "I2C start failed");
|
||||
let reply = unsafe {
|
||||
KERNEL_CHANNEL_1TO0
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.send(Message::I2cStartRequest(busno as u32));
|
||||
KERNEL_CHANNEL_0TO1.as_mut().unwrap().recv()
|
||||
};
|
||||
match reply {
|
||||
Message::I2cBasicReply(true) => (),
|
||||
Message::I2cBasicReply(false) => artiq_raise!("I2CError", "I2C start fail"),
|
||||
msg => panic!("Expected I2cBasicReply for I2cStartRequest, got: {:?}", msg),
|
||||
}
|
||||
}
|
||||
|
||||
pub extern "C" fn restart(busno: i32) {
|
||||
let _destination = (busno >> 16) as u8;
|
||||
#[cfg(has_drtio)]
|
||||
if _destination != 0 {
|
||||
let reply = unsafe {
|
||||
KERNEL_CHANNEL_1TO0
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.send(Message::I2cRestartRequest(busno as u32));
|
||||
KERNEL_CHANNEL_0TO1.as_mut().unwrap().recv()
|
||||
};
|
||||
match reply {
|
||||
Message::I2cBasicReply(true) => return,
|
||||
Message::I2cBasicReply(false) => artiq_raise!("I2CError", "I2C remote restart fail"),
|
||||
msg => panic!("Expected I2cBasicReply for I2cRetartRequest, got: {:?}", msg),
|
||||
}
|
||||
}
|
||||
if busno > 0 {
|
||||
artiq_raise!("I2CError", "I2C bus could not be accessed");
|
||||
}
|
||||
if get_bus().restart().is_err() {
|
||||
artiq_raise!("I2CError", "I2C restart failed");
|
||||
let reply = unsafe {
|
||||
KERNEL_CHANNEL_1TO0
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.send(Message::I2cRestartRequest(busno as u32));
|
||||
KERNEL_CHANNEL_0TO1.as_mut().unwrap().recv()
|
||||
};
|
||||
match reply {
|
||||
Message::I2cBasicReply(true) => (),
|
||||
Message::I2cBasicReply(false) => artiq_raise!("I2CError", "I2C restart fail"),
|
||||
msg => panic!("Expected I2cBasicReply for I2cRestartRequest, got: {:?}", msg),
|
||||
}
|
||||
}
|
||||
|
||||
pub extern "C" fn stop(busno: i32) {
|
||||
let _destination = (busno >> 16) as u8;
|
||||
#[cfg(has_drtio)]
|
||||
if _destination != 0 {
|
||||
// remote
|
||||
let reply = unsafe {
|
||||
KERNEL_CHANNEL_1TO0
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.send(Message::I2cStopRequest(busno as u32));
|
||||
KERNEL_CHANNEL_0TO1.as_mut().unwrap().recv()
|
||||
};
|
||||
match reply {
|
||||
Message::I2cBasicReply(true) => return,
|
||||
Message::I2cBasicReply(false) => artiq_raise!("I2CError", "I2C remote stop fail"),
|
||||
msg => panic!("Expected I2cBasicReply for I2cStopRequest, got: {:?}", msg),
|
||||
}
|
||||
}
|
||||
if busno > 0 {
|
||||
artiq_raise!("I2CError", "I2C bus could not be accessed");
|
||||
}
|
||||
if get_bus().stop().is_err() {
|
||||
artiq_raise!("I2CError", "I2C stop failed");
|
||||
let reply = unsafe {
|
||||
KERNEL_CHANNEL_1TO0
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.send(Message::I2cStopRequest(busno as u32));
|
||||
KERNEL_CHANNEL_0TO1.as_mut().unwrap().recv()
|
||||
};
|
||||
match reply {
|
||||
Message::I2cBasicReply(true) => (),
|
||||
Message::I2cBasicReply(false) => artiq_raise!("I2CError", "I2C stop fail"),
|
||||
msg => panic!("Expected I2cBasicReply for I2cStopRequest, got: {:?}", msg),
|
||||
}
|
||||
}
|
||||
|
||||
pub extern "C" fn write(busno: i32, data: i32) -> bool {
|
||||
let _destination = (busno >> 16) as u8;
|
||||
#[cfg(has_drtio)]
|
||||
if _destination != 0 {
|
||||
// remote
|
||||
let reply = unsafe {
|
||||
KERNEL_CHANNEL_1TO0.as_mut().unwrap().send(Message::I2cWriteRequest {
|
||||
busno: busno as u32,
|
||||
data: data as u8,
|
||||
});
|
||||
KERNEL_CHANNEL_0TO1.as_mut().unwrap().recv()
|
||||
};
|
||||
match reply {
|
||||
Message::I2cWriteReply { succeeded: true, ack } => return ack,
|
||||
Message::I2cWriteReply { succeeded: false, .. } => artiq_raise!("I2CError", "I2C remote write fail"),
|
||||
msg => panic!("Expected I2cWriteReply for I2cWriteRequest, got: {:?}", msg),
|
||||
}
|
||||
}
|
||||
if busno > 0 {
|
||||
artiq_raise!("I2CError", "I2C bus could not be accessed");
|
||||
}
|
||||
match get_bus().write(data as u8) {
|
||||
Ok(()) => true,
|
||||
Err(Error::Nack) => false,
|
||||
Err(_) => artiq_raise!("I2CError", "I2C write failed"),
|
||||
let reply = unsafe {
|
||||
KERNEL_CHANNEL_1TO0.as_mut().unwrap().send(Message::I2cWriteRequest {
|
||||
busno: busno as u32,
|
||||
data: data as u8,
|
||||
});
|
||||
KERNEL_CHANNEL_0TO1.as_mut().unwrap().recv()
|
||||
};
|
||||
match reply {
|
||||
Message::I2cWriteReply { succeeded: true, ack } => ack,
|
||||
Message::I2cWriteReply { succeeded: false, .. } => artiq_raise!("I2CError", "I2C write fail"),
|
||||
msg => panic!("Expected I2cWriteReply for I2cWriteRequest, got: {:?}", msg),
|
||||
}
|
||||
}
|
||||
|
||||
pub extern "C" fn read(busno: i32, ack: bool) -> i32 {
|
||||
let _destination = (busno >> 16) as u8;
|
||||
#[cfg(has_drtio)]
|
||||
if _destination != 0 {
|
||||
let reply = unsafe {
|
||||
KERNEL_CHANNEL_1TO0.as_mut().unwrap().send(Message::I2cReadRequest {
|
||||
busno: busno as u32,
|
||||
ack,
|
||||
});
|
||||
KERNEL_CHANNEL_0TO1.as_mut().unwrap().recv()
|
||||
};
|
||||
match reply {
|
||||
Message::I2cReadReply { succeeded: true, data } => return data as i32,
|
||||
Message::I2cReadReply { succeeded: false, .. } => artiq_raise!("I2CError", "I2C remote read fail"),
|
||||
msg => panic!("Expected I2cReadReply for I2cReadRequest, got: {:?}", msg),
|
||||
}
|
||||
}
|
||||
if busno > 0 {
|
||||
artiq_raise!("I2CError", "I2C bus could not be accessed");
|
||||
}
|
||||
match get_bus().read(ack) {
|
||||
Ok(r) => r as i32,
|
||||
Err(_) => artiq_raise!("I2CError", "I2C read failed"),
|
||||
let reply = unsafe {
|
||||
KERNEL_CHANNEL_1TO0.as_mut().unwrap().send(Message::I2cReadRequest {
|
||||
busno: busno as u32,
|
||||
ack,
|
||||
});
|
||||
KERNEL_CHANNEL_0TO1.as_mut().unwrap().recv()
|
||||
};
|
||||
match reply {
|
||||
Message::I2cReadReply { succeeded: true, data } => data as i32,
|
||||
Message::I2cReadReply { succeeded: false, .. } => artiq_raise!("I2CError", "I2C read fail"),
|
||||
msg => panic!("Expected I2cReadReply for I2cReadRequest, got: {:?}", msg),
|
||||
}
|
||||
}
|
||||
|
||||
pub extern "C" fn switch_select(busno: i32, address: i32, mask: i32) {
|
||||
let _destination = (busno >> 16) as u8;
|
||||
#[cfg(has_drtio)]
|
||||
if _destination != 0 {
|
||||
// remote
|
||||
let reply = unsafe {
|
||||
KERNEL_CHANNEL_1TO0
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.send(Message::I2cSwitchSelectRequest {
|
||||
busno: busno as u32,
|
||||
address: address as u8,
|
||||
mask: mask as u8,
|
||||
});
|
||||
KERNEL_CHANNEL_0TO1.as_mut().unwrap().recv()
|
||||
};
|
||||
match reply {
|
||||
Message::I2cBasicReply(true) => return,
|
||||
Message::I2cBasicReply(false) => artiq_raise!("I2CError", "I2C remote start fail"),
|
||||
msg => panic!("Expected I2cBasicReply for I2cSwitchSelectRequest, got: {:?}", msg),
|
||||
}
|
||||
}
|
||||
if busno > 0 {
|
||||
artiq_raise!("I2CError", "I2C bus could not be accessed");
|
||||
}
|
||||
let ch = match mask {
|
||||
//decode from mainline, PCA9548-centric API
|
||||
0x00 => None,
|
||||
0x01 => Some(0),
|
||||
0x02 => Some(1),
|
||||
0x04 => Some(2),
|
||||
0x08 => Some(3),
|
||||
0x10 => Some(4),
|
||||
0x20 => Some(5),
|
||||
0x40 => Some(6),
|
||||
0x80 => Some(7),
|
||||
_ => artiq_raise!("I2CError", "switch select supports only one channel"),
|
||||
let reply = unsafe {
|
||||
KERNEL_CHANNEL_1TO0
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.send(Message::I2cSwitchSelectRequest {
|
||||
busno: busno as u32,
|
||||
address: address as u8,
|
||||
mask: mask as u8,
|
||||
});
|
||||
KERNEL_CHANNEL_0TO1.as_mut().unwrap().recv()
|
||||
};
|
||||
if get_bus().pca954x_select(address as u8, ch).is_err() {
|
||||
artiq_raise!("I2CError", "switch select failed");
|
||||
match reply {
|
||||
Message::I2cBasicReply(true) => (),
|
||||
Message::I2cBasicReply(false) => artiq_raise!("I2CError", "I2C switch select fail"),
|
||||
msg => panic!("Expected I2cBasicReply for I2cSwitchSelectRequest, got: {:?}", msg),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn init() {
|
||||
let mut i2c = I2c::i2c0();
|
||||
i2c.init().expect("I2C bus initialization failed");
|
||||
unsafe { I2C_BUS.write(i2c) };
|
||||
}
|
||||
|
||||
pub fn get_bus() -> &'static mut I2c {
|
||||
unsafe { I2C_BUS.assume_init_mut() }
|
||||
}
|
||||
|
||||
@ -45,12 +45,11 @@ pub enum Message {
|
||||
LoadCompleted,
|
||||
LoadFailed,
|
||||
StartRequest,
|
||||
KernelFinished(u8),
|
||||
KernelFinished,
|
||||
KernelException(
|
||||
&'static [Option<eh_artiq::Exception<'static>>],
|
||||
&'static [eh_artiq::StackPointerBacktrace],
|
||||
&'static [(usize, usize)],
|
||||
u8,
|
||||
),
|
||||
|
||||
#[cfg(has_drtio)]
|
||||
@ -93,35 +92,26 @@ pub enum Message {
|
||||
#[cfg(has_drtio)]
|
||||
UpDestinationsReply(bool),
|
||||
|
||||
#[cfg(has_drtio)]
|
||||
I2cStartRequest(u32),
|
||||
#[cfg(has_drtio)]
|
||||
I2cRestartRequest(u32),
|
||||
#[cfg(has_drtio)]
|
||||
I2cStopRequest(u32),
|
||||
#[cfg(has_drtio)]
|
||||
I2cWriteRequest {
|
||||
busno: u32,
|
||||
data: u8,
|
||||
},
|
||||
#[cfg(has_drtio)]
|
||||
I2cWriteReply {
|
||||
succeeded: bool,
|
||||
ack: bool,
|
||||
},
|
||||
#[cfg(has_drtio)]
|
||||
I2cReadRequest {
|
||||
busno: u32,
|
||||
ack: bool,
|
||||
},
|
||||
#[cfg(has_drtio)]
|
||||
I2cReadReply {
|
||||
succeeded: bool,
|
||||
data: u8,
|
||||
},
|
||||
#[cfg(has_drtio)]
|
||||
I2cBasicReply(bool),
|
||||
#[cfg(has_drtio)]
|
||||
I2cSwitchSelectRequest {
|
||||
busno: u32,
|
||||
address: u8,
|
||||
|
||||
@ -6,7 +6,7 @@ use vcell::VolatileCell;
|
||||
|
||||
#[cfg(has_drtio)]
|
||||
use super::{KERNEL_CHANNEL_0TO1, KERNEL_CHANNEL_1TO0, Message};
|
||||
use crate::{artiq_raise, pl::csr, resolve_channel_name, rtio_core};
|
||||
use crate::{artiq_raise, pl::csr, rtio_core};
|
||||
|
||||
pub const RTIO_O_STATUS_WAIT: i32 = 1;
|
||||
pub const RTIO_O_STATUS_UNDERFLOW: i32 = 2;
|
||||
@ -17,6 +17,9 @@ pub const RTIO_I_STATUS_OVERFLOW: i32 = 2;
|
||||
pub const RTIO_I_STATUS_WAIT_STATUS: i32 = 4; // TODO
|
||||
pub const RTIO_I_STATUS_DESTINATION_UNREACHABLE: i32 = 8;
|
||||
|
||||
const RTIO_CMD_OUTPUT: i8 = 0;
|
||||
const RTIO_CMD_INPUT: i8 = 1;
|
||||
|
||||
#[repr(C)]
|
||||
pub struct TimestampedData {
|
||||
timestamp: i64,
|
||||
@ -25,6 +28,7 @@ pub struct TimestampedData {
|
||||
|
||||
#[repr(C, align(64))]
|
||||
struct Transaction {
|
||||
/* DOUT */
|
||||
request_cmd: i8,
|
||||
data_width: i8,
|
||||
padding0: [i8; 2],
|
||||
@ -32,6 +36,7 @@ struct Transaction {
|
||||
request_timestamp: i64,
|
||||
request_data: [i32; 16],
|
||||
padding1: [i64; 2],
|
||||
/* DIN */
|
||||
reply_status: VolatileCell<i32>,
|
||||
reply_data: VolatileCell<i32>,
|
||||
reply_timestamp: VolatileCell<i64>,
|
||||
@ -39,11 +44,13 @@ struct Transaction {
|
||||
}
|
||||
|
||||
static mut TRANSACTION_BUFFER: Transaction = Transaction {
|
||||
/* DOUT */
|
||||
request_cmd: 0,
|
||||
data_width: 0,
|
||||
request_target: 0,
|
||||
request_timestamp: 0,
|
||||
request_data: [0; 16],
|
||||
/* DIN */
|
||||
reply_status: VolatileCell::new(0),
|
||||
reply_data: VolatileCell::new(0),
|
||||
reply_timestamp: VolatileCell::new(0),
|
||||
@ -92,18 +99,12 @@ pub extern "C" fn delay_mu(dt: i64) {
|
||||
#[inline(never)]
|
||||
unsafe fn process_exceptional_status(channel: i32, status: i32) {
|
||||
let timestamp = now_mu();
|
||||
if status & RTIO_O_STATUS_WAIT != 0 {
|
||||
// FIXME: this is a kludge and probably buggy (kernel interrupted?)
|
||||
while csr::rtio::o_status_read() as i32 & RTIO_O_STATUS_WAIT != 0 {}
|
||||
}
|
||||
// The gateware should handle waiting
|
||||
assert!(status & RTIO_O_STATUS_WAIT == 0);
|
||||
if status & RTIO_O_STATUS_UNDERFLOW != 0 {
|
||||
artiq_raise!(
|
||||
"RTIOUnderflow",
|
||||
format!(
|
||||
"RTIO underflow at {{1}} mu, channel 0x{:04x}:{}, slack {{2}} mu",
|
||||
channel,
|
||||
resolve_channel_name(channel as u32)
|
||||
),
|
||||
"RTIO underflow at {1} mu, channel {rtio_channel_info:0}, slack {2} mu",
|
||||
channel as i64,
|
||||
timestamp,
|
||||
timestamp - get_counter()
|
||||
@ -112,40 +113,40 @@ unsafe fn process_exceptional_status(channel: i32, status: i32) {
|
||||
if status & RTIO_O_STATUS_DESTINATION_UNREACHABLE != 0 {
|
||||
artiq_raise!(
|
||||
"RTIODestinationUnreachable",
|
||||
format!(
|
||||
"RTIO destination unreachable, output, at {{0}} mu, channel 0x{:04x}:{}",
|
||||
channel,
|
||||
resolve_channel_name(channel as u32)
|
||||
),
|
||||
timestamp,
|
||||
"RTIO destination unreachable, output, at {1} mu, channel {rtio_channel_info:0}",
|
||||
channel as i64,
|
||||
timestamp,
|
||||
0
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn await_reply_status() -> i32 {
|
||||
unsafe {
|
||||
// dmb and send event (commit the event to gateware)
|
||||
fence(Ordering::SeqCst);
|
||||
asm::sev();
|
||||
// actually await status
|
||||
loop {
|
||||
let status = TRANSACTION_BUFFER.reply_status.get();
|
||||
if status != 0 {
|
||||
// Clear status so we can observe response on the next call
|
||||
TRANSACTION_BUFFER.reply_status.set(0);
|
||||
return status;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub extern "C" fn output(target: i32, data: i32) {
|
||||
unsafe {
|
||||
// Clear status so we can observe response
|
||||
TRANSACTION_BUFFER.reply_status.set(0);
|
||||
|
||||
TRANSACTION_BUFFER.request_cmd = 0;
|
||||
TRANSACTION_BUFFER.request_cmd = RTIO_CMD_OUTPUT;
|
||||
TRANSACTION_BUFFER.data_width = 1;
|
||||
TRANSACTION_BUFFER.request_target = target;
|
||||
TRANSACTION_BUFFER.request_timestamp = NOW;
|
||||
TRANSACTION_BUFFER.request_data[0] = data;
|
||||
|
||||
fence(Ordering::SeqCst);
|
||||
asm::sev();
|
||||
let mut status;
|
||||
loop {
|
||||
status = TRANSACTION_BUFFER.reply_status.get();
|
||||
if status != 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let status = status & !0x10000;
|
||||
let status = await_reply_status() & !(1 << 16);
|
||||
if status != 0 {
|
||||
process_exceptional_status(target >> 8, status);
|
||||
}
|
||||
@ -154,61 +155,52 @@ pub extern "C" fn output(target: i32, data: i32) {
|
||||
|
||||
pub extern "C" fn output_wide(target: i32, data: CSlice<i32>) {
|
||||
unsafe {
|
||||
// Clear status so we can observe response
|
||||
TRANSACTION_BUFFER.reply_status.set(0);
|
||||
|
||||
TRANSACTION_BUFFER.request_cmd = 0;
|
||||
TRANSACTION_BUFFER.request_cmd = RTIO_CMD_OUTPUT;
|
||||
TRANSACTION_BUFFER.data_width = data.len() as i8;
|
||||
TRANSACTION_BUFFER.request_target = target;
|
||||
TRANSACTION_BUFFER.request_timestamp = NOW;
|
||||
TRANSACTION_BUFFER.request_data[..data.len()].copy_from_slice(data.as_ref());
|
||||
|
||||
fence(Ordering::SeqCst);
|
||||
asm::sev();
|
||||
let mut status;
|
||||
loop {
|
||||
status = TRANSACTION_BUFFER.reply_status.get();
|
||||
if status != 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let status = status & !0x10000;
|
||||
let status = await_reply_status() & !(1 << 16);
|
||||
if status != 0 {
|
||||
process_exceptional_status(target >> 8, status);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn process_exceptional_input_status(status: i32, channel: i32) {
|
||||
if status & RTIO_I_STATUS_OVERFLOW != 0 {
|
||||
artiq_raise!(
|
||||
"RTIOOverflow",
|
||||
"RTIO input overflow on channel {rtio_channel_info:0}",
|
||||
channel as i64,
|
||||
0,
|
||||
0
|
||||
);
|
||||
}
|
||||
if status & RTIO_I_STATUS_DESTINATION_UNREACHABLE != 0 {
|
||||
artiq_raise!(
|
||||
"RTIODestinationUnreachable",
|
||||
"RTIO destination unreachable, input, on channel {rtio_channel_info:0}",
|
||||
channel as i64,
|
||||
0,
|
||||
0
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub extern "C" fn input_timestamp(timeout: i64, channel: i32) -> i64 {
|
||||
unsafe {
|
||||
// Clear status so we can observe response
|
||||
TRANSACTION_BUFFER.reply_status.set(0);
|
||||
|
||||
TRANSACTION_BUFFER.request_cmd = 1;
|
||||
TRANSACTION_BUFFER.request_cmd = RTIO_CMD_INPUT;
|
||||
TRANSACTION_BUFFER.request_timestamp = timeout;
|
||||
TRANSACTION_BUFFER.request_target = channel << 8;
|
||||
TRANSACTION_BUFFER.data_width = 0;
|
||||
|
||||
fence(Ordering::SeqCst);
|
||||
asm::sev();
|
||||
|
||||
let mut status;
|
||||
loop {
|
||||
status = TRANSACTION_BUFFER.reply_status.get();
|
||||
if status != 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
let status = await_reply_status();
|
||||
|
||||
if status & RTIO_I_STATUS_OVERFLOW != 0 {
|
||||
artiq_raise!(
|
||||
"RTIOOverflow",
|
||||
format!(
|
||||
"RTIO input overflow on channel 0x{:04x}:{}",
|
||||
channel,
|
||||
resolve_channel_name(channel as u32)
|
||||
),
|
||||
"RTIO input overflow on channel {rtio_channel_info:0}",
|
||||
channel as i64,
|
||||
0,
|
||||
0
|
||||
@ -220,11 +212,7 @@ pub extern "C" fn input_timestamp(timeout: i64, channel: i32) -> i64 {
|
||||
if status & RTIO_I_STATUS_DESTINATION_UNREACHABLE != 0 {
|
||||
artiq_raise!(
|
||||
"RTIODestinationUnreachable",
|
||||
format!(
|
||||
"RTIO destination unreachable, input, on channel 0x{:04x}:{}",
|
||||
channel,
|
||||
resolve_channel_name(channel as u32)
|
||||
),
|
||||
"RTIO destination unreachable, input, on channel {rtio_channel_info:0}",
|
||||
channel as i64,
|
||||
0,
|
||||
0
|
||||
@ -237,50 +225,14 @@ pub extern "C" fn input_timestamp(timeout: i64, channel: i32) -> i64 {
|
||||
|
||||
pub extern "C" fn input_data(channel: i32) -> i32 {
|
||||
unsafe {
|
||||
TRANSACTION_BUFFER.reply_status.set(0);
|
||||
|
||||
TRANSACTION_BUFFER.request_cmd = 1;
|
||||
TRANSACTION_BUFFER.request_cmd = RTIO_CMD_INPUT;
|
||||
TRANSACTION_BUFFER.request_timestamp = -1;
|
||||
TRANSACTION_BUFFER.request_target = channel << 8;
|
||||
TRANSACTION_BUFFER.data_width = 0;
|
||||
|
||||
fence(Ordering::SeqCst);
|
||||
asm::sev();
|
||||
let status = await_reply_status();
|
||||
|
||||
let mut status;
|
||||
loop {
|
||||
status = TRANSACTION_BUFFER.reply_status.get();
|
||||
if status != 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if status & RTIO_I_STATUS_OVERFLOW != 0 {
|
||||
artiq_raise!(
|
||||
"RTIOOverflow",
|
||||
format!(
|
||||
"RTIO input overflow on channel 0x{:04x}:{}",
|
||||
channel,
|
||||
resolve_channel_name(channel as u32)
|
||||
),
|
||||
channel as i64,
|
||||
0,
|
||||
0
|
||||
);
|
||||
}
|
||||
if status & RTIO_I_STATUS_DESTINATION_UNREACHABLE != 0 {
|
||||
artiq_raise!(
|
||||
"RTIODestinationUnreachable",
|
||||
format!(
|
||||
"RTIO destination unreachable, input, on channel 0x{:04x}:{}",
|
||||
channel,
|
||||
resolve_channel_name(channel as u32)
|
||||
),
|
||||
channel as i64,
|
||||
0,
|
||||
0
|
||||
);
|
||||
}
|
||||
process_exceptional_input_status(status, channel);
|
||||
|
||||
TRANSACTION_BUFFER.reply_data.get()
|
||||
}
|
||||
@ -288,50 +240,13 @@ pub extern "C" fn input_data(channel: i32) -> i32 {
|
||||
|
||||
pub extern "C" fn input_timestamped_data(timeout: i64, channel: i32) -> TimestampedData {
|
||||
unsafe {
|
||||
TRANSACTION_BUFFER.reply_status.set(0);
|
||||
|
||||
TRANSACTION_BUFFER.request_cmd = 1;
|
||||
TRANSACTION_BUFFER.request_cmd = RTIO_CMD_INPUT;
|
||||
TRANSACTION_BUFFER.request_timestamp = timeout;
|
||||
TRANSACTION_BUFFER.request_target = channel << 8;
|
||||
TRANSACTION_BUFFER.data_width = 0;
|
||||
|
||||
fence(Ordering::SeqCst);
|
||||
asm::sev();
|
||||
|
||||
let mut status;
|
||||
loop {
|
||||
status = TRANSACTION_BUFFER.reply_status.get();
|
||||
if status != 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if status & RTIO_I_STATUS_OVERFLOW != 0 {
|
||||
artiq_raise!(
|
||||
"RTIOOverflow",
|
||||
format!(
|
||||
"RTIO input overflow on channel 0x{:04x}:{}",
|
||||
channel,
|
||||
resolve_channel_name(channel as u32)
|
||||
),
|
||||
channel as i64,
|
||||
0,
|
||||
0
|
||||
);
|
||||
}
|
||||
if status & RTIO_I_STATUS_DESTINATION_UNREACHABLE != 0 {
|
||||
artiq_raise!(
|
||||
"RTIODestinationUnreachable",
|
||||
format!(
|
||||
"RTIO destination unreachable, input, on channel 0x{:04x}:{}",
|
||||
channel,
|
||||
resolve_channel_name(channel as u32)
|
||||
),
|
||||
channel as i64,
|
||||
0,
|
||||
0
|
||||
);
|
||||
}
|
||||
let status = await_reply_status();
|
||||
process_exceptional_input_status(status, channel);
|
||||
|
||||
TimestampedData {
|
||||
timestamp: TRANSACTION_BUFFER.reply_timestamp.get(),
|
||||
|
||||
@ -4,7 +4,7 @@ use cslice::CSlice;
|
||||
|
||||
#[cfg(has_drtio)]
|
||||
use super::{KERNEL_CHANNEL_0TO1, KERNEL_CHANNEL_1TO0, Message};
|
||||
use crate::{artiq_raise, pl::csr, resolve_channel_name, rtio_core};
|
||||
use crate::{artiq_raise, pl::csr, rtio_core};
|
||||
|
||||
pub const RTIO_O_STATUS_WAIT: u8 = 1;
|
||||
pub const RTIO_O_STATUS_UNDERFLOW: u8 = 2;
|
||||
@ -80,11 +80,7 @@ unsafe fn process_exceptional_status(channel: i32, status: u8) {
|
||||
if status & RTIO_O_STATUS_UNDERFLOW != 0 {
|
||||
artiq_raise!(
|
||||
"RTIOUnderflow",
|
||||
format!(
|
||||
"RTIO underflow at {{1}} mu, channel 0x{:04x}:{}, slack {{2}} mu",
|
||||
channel,
|
||||
resolve_channel_name(channel as u32)
|
||||
),
|
||||
"RTIO underflow at {1} mu, channel {rtio_channel_info:0}, slack {2} mu",
|
||||
channel as i64,
|
||||
timestamp,
|
||||
timestamp - get_counter()
|
||||
@ -93,13 +89,9 @@ unsafe fn process_exceptional_status(channel: i32, status: u8) {
|
||||
if status & RTIO_O_STATUS_DESTINATION_UNREACHABLE != 0 {
|
||||
artiq_raise!(
|
||||
"RTIODestinationUnreachable",
|
||||
format!(
|
||||
"RTIO destination unreachable, output, at {{0}} mu, channel 0x{:04x}:{}",
|
||||
channel,
|
||||
resolve_channel_name(channel as u32)
|
||||
),
|
||||
timestamp,
|
||||
"RTIO destination unreachable, output, at {1} mu, channel {rtio_channel_info:0}",
|
||||
channel as i64,
|
||||
timestamp,
|
||||
0
|
||||
);
|
||||
}
|
||||
@ -144,11 +136,7 @@ pub extern "C" fn input_timestamp(timeout: i64, channel: i32) -> i64 {
|
||||
if status & RTIO_I_STATUS_OVERFLOW != 0 {
|
||||
artiq_raise!(
|
||||
"RTIOOverflow",
|
||||
format!(
|
||||
"RTIO input overflow on channel 0x{:04x}:{}",
|
||||
channel,
|
||||
resolve_channel_name(channel as u32)
|
||||
),
|
||||
"RTIO input overflow on channel {rtio_channel_info:0}",
|
||||
channel as i64,
|
||||
0,
|
||||
0
|
||||
@ -160,11 +148,7 @@ pub extern "C" fn input_timestamp(timeout: i64, channel: i32) -> i64 {
|
||||
if status & RTIO_I_STATUS_DESTINATION_UNREACHABLE != 0 {
|
||||
artiq_raise!(
|
||||
"RTIODestinationUnreachable",
|
||||
format!(
|
||||
"RTIO destination unreachable, input, on channel 0x{:04x}:{}",
|
||||
channel,
|
||||
resolve_channel_name(channel as u32)
|
||||
),
|
||||
"RTIO destination unreachable, input, on channel {rtio_channel_info:0}",
|
||||
channel as i64,
|
||||
0,
|
||||
0
|
||||
@ -188,11 +172,7 @@ pub extern "C" fn input_data(channel: i32) -> i32 {
|
||||
if status & RTIO_I_STATUS_OVERFLOW != 0 {
|
||||
artiq_raise!(
|
||||
"RTIOOverflow",
|
||||
format!(
|
||||
"RTIO input overflow on channel 0x{:04x}:{}",
|
||||
channel,
|
||||
resolve_channel_name(channel as u32)
|
||||
),
|
||||
"RTIO input overflow on channel {rtio_channel_info:0}",
|
||||
channel as i64,
|
||||
0,
|
||||
0
|
||||
@ -201,11 +181,7 @@ pub extern "C" fn input_data(channel: i32) -> i32 {
|
||||
if status & RTIO_I_STATUS_DESTINATION_UNREACHABLE != 0 {
|
||||
artiq_raise!(
|
||||
"RTIODestinationUnreachable",
|
||||
format!(
|
||||
"RTIO destination unreachable, input, on channel 0x{:04x}:{}",
|
||||
channel,
|
||||
resolve_channel_name(channel as u32)
|
||||
),
|
||||
"RTIO destination unreachable, input, on channel {rtio_channel_info:0}",
|
||||
channel as i64,
|
||||
0,
|
||||
0
|
||||
@ -229,11 +205,7 @@ pub extern "C" fn input_timestamped_data(timeout: i64, channel: i32) -> Timestam
|
||||
if status & RTIO_I_STATUS_OVERFLOW != 0 {
|
||||
artiq_raise!(
|
||||
"RTIOOverflow",
|
||||
format!(
|
||||
"RTIO input overflow on channel 0x{:04x}:{}",
|
||||
channel,
|
||||
resolve_channel_name(channel as u32)
|
||||
),
|
||||
"RTIO input overflow on channel {rtio_channel_info:0}",
|
||||
channel as i64,
|
||||
0,
|
||||
0
|
||||
@ -245,11 +217,7 @@ pub extern "C" fn input_timestamped_data(timeout: i64, channel: i32) -> Timestam
|
||||
if status & RTIO_I_STATUS_DESTINATION_UNREACHABLE != 0 {
|
||||
artiq_raise!(
|
||||
"RTIODestinationUnreachable",
|
||||
format!(
|
||||
"RTIO destination unreachable, input, on channel 0x{:04x}:{}",
|
||||
channel,
|
||||
resolve_channel_name(channel as u32)
|
||||
),
|
||||
"RTIO destination unreachable, input, on channel {rtio_channel_info:0}",
|
||||
channel as i64,
|
||||
0,
|
||||
0
|
||||
|
||||
@ -8,18 +8,10 @@
|
||||
#[macro_use]
|
||||
extern crate alloc;
|
||||
|
||||
use alloc::{collections::BTreeMap, string::String};
|
||||
|
||||
use byteorder::NativeEndian;
|
||||
use io::{Cursor, ProtoRead};
|
||||
use libasync::block_async;
|
||||
use libconfig;
|
||||
use log::{error, warn};
|
||||
#[cfg(has_drtiosat)]
|
||||
pub use pl::csr::drtiosat as rtio_core;
|
||||
#[cfg(has_rtio_core)]
|
||||
pub use pl::csr::rtio_core;
|
||||
use void::Void;
|
||||
|
||||
pub mod eh_artiq;
|
||||
pub mod irq;
|
||||
@ -39,115 +31,3 @@ pub struct RPCException {
|
||||
pub column: i32,
|
||||
pub function: u32,
|
||||
}
|
||||
|
||||
pub static mut SEEN_ASYNC_ERRORS: u8 = 0;
|
||||
|
||||
pub const ASYNC_ERROR_COLLISION: u8 = 1 << 0;
|
||||
pub const ASYNC_ERROR_BUSY: u8 = 1 << 1;
|
||||
pub const ASYNC_ERROR_SEQUENCE_ERROR: u8 = 1 << 2;
|
||||
|
||||
pub unsafe fn get_async_errors() -> u8 {
|
||||
let errors = SEEN_ASYNC_ERRORS;
|
||||
SEEN_ASYNC_ERRORS = 0;
|
||||
errors
|
||||
}
|
||||
|
||||
fn wait_for_async_rtio_error() -> nb::Result<(), Void> {
|
||||
unsafe {
|
||||
#[cfg(has_rtio_core)]
|
||||
let errors = rtio_core::async_error_read();
|
||||
#[cfg(has_drtiosat)]
|
||||
let errors = rtio_core::protocol_error_read();
|
||||
if errors != 0 {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(nb::Error::WouldBlock)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn report_async_rtio_errors() {
|
||||
loop {
|
||||
let _ = block_async!(wait_for_async_rtio_error()).await;
|
||||
unsafe {
|
||||
#[cfg(has_rtio_core)]
|
||||
let errors = rtio_core::async_error_read();
|
||||
#[cfg(has_drtiosat)]
|
||||
let errors = rtio_core::protocol_error_read();
|
||||
if errors & ASYNC_ERROR_COLLISION != 0 {
|
||||
let channel = rtio_core::collision_channel_read();
|
||||
error!(
|
||||
"RTIO collision involving channel 0x{:04x}:{}",
|
||||
channel,
|
||||
resolve_channel_name(channel as u32)
|
||||
);
|
||||
}
|
||||
if errors & ASYNC_ERROR_BUSY != 0 {
|
||||
let channel = rtio_core::busy_channel_read();
|
||||
error!(
|
||||
"RTIO busy error involving channel 0x{:04x}:{}",
|
||||
channel,
|
||||
resolve_channel_name(channel as u32)
|
||||
);
|
||||
}
|
||||
if errors & ASYNC_ERROR_SEQUENCE_ERROR != 0 {
|
||||
let channel = rtio_core::sequence_error_channel_read();
|
||||
error!(
|
||||
"RTIO sequence error involving channel 0x{:04x}:{}",
|
||||
channel,
|
||||
resolve_channel_name(channel as u32)
|
||||
);
|
||||
}
|
||||
SEEN_ASYNC_ERRORS = errors;
|
||||
#[cfg(has_rtio_core)]
|
||||
rtio_core::async_error_write(errors);
|
||||
#[cfg(has_drtiosat)]
|
||||
rtio_core::protocol_error_write(errors);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static mut RTIO_DEVICE_MAP: BTreeMap<u32, String> = BTreeMap::new();
|
||||
|
||||
fn read_device_map() -> BTreeMap<u32, String> {
|
||||
let mut device_map: BTreeMap<u32, String> = BTreeMap::new();
|
||||
let _ = libconfig::read("device_map")
|
||||
.and_then(|raw_bytes| {
|
||||
let mut bytes_cr = Cursor::new(raw_bytes);
|
||||
let size = bytes_cr.read_u32::<NativeEndian>().unwrap();
|
||||
for _ in 0..size {
|
||||
let channel = bytes_cr.read_u32::<NativeEndian>().unwrap();
|
||||
let device_name = bytes_cr.read_string::<NativeEndian>().unwrap();
|
||||
if let Some(old_entry) = device_map.insert(channel, device_name.clone()) {
|
||||
warn!(
|
||||
"conflicting device map entries for RTIO channel {}: '{}' and '{}'",
|
||||
channel, old_entry, device_name
|
||||
);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
.or_else(|err| {
|
||||
warn!(
|
||||
"error reading device map ({}), device names will not be available in RTIO error messages",
|
||||
err
|
||||
);
|
||||
Err(err)
|
||||
});
|
||||
device_map
|
||||
}
|
||||
|
||||
pub fn resolve_channel_name(channel: u32) -> String {
|
||||
unsafe {
|
||||
match RTIO_DEVICE_MAP.get(&channel) {
|
||||
Some(val) => val.clone(),
|
||||
None => String::from("unknown"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn setup_device_map() {
|
||||
unsafe {
|
||||
RTIO_DEVICE_MAP = read_device_map();
|
||||
}
|
||||
}
|
||||
|
||||
@ -28,6 +28,7 @@ futures = { version = "0.3", default-features = false, features = ["async-await"
|
||||
async-recursion = "1.1"
|
||||
log_buffer = { version = "1.2" }
|
||||
vcell = "0.1"
|
||||
nb = "0.1"
|
||||
|
||||
libboard_zynq = { path = "@@ZYNQ_RS@@/libboard_zynq", features = ["ipv6", "async"]}
|
||||
libsupport_zynq = { path = "@@ZYNQ_RS@@/libsupport_zynq", default-features = false, features = ["alloc_core"] }
|
||||
|
||||
@ -6,7 +6,7 @@ use core::cell::RefCell;
|
||||
use libasync::{smoltcp::TcpStream, task};
|
||||
use libboard_artiq::drtio_routing;
|
||||
use libboard_zynq::smoltcp::Error;
|
||||
use libcortex_a9::{cache, mutex::Mutex};
|
||||
use libcortex_a9::cache;
|
||||
use log::{debug, info, warn};
|
||||
|
||||
use crate::{pl, proto_async::*};
|
||||
@ -56,8 +56,6 @@ pub mod remote_analyzer {
|
||||
}
|
||||
|
||||
pub async fn get_data(
|
||||
aux_mutex: &Rc<Mutex<bool>>,
|
||||
routing_table: &drtio_routing::RoutingTable,
|
||||
up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>,
|
||||
) -> Result<RemoteBuffer, drtio::Error> {
|
||||
// gets data from satellites and returns consolidated data
|
||||
@ -66,7 +64,7 @@ pub mod remote_analyzer {
|
||||
let mut remote_sent_bytes = 0;
|
||||
let mut remote_total_bytes = 0;
|
||||
|
||||
let data_vec = match drtio::analyzer_query(aux_mutex, routing_table, up_destinations).await {
|
||||
let data_vec = match drtio::analyzer_query(up_destinations).await {
|
||||
Ok(data_vec) => data_vec,
|
||||
Err(e) => return Err(e),
|
||||
};
|
||||
@ -107,8 +105,6 @@ async fn write_header(stream: &mut TcpStream, header: &Header) -> Result<(), Err
|
||||
|
||||
async fn handle_connection(
|
||||
stream: &mut TcpStream,
|
||||
_aux_mutex: &Rc<Mutex<bool>>,
|
||||
_routing_table: &drtio_routing::RoutingTable,
|
||||
_up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>,
|
||||
) -> Result<(), Error> {
|
||||
info!("received connection");
|
||||
@ -133,7 +129,7 @@ async fn handle_connection(
|
||||
}
|
||||
|
||||
#[cfg(has_drtio)]
|
||||
let remote = remote_analyzer::get_data(_aux_mutex, _routing_table, _up_destinations).await;
|
||||
let remote = remote_analyzer::get_data(_up_destinations).await;
|
||||
#[cfg(has_drtio)]
|
||||
let (header, remote_data) = match remote {
|
||||
Ok(remote) => (
|
||||
@ -184,21 +180,14 @@ async fn handle_connection(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn start(
|
||||
aux_mutex: &Rc<Mutex<bool>>,
|
||||
routing_table: &Rc<RefCell<drtio_routing::RoutingTable>>,
|
||||
up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>,
|
||||
) {
|
||||
let aux_mutex = aux_mutex.clone();
|
||||
let routing_table = routing_table.clone();
|
||||
pub fn start(up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>) {
|
||||
let up_destinations = up_destinations.clone();
|
||||
task::spawn(async move {
|
||||
loop {
|
||||
arm();
|
||||
let mut stream = TcpStream::accept(1382, 2048, 2048).await.unwrap();
|
||||
disarm();
|
||||
let routing_table = routing_table.borrow();
|
||||
let _ = handle_connection(&mut stream, &aux_mutex, &routing_table, &up_destinations)
|
||||
let _ = handle_connection(&mut stream, &up_destinations)
|
||||
.await
|
||||
.map_err(|e| warn!("connection terminated: {:?}", e));
|
||||
let _ = stream.flush().await;
|
||||
|
||||
@ -9,17 +9,20 @@ use dyld::elf;
|
||||
use futures::{future::FutureExt, select_biased};
|
||||
#[cfg(has_drtio)]
|
||||
use io::Cursor;
|
||||
use ksupport::kernel;
|
||||
#[cfg(has_drtio)]
|
||||
use ksupport::rpc;
|
||||
use ksupport::{kernel, resolve_channel_name};
|
||||
use libasync::{smoltcp::{Sockets, TcpStream},
|
||||
use libasync::{block_async,
|
||||
smoltcp::{Sockets, TcpStream},
|
||||
task};
|
||||
use libboard_artiq::drtio_routing;
|
||||
#[cfg(has_drtio)]
|
||||
use libboard_artiq::drtioaux::Packet;
|
||||
use libboard_artiq::{drtio_routing::{self, RoutingTable},
|
||||
resolve_channel_name};
|
||||
#[cfg(feature = "target_kasli_soc")]
|
||||
use libboard_zynq::error_led::ErrorLED;
|
||||
use libboard_zynq::{self as zynq,
|
||||
i2c::Error as I2cError,
|
||||
smoltcp::{self,
|
||||
iface::{EthernetInterfaceBuilder, NeighborCache},
|
||||
time::{Duration, Instant},
|
||||
@ -27,15 +30,21 @@ use libboard_zynq::{self as zynq,
|
||||
timer};
|
||||
use libconfig::{self, net_settings};
|
||||
use libcortex_a9::{mutex::Mutex,
|
||||
once_lock::OnceLock,
|
||||
semaphore::Semaphore,
|
||||
sync_channel::{Receiver, Sender}};
|
||||
use log::{error, info, warn};
|
||||
use num_derive::{FromPrimitive, ToPrimitive};
|
||||
use num_traits::{FromPrimitive, ToPrimitive};
|
||||
#[cfg(has_drtiosat)]
|
||||
use pl::csr::drtiosat as rtio_core;
|
||||
#[cfg(has_rtio_core)]
|
||||
use pl::csr::rtio_core;
|
||||
#[cfg(has_drtio)]
|
||||
use tar_no_std::TarArchiveRef;
|
||||
use void::Void;
|
||||
|
||||
#[cfg(has_drtio)]
|
||||
#[cfg(any(has_rtio_core, has_drtiosat, has_drtio))]
|
||||
use crate::pl;
|
||||
use crate::{analyzer, mgmt, moninj, proto_async::*, rpc_async, rtio_dma, rtio_mgt};
|
||||
#[cfg(has_drtio)]
|
||||
@ -114,8 +123,79 @@ enum Reply {
|
||||
ClockFailure = 15,
|
||||
}
|
||||
|
||||
pub static mut SEEN_ASYNC_ERRORS: u8 = 0;
|
||||
|
||||
pub const ASYNC_ERROR_COLLISION: u8 = 1 << 0;
|
||||
pub const ASYNC_ERROR_BUSY: u8 = 1 << 1;
|
||||
pub const ASYNC_ERROR_SEQUENCE_ERROR: u8 = 1 << 2;
|
||||
|
||||
pub unsafe fn get_async_errors() -> u8 {
|
||||
let errors = SEEN_ASYNC_ERRORS;
|
||||
SEEN_ASYNC_ERRORS = 0;
|
||||
errors
|
||||
}
|
||||
|
||||
fn wait_for_async_rtio_error() -> nb::Result<(), Void> {
|
||||
unsafe {
|
||||
#[cfg(has_rtio_core)]
|
||||
let errors = rtio_core::async_error_read();
|
||||
#[cfg(has_drtiosat)]
|
||||
let errors = rtio_core::protocol_error_read();
|
||||
if errors != 0 {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(nb::Error::WouldBlock)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn report_async_rtio_errors() {
|
||||
loop {
|
||||
let _ = block_async!(wait_for_async_rtio_error()).await;
|
||||
unsafe {
|
||||
#[cfg(has_rtio_core)]
|
||||
let errors = rtio_core::async_error_read();
|
||||
#[cfg(has_drtiosat)]
|
||||
let errors = rtio_core::protocol_error_read();
|
||||
if errors & ASYNC_ERROR_COLLISION != 0 {
|
||||
let channel = rtio_core::collision_channel_read();
|
||||
error!(
|
||||
"RTIO collision involving channel 0x{:04x}:{}",
|
||||
channel,
|
||||
resolve_channel_name(channel as u32)
|
||||
);
|
||||
}
|
||||
if errors & ASYNC_ERROR_BUSY != 0 {
|
||||
let channel = rtio_core::busy_channel_read();
|
||||
error!(
|
||||
"RTIO busy error involving channel 0x{:04x}:{}",
|
||||
channel,
|
||||
resolve_channel_name(channel as u32)
|
||||
);
|
||||
}
|
||||
if errors & ASYNC_ERROR_SEQUENCE_ERROR != 0 {
|
||||
let channel = rtio_core::sequence_error_channel_read();
|
||||
error!(
|
||||
"RTIO sequence error involving channel 0x{:04x}:{}",
|
||||
channel,
|
||||
resolve_channel_name(channel as u32)
|
||||
);
|
||||
}
|
||||
SEEN_ASYNC_ERRORS = errors;
|
||||
#[cfg(has_rtio_core)]
|
||||
rtio_core::async_error_write(errors);
|
||||
#[cfg(has_drtiosat)]
|
||||
rtio_core::protocol_error_write(errors);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static CACHE_STORE: Mutex<BTreeMap<String, Vec<i32>>> = Mutex::new(BTreeMap::new());
|
||||
|
||||
pub static RESTART_IDLE: Semaphore = Semaphore::new(1, 1);
|
||||
|
||||
pub static ROUTING_TABLE: OnceLock<RoutingTable> = OnceLock::new();
|
||||
|
||||
async fn write_header(stream: &TcpStream, reply: Reply) -> Result<()> {
|
||||
stream
|
||||
.send_slice(&[0x5a, 0x5a, 0x5a, 0x5a, reply.to_u8().unwrap()])
|
||||
@ -192,9 +272,8 @@ async fn handle_run_kernel(
|
||||
stream: Option<&TcpStream>,
|
||||
control: &Rc<RefCell<kernel::Control>>,
|
||||
_up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>,
|
||||
aux_mutex: &Rc<Mutex<bool>>,
|
||||
routing_table: &drtio_routing::RoutingTable,
|
||||
) -> Result<()> {
|
||||
let i2c_bus = libboard_artiq::i2c::get_bus();
|
||||
control.borrow_mut().tx.async_send(kernel::Message::StartRequest).await;
|
||||
loop {
|
||||
let reply = control.borrow_mut().rx.async_recv().await;
|
||||
@ -280,14 +359,16 @@ async fn handle_run_kernel(
|
||||
}
|
||||
}
|
||||
}
|
||||
kernel::Message::KernelFinished(async_errors) => {
|
||||
kernel::Message::KernelFinished => {
|
||||
let async_errors = unsafe { get_async_errors() };
|
||||
if let Some(stream) = stream {
|
||||
write_header(stream, Reply::KernelFinished).await?;
|
||||
write_i8(stream, async_errors as i8).await?;
|
||||
}
|
||||
break;
|
||||
}
|
||||
kernel::Message::KernelException(exceptions, stack_pointers, backtrace, async_errors) => {
|
||||
kernel::Message::KernelException(exceptions, stack_pointers, backtrace) => {
|
||||
let async_errors = unsafe { get_async_errors() };
|
||||
match stream {
|
||||
Some(stream) => {
|
||||
// only send the exception data to host if there is host,
|
||||
@ -356,13 +437,13 @@ async fn handle_run_kernel(
|
||||
.await;
|
||||
}
|
||||
kernel::Message::DmaPutRequest(recorder) => {
|
||||
let _id = rtio_dma::put_record(aux_mutex, routing_table, recorder).await;
|
||||
let _id = rtio_dma::put_record(recorder).await;
|
||||
#[cfg(has_drtio)]
|
||||
rtio_dma::remote_dma::upload_traces(aux_mutex, routing_table, _id).await;
|
||||
rtio_dma::remote_dma::upload_traces(_id).await;
|
||||
}
|
||||
kernel::Message::DmaEraseRequest(name) => {
|
||||
// prevent possible OOM when we have large DMA record replacement.
|
||||
rtio_dma::erase(name, aux_mutex, routing_table).await;
|
||||
rtio_dma::erase(name).await;
|
||||
}
|
||||
kernel::Message::DmaGetRequest(name) => {
|
||||
let result = rtio_dma::retrieve(name).await;
|
||||
@ -374,7 +455,7 @@ async fn handle_run_kernel(
|
||||
}
|
||||
#[cfg(has_drtio)]
|
||||
kernel::Message::DmaStartRemoteRequest { id, timestamp } => {
|
||||
rtio_dma::remote_dma::playback(aux_mutex, routing_table, id as u32, timestamp as u64).await;
|
||||
rtio_dma::remote_dma::playback(id as u32, timestamp as u64).await;
|
||||
}
|
||||
#[cfg(has_drtio)]
|
||||
kernel::Message::DmaAwaitRemoteRequest(id) => {
|
||||
@ -399,41 +480,110 @@ async fn handle_run_kernel(
|
||||
};
|
||||
control.borrow_mut().tx.async_send(reply).await;
|
||||
}
|
||||
#[cfg(has_drtio)]
|
||||
kernel::Message::I2cStartRequest(busno)
|
||||
| kernel::Message::I2cRestartRequest(busno)
|
||||
| kernel::Message::I2cStopRequest(busno)
|
||||
| kernel::Message::I2cSwitchSelectRequest { busno, .. } => {
|
||||
let result = rtio_mgt::drtio::i2c_send_basic(aux_mutex, routing_table, &reply, busno).await;
|
||||
let reply = match result {
|
||||
Ok(succeeded) => kernel::Message::I2cBasicReply(succeeded),
|
||||
Err(_) => kernel::Message::I2cBasicReply(false),
|
||||
};
|
||||
control.borrow_mut().tx.async_send(reply).await;
|
||||
let _destination = (busno >> 16) as u8;
|
||||
#[cfg(has_drtio)]
|
||||
if _destination != 0 {
|
||||
let result = rtio_mgt::drtio::i2c_send_basic(&reply, busno).await;
|
||||
let reply = match result {
|
||||
Ok(succeeded) => kernel::Message::I2cBasicReply(succeeded),
|
||||
Err(_) => kernel::Message::I2cBasicReply(false),
|
||||
};
|
||||
control.borrow_mut().tx.async_send(reply).await;
|
||||
continue;
|
||||
}
|
||||
let mut succeeded = busno == 0;
|
||||
if succeeded {
|
||||
succeeded = match &reply {
|
||||
kernel::Message::I2cStartRequest(_) => i2c_bus.start().is_ok(),
|
||||
kernel::Message::I2cRestartRequest(_) => i2c_bus.restart().is_ok(),
|
||||
kernel::Message::I2cStopRequest(_) => i2c_bus.stop().is_ok(),
|
||||
kernel::Message::I2cSwitchSelectRequest { address, mask, .. } => {
|
||||
let ch = match mask {
|
||||
//decode from mainline, PCA9548-centric API
|
||||
0x00 => Some(None),
|
||||
0x01 => Some(Some(0)),
|
||||
0x02 => Some(Some(1)),
|
||||
0x04 => Some(Some(2)),
|
||||
0x08 => Some(Some(3)),
|
||||
0x10 => Some(Some(4)),
|
||||
0x20 => Some(Some(5)),
|
||||
0x40 => Some(Some(6)),
|
||||
0x80 => Some(Some(7)),
|
||||
_ => None,
|
||||
};
|
||||
ch.is_some_and(|c| i2c_bus.pca954x_select(*address as u8, c).is_ok())
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
control
|
||||
.borrow_mut()
|
||||
.tx
|
||||
.async_send(kernel::Message::I2cBasicReply(succeeded))
|
||||
.await;
|
||||
}
|
||||
#[cfg(has_drtio)]
|
||||
kernel::Message::I2cWriteRequest { busno, data } => {
|
||||
let result = rtio_mgt::drtio::i2c_send_write(aux_mutex, routing_table, busno, data).await;
|
||||
let reply = match result {
|
||||
Ok((succeeded, ack)) => kernel::Message::I2cWriteReply { succeeded, ack },
|
||||
Err(_) => kernel::Message::I2cWriteReply {
|
||||
succeeded: false,
|
||||
ack: false,
|
||||
},
|
||||
};
|
||||
control.borrow_mut().tx.async_send(reply).await;
|
||||
let _destination = (busno >> 16) as u8;
|
||||
#[cfg(has_drtio)]
|
||||
if _destination != 0 {
|
||||
let result = rtio_mgt::drtio::i2c_send_write(busno, data).await;
|
||||
let reply = match result {
|
||||
Ok((succeeded, ack)) => kernel::Message::I2cWriteReply { succeeded, ack },
|
||||
Err(_) => kernel::Message::I2cWriteReply {
|
||||
succeeded: false,
|
||||
ack: false,
|
||||
},
|
||||
};
|
||||
control.borrow_mut().tx.async_send(reply).await;
|
||||
continue;
|
||||
}
|
||||
let mut succeeded = busno == 0;
|
||||
let mut ack = false;
|
||||
if succeeded {
|
||||
(succeeded, ack) = match i2c_bus.write(data as u8) {
|
||||
Ok(()) => (true, true),
|
||||
Err(I2cError::Nack) => (true, false),
|
||||
Err(_) => (false, false),
|
||||
}
|
||||
}
|
||||
control
|
||||
.borrow_mut()
|
||||
.tx
|
||||
.async_send(kernel::Message::I2cWriteReply { succeeded, ack })
|
||||
.await;
|
||||
}
|
||||
#[cfg(has_drtio)]
|
||||
kernel::Message::I2cReadRequest { busno, ack } => {
|
||||
let result = rtio_mgt::drtio::i2c_send_read(aux_mutex, routing_table, busno, ack).await;
|
||||
let reply = match result {
|
||||
Ok((succeeded, data)) => kernel::Message::I2cReadReply { succeeded, data },
|
||||
Err(_) => kernel::Message::I2cReadReply {
|
||||
succeeded: false,
|
||||
data: 0xFF,
|
||||
},
|
||||
};
|
||||
control.borrow_mut().tx.async_send(reply).await;
|
||||
let _destination = (busno >> 16) as u8;
|
||||
#[cfg(has_drtio)]
|
||||
if _destination != 0 {
|
||||
let result = rtio_mgt::drtio::i2c_send_read(busno, ack).await;
|
||||
let reply = match result {
|
||||
Ok((succeeded, data)) => kernel::Message::I2cReadReply { succeeded, data },
|
||||
Err(_) => kernel::Message::I2cReadReply {
|
||||
succeeded: false,
|
||||
data: 0xFF,
|
||||
},
|
||||
};
|
||||
control.borrow_mut().tx.async_send(reply).await;
|
||||
continue;
|
||||
}
|
||||
let mut succeeded = busno == 0;
|
||||
let mut data = 0xFF;
|
||||
if succeeded {
|
||||
(succeeded, data) = match i2c_bus.read(ack) {
|
||||
Ok(r) => (true, r),
|
||||
Err(_) => (false, 0xFF),
|
||||
}
|
||||
}
|
||||
control
|
||||
.borrow_mut()
|
||||
.tx
|
||||
.async_send(kernel::Message::I2cReadReply { succeeded, data })
|
||||
.await;
|
||||
}
|
||||
#[cfg(has_drtio)]
|
||||
kernel::Message::SubkernelLoadRunRequest {
|
||||
@ -442,7 +592,7 @@ async fn handle_run_kernel(
|
||||
run,
|
||||
timestamp,
|
||||
} => {
|
||||
let succeeded = match subkernel::load(aux_mutex, routing_table, id, run, timestamp).await {
|
||||
let succeeded = match subkernel::load(id, run, timestamp).await {
|
||||
Ok(()) => true,
|
||||
Err(e) => {
|
||||
error!("Error loading subkernel: {:?}", e);
|
||||
@ -457,7 +607,7 @@ async fn handle_run_kernel(
|
||||
}
|
||||
#[cfg(has_drtio)]
|
||||
kernel::Message::SubkernelAwaitFinishRequest { id, timeout } => {
|
||||
let res = subkernel::await_finish(aux_mutex, routing_table, id, timeout).await;
|
||||
let res = subkernel::await_finish(id, timeout).await;
|
||||
let response = match res {
|
||||
Ok(res) => {
|
||||
if res.status == subkernel::FinishStatus::CommLost {
|
||||
@ -478,7 +628,7 @@ async fn handle_run_kernel(
|
||||
}
|
||||
#[cfg(has_drtio)]
|
||||
kernel::Message::SubkernelMsgSend { id, destination, data } => {
|
||||
let res = subkernel::message_send(aux_mutex, routing_table, id, destination.unwrap(), data).await;
|
||||
let res = subkernel::message_send(id, destination.unwrap(), data).await;
|
||||
match res {
|
||||
Ok(_) => (),
|
||||
Err(e) => {
|
||||
@ -503,9 +653,7 @@ async fn handle_run_kernel(
|
||||
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, id as u32, timeout)
|
||||
.await
|
||||
.unwrap();
|
||||
let status = subkernel::await_finish(id as u32, timeout).await.unwrap();
|
||||
kernel::Message::SubkernelError(kernel::SubkernelStatus::Exception(status.exception.unwrap()))
|
||||
}
|
||||
Err(_) => kernel::Message::SubkernelError(kernel::SubkernelStatus::OtherError),
|
||||
@ -561,7 +709,7 @@ async fn handle_run_kernel(
|
||||
}
|
||||
#[cfg(has_drtio)]
|
||||
kernel::Message::RtioInitRequest => {
|
||||
rtio_mgt::drtio::reset(aux_mutex, routing_table).await;
|
||||
rtio_mgt::drtio::reset().await;
|
||||
control.borrow_mut().tx.async_send(kernel::Message::RtioInitReply).await;
|
||||
}
|
||||
#[cfg(has_drtio)]
|
||||
@ -570,12 +718,10 @@ async fn handle_run_kernel(
|
||||
address,
|
||||
length,
|
||||
} => {
|
||||
let linkno = routing_table.0[destination as usize][0] - 1;
|
||||
let linkno = ROUTING_TABLE.get().unwrap().0[destination as usize][0] - 1;
|
||||
let reply = loop {
|
||||
let result = rtio_mgt::drtio::aux_transact(
|
||||
aux_mutex,
|
||||
linkno,
|
||||
routing_table,
|
||||
&Packet::CXPReadRequest {
|
||||
destination,
|
||||
address,
|
||||
@ -612,12 +758,10 @@ async fn handle_run_kernel(
|
||||
address,
|
||||
value,
|
||||
} => {
|
||||
let linkno = routing_table.0[destination as usize][0] - 1;
|
||||
let linkno = ROUTING_TABLE.get().unwrap().0[destination as usize][0] - 1;
|
||||
let reply = loop {
|
||||
let drtioaux_packet = rtio_mgt::drtio::aux_transact(
|
||||
aux_mutex,
|
||||
linkno,
|
||||
routing_table,
|
||||
&Packet::CXPWrite32Request {
|
||||
destination,
|
||||
address,
|
||||
@ -654,11 +798,9 @@ async fn handle_run_kernel(
|
||||
x1,
|
||||
y1,
|
||||
} => {
|
||||
let linkno = routing_table.0[destination as usize][0] - 1;
|
||||
let linkno = ROUTING_TABLE.get().unwrap().0[destination as usize][0] - 1;
|
||||
let drtioaux_packet = rtio_mgt::drtio::aux_transact(
|
||||
aux_mutex,
|
||||
linkno,
|
||||
routing_table,
|
||||
&Packet::CXPROIViewerSetupRequest {
|
||||
destination,
|
||||
x0,
|
||||
@ -684,15 +826,10 @@ async fn handle_run_kernel(
|
||||
}
|
||||
#[cfg(has_drtio)]
|
||||
kernel::Message::CXPROIViewerDataRequest { destination } => {
|
||||
let linkno = routing_table.0[destination as usize][0] - 1;
|
||||
let linkno = ROUTING_TABLE.get().unwrap().0[destination as usize][0] - 1;
|
||||
let reply = loop {
|
||||
let drtioaux_packet = rtio_mgt::drtio::aux_transact(
|
||||
aux_mutex,
|
||||
linkno,
|
||||
routing_table,
|
||||
&Packet::CXPROIViewerDataRequest { destination },
|
||||
)
|
||||
.await;
|
||||
let drtioaux_packet =
|
||||
rtio_mgt::drtio::aux_transact(linkno, &Packet::CXPROIViewerDataRequest { destination }).await;
|
||||
|
||||
match drtioaux_packet {
|
||||
Ok(Packet::CXPWaitReply) => {}
|
||||
@ -734,8 +871,6 @@ 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,
|
||||
) -> Result<()> {
|
||||
if buffer[0] == elf::ELFMAG0 && buffer[1] == elf::ELFMAG1 && buffer[2] == elf::ELFMAG2 && buffer[3] == elf::ELFMAG3
|
||||
{
|
||||
@ -761,7 +896,7 @@ async fn handle_flash_kernel(
|
||||
if up {
|
||||
let subkernel_lib = entry.data().to_vec();
|
||||
subkernel::add_subkernel(sid, dest, subkernel_lib).await;
|
||||
match subkernel::upload(_aux_mutex, _routing_table, sid).await {
|
||||
match subkernel::upload(sid).await {
|
||||
Ok(_) => (),
|
||||
Err(_) => return Err(Error::UnexpectedPattern),
|
||||
}
|
||||
@ -822,8 +957,6 @@ async fn handle_connection(
|
||||
stream: &mut TcpStream,
|
||||
control: Rc<RefCell<kernel::Control>>,
|
||||
up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>,
|
||||
aux_mutex: &Rc<Mutex<bool>>,
|
||||
routing_table: &drtio_routing::RoutingTable,
|
||||
) -> Result<()> {
|
||||
stream.set_ack_delay(None);
|
||||
|
||||
@ -851,7 +984,7 @@ async fn handle_connection(
|
||||
load_kernel(&buffer, &control, Some(stream)).await?;
|
||||
}
|
||||
Request::RunKernel => {
|
||||
handle_run_kernel(Some(stream), &control, &up_destinations, aux_mutex, routing_table).await?;
|
||||
handle_run_kernel(Some(stream), &control, &up_destinations).await?;
|
||||
}
|
||||
Request::UploadSubkernel => {
|
||||
#[cfg(has_drtio)]
|
||||
@ -860,7 +993,7 @@ async fn handle_connection(
|
||||
let destination = read_i8(stream).await? as u8;
|
||||
let buffer = read_bytes(stream, 1024 * 1024).await?;
|
||||
subkernel::add_subkernel(id, destination, buffer).await;
|
||||
match subkernel::upload(aux_mutex, routing_table, id).await {
|
||||
match subkernel::upload(id).await {
|
||||
Ok(_) => write_header(stream, Reply::LoadCompleted).await?,
|
||||
Err(_) => {
|
||||
write_header(stream, Reply::LoadFailed).await?;
|
||||
@ -925,57 +1058,41 @@ pub fn main() {
|
||||
|
||||
Sockets::init(32);
|
||||
|
||||
let aux_mutex: Rc<Mutex<bool>> = Rc::new(Mutex::new(false));
|
||||
#[cfg(has_drtio)]
|
||||
let drtio_routing_table = Rc::new(RefCell::new(drtio_routing::config_routing_table(pl::csr::DRTIO.len())));
|
||||
let res = ROUTING_TABLE.set(drtio_routing::config_routing_table(pl::csr::DRTIO.len()));
|
||||
#[cfg(not(has_drtio))]
|
||||
let drtio_routing_table = Rc::new(RefCell::new(drtio_routing::RoutingTable::default_empty()));
|
||||
let res = ROUTING_TABLE.set(drtio_routing::RoutingTable::default_empty());
|
||||
res.expect("routing_table can only be initialized once");
|
||||
|
||||
let up_destinations = Rc::new(RefCell::new([false; drtio_routing::DEST_COUNT]));
|
||||
#[cfg(has_drtio_routing)]
|
||||
drtio_routing::interconnect_disable_all();
|
||||
|
||||
rtio_mgt::startup(&aux_mutex, &drtio_routing_table, &up_destinations);
|
||||
ksupport::setup_device_map();
|
||||
task::spawn(report_async_rtio_errors());
|
||||
rtio_mgt::startup(&up_destinations);
|
||||
libboard_artiq::setup_device_map();
|
||||
|
||||
analyzer::start(&aux_mutex, &drtio_routing_table, &up_destinations);
|
||||
moninj::start(&aux_mutex, &drtio_routing_table);
|
||||
analyzer::start(&up_destinations);
|
||||
moninj::start();
|
||||
|
||||
let control: Rc<RefCell<kernel::Control>> = Rc::new(RefCell::new(kernel::Control::start()));
|
||||
if let Ok(buffer) = libconfig::read("startup_kernel") {
|
||||
info!("Loading startup kernel...");
|
||||
let routing_table = drtio_routing_table.borrow();
|
||||
if let Ok(()) = task::block_on(handle_flash_kernel(
|
||||
&buffer,
|
||||
&control,
|
||||
&up_destinations,
|
||||
&aux_mutex,
|
||||
&routing_table,
|
||||
)) {
|
||||
if let Ok(()) = task::block_on(handle_flash_kernel(&buffer, &control, &up_destinations)) {
|
||||
info!("Starting startup kernel...");
|
||||
let _ = task::block_on(handle_run_kernel(
|
||||
None,
|
||||
&control,
|
||||
&up_destinations,
|
||||
&aux_mutex,
|
||||
&routing_table,
|
||||
));
|
||||
let _ = task::block_on(handle_run_kernel(None, &control, &up_destinations));
|
||||
info!("Startup kernel finished!");
|
||||
} else {
|
||||
error!("Error loading startup kernel!");
|
||||
}
|
||||
}
|
||||
|
||||
let restart_idle = Rc::new(Semaphore::new(1, 1));
|
||||
mgmt::start(
|
||||
restart_idle.clone(),
|
||||
Some(mgmt::DrtioContext(aux_mutex.clone(), drtio_routing_table.clone())),
|
||||
);
|
||||
mgmt::start();
|
||||
|
||||
task::spawn(async move {
|
||||
let connection = Rc::new(Semaphore::new(1, 1));
|
||||
let terminate = Rc::new(Semaphore::new(0, 1));
|
||||
let can_restart_idle = Rc::new(Semaphore::new(1, 1));
|
||||
let restart_idle = restart_idle.clone();
|
||||
loop {
|
||||
let control = control.clone();
|
||||
let mut maybe_stream = select_biased! {
|
||||
@ -983,7 +1100,7 @@ pub fn main() {
|
||||
TcpStream::accept(1381, 0x10_000, 0x10_000).await.unwrap()
|
||||
}).fuse() => Some(s),
|
||||
_ = (async {
|
||||
restart_idle.async_wait().await;
|
||||
RESTART_IDLE.async_wait().await;
|
||||
can_restart_idle.async_wait().await;
|
||||
}).fuse() => None
|
||||
};
|
||||
@ -1004,18 +1121,15 @@ pub fn main() {
|
||||
let terminate = terminate.clone();
|
||||
let can_restart_idle = can_restart_idle.clone();
|
||||
let up_destinations = up_destinations.clone();
|
||||
let aux_mutex = aux_mutex.clone();
|
||||
let routing_table = drtio_routing_table.clone();
|
||||
|
||||
// we make sure the value of terminate is 0 before we start
|
||||
let _ = terminate.try_wait();
|
||||
let _ = can_restart_idle.try_wait();
|
||||
task::spawn(async move {
|
||||
let routing_table = routing_table.borrow();
|
||||
select_biased! {
|
||||
_ = (async {
|
||||
if let Some(stream) = &mut maybe_stream {
|
||||
let _ = handle_connection(stream, control.clone(), &up_destinations, &aux_mutex, &routing_table)
|
||||
let _ = handle_connection(stream, control.clone(), &up_destinations)
|
||||
.await
|
||||
.map_err(|e| warn!("connection terminated: {}", e));
|
||||
}
|
||||
@ -1024,10 +1138,10 @@ pub fn main() {
|
||||
Some(buffer) => {
|
||||
loop {
|
||||
info!("loading idle kernel");
|
||||
match handle_flash_kernel(&buffer, &control, &up_destinations, &aux_mutex, &routing_table).await {
|
||||
match handle_flash_kernel(&buffer, &control, &up_destinations).await {
|
||||
Ok(_) => {
|
||||
info!("running idle kernel");
|
||||
match handle_run_kernel(None, &control, &up_destinations, &aux_mutex, &routing_table).await {
|
||||
match handle_run_kernel(None, &control, &up_destinations).await {
|
||||
Ok(_) => info!("idle kernel finished"),
|
||||
Err(_) => warn!("idle kernel running error")
|
||||
}
|
||||
@ -1110,8 +1224,7 @@ pub fn soft_panic_main() -> ! {
|
||||
|
||||
Sockets::init(32);
|
||||
|
||||
let dummy = Rc::new(Semaphore::new(0, 1));
|
||||
mgmt::start(dummy, None);
|
||||
mgmt::start();
|
||||
|
||||
// getting eth settings disables the LED as it resets GPIO
|
||||
// need to re-enable it here
|
||||
|
||||
@ -20,12 +20,12 @@ use libboard_artiq::drtio_eem;
|
||||
use libboard_artiq::io_expander;
|
||||
#[cfg(has_cxp_grabber)]
|
||||
use libboard_artiq::{cxp_grabber, cxp_phys};
|
||||
use libboard_artiq::{identifier_read, logger, pl};
|
||||
use libboard_artiq::{i2c, identifier_read, logger, pl};
|
||||
use libboard_zynq::{gic, mpcore, timer};
|
||||
use libconfig;
|
||||
use libcortex_a9::l2c::enable_l2_cache;
|
||||
use libsupport_zynq::{exception_vectors, ram};
|
||||
use log::{info, warn};
|
||||
use log::{LevelFilter, info, warn};
|
||||
|
||||
mod analyzer;
|
||||
mod comms;
|
||||
@ -78,6 +78,29 @@ mod grabber {
|
||||
}
|
||||
}
|
||||
|
||||
fn setup_log_levels() {
|
||||
if let Ok(level_string) = libconfig::read_str("log_level") {
|
||||
if let Ok(level) = level_string.parse::<LevelFilter>() {
|
||||
info!("log level set to {} by `log_level` config key", level);
|
||||
logger::BufferLogger::get_logger().set_buffer_log_level(level);
|
||||
} else {
|
||||
info!("log level set to INFO by default");
|
||||
}
|
||||
} else {
|
||||
info!("log level set to INFO by default");
|
||||
}
|
||||
if let Ok(level_string) = libconfig::read_str("uart_log_level") {
|
||||
if let Ok(level) = level_string.parse::<LevelFilter>() {
|
||||
info!("UART log level set to {} by `uart_log_level` config key", level);
|
||||
logger::BufferLogger::get_logger().set_uart_log_level(level);
|
||||
} else {
|
||||
info!("UART log level set to INFO by default");
|
||||
}
|
||||
} else {
|
||||
info!("UART log level set to INFO by default");
|
||||
}
|
||||
}
|
||||
|
||||
static mut LOG_BUFFER: [u8; 1 << 17] = [0; 1 << 17];
|
||||
|
||||
#[no_mangle]
|
||||
@ -88,10 +111,9 @@ pub fn main_core0() {
|
||||
enable_l2_cache(0x8);
|
||||
timer::start();
|
||||
|
||||
let buffer_logger = unsafe { logger::BufferLogger::new(&mut LOG_BUFFER[..]) };
|
||||
buffer_logger.set_uart_log_level(log::LevelFilter::Info);
|
||||
let buffer_logger = unsafe { libboard_artiq::logger::BufferLogger::new(&mut LOG_BUFFER[..]) };
|
||||
buffer_logger.register();
|
||||
log::set_max_level(log::LevelFilter::Info);
|
||||
log::set_max_level(log::LevelFilter::Trace);
|
||||
|
||||
info!("NAR3/Zynq7000 starting...");
|
||||
|
||||
@ -100,10 +122,10 @@ pub fn main_core0() {
|
||||
|
||||
info!("gateware ident: {}", identifier_read(&mut [0; 64]));
|
||||
|
||||
ksupport::kernel::i2c::init();
|
||||
i2c::init();
|
||||
#[cfg(feature = "target_kasli_soc")]
|
||||
{
|
||||
let i2c_bus = ksupport::kernel::i2c::get_bus();
|
||||
let i2c_bus = i2c::get_bus();
|
||||
let mut io_expander0 = io_expander::IoExpander::new(i2c_bus, 0).unwrap();
|
||||
let mut io_expander1 = io_expander::IoExpander::new(i2c_bus, 1).unwrap();
|
||||
io_expander0
|
||||
@ -122,8 +144,14 @@ pub fn main_core0() {
|
||||
io_expander1.set(0, 1, false);
|
||||
io_expander0.set(1, 1, false);
|
||||
io_expander1.set(1, 1, false);
|
||||
|
||||
// Enable EEM power
|
||||
#[cfg(hw_rev = "v1.2")]
|
||||
io_expander1.set(0, 7, true);
|
||||
|
||||
io_expander0.service(i2c_bus).unwrap();
|
||||
io_expander1.service(i2c_bus).unwrap();
|
||||
|
||||
#[cfg(has_virtual_leds)]
|
||||
task::spawn(io_expanders_service(
|
||||
RefCell::new(i2c_bus),
|
||||
@ -135,6 +163,9 @@ pub fn main_core0() {
|
||||
if let Err(err) = libconfig::init() {
|
||||
warn!("config initialization failed: {}", err);
|
||||
}
|
||||
|
||||
setup_log_levels();
|
||||
|
||||
rtio_clocking::init();
|
||||
|
||||
#[cfg(has_drtio_eem)]
|
||||
@ -143,12 +174,10 @@ pub fn main_core0() {
|
||||
#[cfg(has_grabber)]
|
||||
task::spawn(grabber::grabber_thread());
|
||||
|
||||
task::spawn(ksupport::report_async_rtio_errors());
|
||||
|
||||
#[cfg(has_cxp_grabber)]
|
||||
{
|
||||
cxp_phys::setup();
|
||||
task::spawn(cxp_grabber::thread(ksupport::kernel::i2c::get_bus()));
|
||||
task::spawn(cxp_grabber::thread(i2c::get_bus()));
|
||||
}
|
||||
|
||||
comms::main();
|
||||
|
||||
@ -1,27 +1,29 @@
|
||||
use alloc::{rc::Rc, string::String, vec::Vec};
|
||||
use core::cell::RefCell;
|
||||
use core::{cell::RefCell, str::Utf8Error};
|
||||
|
||||
use byteorder::{ByteOrder, NativeEndian};
|
||||
use crc::crc32;
|
||||
use futures::{future::poll_fn, task::Poll};
|
||||
use libasync::{smoltcp::TcpStream, task};
|
||||
use libboard_artiq::{drtio_routing::RoutingTable,
|
||||
logger::{BufferLogger, LogBufferRef}};
|
||||
#[cfg(has_drtio)]
|
||||
use libboard_artiq::drtio_routing;
|
||||
use libboard_artiq::logger::{BufferLogger, LogBufferRef};
|
||||
use libboard_zynq::smoltcp;
|
||||
use libconfig;
|
||||
use libcortex_a9::{mutex::Mutex, semaphore::Semaphore};
|
||||
use log::{self, debug, error, info, warn};
|
||||
use num_derive::FromPrimitive;
|
||||
use num_traits::FromPrimitive;
|
||||
|
||||
use crate::proto_async::*;
|
||||
use crate::{comms::RESTART_IDLE, proto_async::*};
|
||||
#[cfg(has_drtio)]
|
||||
use crate::rtio_mgt::drtio;
|
||||
use crate::{comms::ROUTING_TABLE, rtio_mgt::drtio};
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum Error {
|
||||
NetworkError(smoltcp::Error),
|
||||
UnknownLogLevel(u8),
|
||||
OvertakeError,
|
||||
UnknownLogLevel(),
|
||||
Utf8(Utf8Error),
|
||||
UnexpectedPattern,
|
||||
UnrecognizedPacket,
|
||||
#[cfg(has_drtio)]
|
||||
@ -34,7 +36,9 @@ impl core::fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
|
||||
match self {
|
||||
&Error::NetworkError(error) => write!(f, "network error: {}", error),
|
||||
&Error::UnknownLogLevel(lvl) => write!(f, "unknown log level {}", lvl),
|
||||
&Error::OvertakeError => write!(f, "connection overtaken"),
|
||||
&Error::UnknownLogLevel() => write!(f, "unknown log level"),
|
||||
&Error::Utf8(error) => write!(f, "invalid UTF-8: {}", error),
|
||||
&Error::UnexpectedPattern => write!(f, "unexpected pattern"),
|
||||
&Error::UnrecognizedPacket => write!(f, "unrecognized packet"),
|
||||
#[cfg(has_drtio)]
|
||||
@ -49,6 +53,12 @@ impl From<smoltcp::Error> for Error {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Utf8Error> for Error {
|
||||
fn from(error: Utf8Error) -> Self {
|
||||
Error::Utf8(error)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(has_drtio)]
|
||||
impl From<drtio::Error> for Error {
|
||||
fn from(error: drtio::Error) -> Self {
|
||||
@ -61,9 +71,7 @@ pub enum Request {
|
||||
GetLog = 1,
|
||||
ClearLog = 2,
|
||||
PullLog = 7,
|
||||
SetLogFilter = 3,
|
||||
Reboot = 5,
|
||||
SetUartLogFilter = 6,
|
||||
|
||||
ConfigRead = 12,
|
||||
ConfigWrite = 13,
|
||||
@ -84,18 +92,6 @@ pub enum Reply {
|
||||
ConfigData = 7,
|
||||
}
|
||||
|
||||
async fn read_log_level_filter(stream: &mut TcpStream) -> Result<log::LevelFilter> {
|
||||
Ok(match read_i8(stream).await? {
|
||||
0 => log::LevelFilter::Off,
|
||||
1 => log::LevelFilter::Error,
|
||||
2 => log::LevelFilter::Warn,
|
||||
3 => log::LevelFilter::Info,
|
||||
4 => log::LevelFilter::Debug,
|
||||
5 => log::LevelFilter::Trace,
|
||||
lv => return Err(Error::UnknownLogLevel(lv as u8)),
|
||||
})
|
||||
}
|
||||
|
||||
async fn get_logger_buffer_pred<F>(f: F) -> LogBufferRef<'static>
|
||||
where F: Fn(&LogBufferRef) -> bool {
|
||||
poll_fn(|ctx| {
|
||||
@ -142,19 +138,11 @@ mod remote_coremgmt {
|
||||
|
||||
use super::*;
|
||||
|
||||
pub async fn get_log(
|
||||
stream: &mut TcpStream,
|
||||
aux_mutex: &Rc<Mutex<bool>>,
|
||||
routing_table: &RoutingTable,
|
||||
linkno: u8,
|
||||
destination: u8,
|
||||
) -> Result<()> {
|
||||
pub async fn get_log(stream: &mut TcpStream, linkno: u8, destination: u8) -> Result<()> {
|
||||
let mut buffer = Vec::new();
|
||||
loop {
|
||||
let reply = drtio::aux_transact(
|
||||
aux_mutex,
|
||||
linkno,
|
||||
routing_table,
|
||||
&Packet::CoreMgmtGetLogRequest {
|
||||
destination,
|
||||
clear: false,
|
||||
@ -185,20 +173,8 @@ mod remote_coremgmt {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn clear_log(
|
||||
stream: &mut TcpStream,
|
||||
aux_mutex: &Rc<Mutex<bool>>,
|
||||
routing_table: &RoutingTable,
|
||||
linkno: u8,
|
||||
destination: u8,
|
||||
) -> Result<()> {
|
||||
let reply = drtio::aux_transact(
|
||||
aux_mutex,
|
||||
linkno,
|
||||
routing_table,
|
||||
&Packet::CoreMgmtClearLogRequest { destination },
|
||||
)
|
||||
.await;
|
||||
pub async fn clear_log(stream: &mut TcpStream, linkno: u8, destination: u8) -> Result<()> {
|
||||
let reply = drtio::aux_transact(linkno, &Packet::CoreMgmtClearLogRequest { destination }).await;
|
||||
|
||||
match reply {
|
||||
Ok(Packet::CoreMgmtReply { succeeded: true }) => {
|
||||
@ -218,14 +194,7 @@ mod remote_coremgmt {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn pull_log(
|
||||
stream: &mut TcpStream,
|
||||
aux_mutex: &Rc<Mutex<bool>>,
|
||||
routing_table: &RoutingTable,
|
||||
linkno: u8,
|
||||
destination: u8,
|
||||
pull_id: &Rc<RefCell<u32>>,
|
||||
) -> Result<()> {
|
||||
pub async fn pull_log(stream: &mut TcpStream, linkno: u8, destination: u8, pull_id: &RefCell<u32>) -> Result<()> {
|
||||
let id = {
|
||||
let mut guard = pull_id.borrow_mut();
|
||||
*guard += 1;
|
||||
@ -237,13 +206,11 @@ mod remote_coremgmt {
|
||||
if id != *pull_id.borrow() {
|
||||
// another connection attempts to pull the log...
|
||||
// abort this connection...
|
||||
break;
|
||||
return Err(Error::OvertakeError);
|
||||
}
|
||||
|
||||
let reply = drtio::aux_transact(
|
||||
aux_mutex,
|
||||
linkno,
|
||||
routing_table,
|
||||
&Packet::CoreMgmtGetLogRequest {
|
||||
destination,
|
||||
clear: true,
|
||||
@ -270,100 +237,15 @@ mod remote_coremgmt {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn set_log_filter(
|
||||
stream: &mut TcpStream,
|
||||
aux_mutex: &Rc<Mutex<bool>>,
|
||||
routing_table: &RoutingTable,
|
||||
linkno: u8,
|
||||
destination: u8,
|
||||
level: log::LevelFilter,
|
||||
) -> Result<()> {
|
||||
let reply = drtio::aux_transact(
|
||||
aux_mutex,
|
||||
linkno,
|
||||
routing_table,
|
||||
&Packet::CoreMgmtSetLogLevelRequest {
|
||||
destination,
|
||||
log_level: level as u8,
|
||||
},
|
||||
)
|
||||
.await;
|
||||
|
||||
match reply {
|
||||
Ok(Packet::CoreMgmtReply { succeeded: true }) => {
|
||||
write_i8(stream, Reply::Success as i8).await?;
|
||||
Ok(())
|
||||
}
|
||||
Ok(packet) => {
|
||||
error!("received unexpected aux packet: {:?}", packet);
|
||||
write_i8(stream, Reply::Error as i8).await?;
|
||||
Err(drtio::Error::UnexpectedReply.into())
|
||||
}
|
||||
Err(e) => {
|
||||
error!("aux packet error ({})", e);
|
||||
write_i8(stream, Reply::Error as i8).await?;
|
||||
Err(e.into())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn set_uart_log_filter(
|
||||
stream: &mut TcpStream,
|
||||
aux_mutex: &Rc<Mutex<bool>>,
|
||||
routing_table: &RoutingTable,
|
||||
linkno: u8,
|
||||
destination: u8,
|
||||
level: log::LevelFilter,
|
||||
) -> Result<()> {
|
||||
let reply = drtio::aux_transact(
|
||||
aux_mutex,
|
||||
linkno,
|
||||
routing_table,
|
||||
&Packet::CoreMgmtSetUartLogLevelRequest {
|
||||
destination,
|
||||
log_level: level as u8,
|
||||
},
|
||||
)
|
||||
.await;
|
||||
|
||||
match reply {
|
||||
Ok(Packet::CoreMgmtReply { succeeded: true }) => {
|
||||
write_i8(stream, Reply::Success as i8).await?;
|
||||
Ok(())
|
||||
}
|
||||
Ok(packet) => {
|
||||
error!("received unexpected aux packet: {:?}", packet);
|
||||
write_i8(stream, Reply::Error as i8).await?;
|
||||
Err(drtio::Error::UnexpectedReply.into())
|
||||
}
|
||||
Err(e) => {
|
||||
error!("aux packet error ({})", e);
|
||||
write_i8(stream, Reply::Error as i8).await?;
|
||||
Err(e.into())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn config_read(
|
||||
stream: &mut TcpStream,
|
||||
aux_mutex: &Rc<Mutex<bool>>,
|
||||
routing_table: &RoutingTable,
|
||||
linkno: u8,
|
||||
destination: u8,
|
||||
key: &String,
|
||||
) -> Result<()> {
|
||||
pub async fn config_read(stream: &mut TcpStream, linkno: u8, destination: u8, key: &String) -> Result<()> {
|
||||
let mut config_key: [u8; MASTER_PAYLOAD_MAX_SIZE] = [0; MASTER_PAYLOAD_MAX_SIZE];
|
||||
let len = key.len();
|
||||
config_key[..len].clone_from_slice(key.as_bytes());
|
||||
|
||||
let mut reply = drtio::aux_transact(
|
||||
aux_mutex,
|
||||
linkno,
|
||||
routing_table,
|
||||
&Packet::CoreMgmtConfigReadRequest {
|
||||
destination: destination,
|
||||
length: len as u16,
|
||||
@ -385,9 +267,7 @@ mod remote_coremgmt {
|
||||
}
|
||||
|
||||
reply = drtio::aux_transact(
|
||||
aux_mutex,
|
||||
linkno,
|
||||
routing_table,
|
||||
&Packet::CoreMgmtConfigReadContinue {
|
||||
destination: destination,
|
||||
},
|
||||
@ -410,13 +290,10 @@ mod remote_coremgmt {
|
||||
|
||||
pub async fn config_write(
|
||||
stream: &mut TcpStream,
|
||||
aux_mutex: &Rc<Mutex<bool>>,
|
||||
routing_table: &RoutingTable,
|
||||
linkno: u8,
|
||||
destination: u8,
|
||||
key: &String,
|
||||
value: Vec<u8>,
|
||||
_restart_idle: &Rc<Semaphore>,
|
||||
) -> Result<()> {
|
||||
let mut message = Vec::with_capacity(key.len() + value.len() + 4 * 2);
|
||||
message.write_string::<NativeEndian>(key).unwrap();
|
||||
@ -424,8 +301,6 @@ mod remote_coremgmt {
|
||||
|
||||
match drtio::partition_data(
|
||||
linkno,
|
||||
aux_mutex,
|
||||
routing_table,
|
||||
&message,
|
||||
|slice, status, len: usize| Packet::CoreMgmtConfigWriteRequest {
|
||||
destination: destination,
|
||||
@ -455,23 +330,13 @@ mod remote_coremgmt {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn config_remove(
|
||||
stream: &mut TcpStream,
|
||||
aux_mutex: &Rc<Mutex<bool>>,
|
||||
routing_table: &RoutingTable,
|
||||
linkno: u8,
|
||||
destination: u8,
|
||||
key: &String,
|
||||
_restart_idle: &Rc<Semaphore>,
|
||||
) -> Result<()> {
|
||||
pub async fn config_remove(stream: &mut TcpStream, linkno: u8, destination: u8, key: &String) -> Result<()> {
|
||||
let mut config_key: [u8; MASTER_PAYLOAD_MAX_SIZE] = [0; MASTER_PAYLOAD_MAX_SIZE];
|
||||
let len = key.len();
|
||||
config_key[..len].clone_from_slice(key.as_bytes());
|
||||
|
||||
let reply = drtio::aux_transact(
|
||||
aux_mutex,
|
||||
linkno,
|
||||
routing_table,
|
||||
&Packet::CoreMgmtConfigRemoveRequest {
|
||||
destination: destination,
|
||||
length: len as u16,
|
||||
@ -498,17 +363,9 @@ mod remote_coremgmt {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn config_erase(
|
||||
stream: &mut TcpStream,
|
||||
aux_mutex: &Rc<Mutex<bool>>,
|
||||
routing_table: &RoutingTable,
|
||||
linkno: u8,
|
||||
destination: u8,
|
||||
) -> Result<()> {
|
||||
pub async fn config_erase(stream: &mut TcpStream, linkno: u8, destination: u8) -> Result<()> {
|
||||
let reply = drtio::aux_transact(
|
||||
aux_mutex,
|
||||
linkno,
|
||||
routing_table,
|
||||
&Packet::CoreMgmtConfigEraseRequest {
|
||||
destination: destination,
|
||||
},
|
||||
@ -533,17 +390,9 @@ mod remote_coremgmt {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn reboot(
|
||||
stream: &mut TcpStream,
|
||||
aux_mutex: &Rc<Mutex<bool>>,
|
||||
routing_table: &RoutingTable,
|
||||
linkno: u8,
|
||||
destination: u8,
|
||||
) -> Result<()> {
|
||||
pub async fn reboot(stream: &mut TcpStream, linkno: u8, destination: u8) -> Result<()> {
|
||||
let reply = drtio::aux_transact(
|
||||
aux_mutex,
|
||||
linkno,
|
||||
routing_table,
|
||||
&Packet::CoreMgmtRebootRequest {
|
||||
destination: destination,
|
||||
},
|
||||
@ -568,17 +417,9 @@ mod remote_coremgmt {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn debug_allocator(
|
||||
stream: &mut TcpStream,
|
||||
aux_mutex: &Rc<Mutex<bool>>,
|
||||
routing_table: &RoutingTable,
|
||||
linkno: u8,
|
||||
destination: u8,
|
||||
) -> Result<()> {
|
||||
pub async fn debug_allocator(stream: &mut TcpStream, linkno: u8, destination: u8) -> Result<()> {
|
||||
let reply = drtio::aux_transact(
|
||||
aux_mutex,
|
||||
linkno,
|
||||
routing_table,
|
||||
&Packet::CoreMgmtAllocatorDebugRequest {
|
||||
destination: destination,
|
||||
},
|
||||
@ -601,20 +442,11 @@ mod remote_coremgmt {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn image_write(
|
||||
stream: &mut TcpStream,
|
||||
aux_mutex: &Rc<Mutex<bool>>,
|
||||
routing_table: &RoutingTable,
|
||||
linkno: u8,
|
||||
destination: u8,
|
||||
image: Vec<u8>,
|
||||
) -> Result<()> {
|
||||
pub async fn image_write(stream: &mut TcpStream, linkno: u8, destination: u8, image: Vec<u8>) -> Result<()> {
|
||||
let mut image = &image[..];
|
||||
|
||||
let alloc_reply = drtio::aux_transact(
|
||||
aux_mutex,
|
||||
linkno,
|
||||
routing_table,
|
||||
&Packet::CoreMgmtFlashRequest {
|
||||
destination: destination,
|
||||
payload_length: image.len() as u32,
|
||||
@ -642,9 +474,7 @@ mod remote_coremgmt {
|
||||
let last = image.is_empty();
|
||||
|
||||
let reply = drtio::aux_transact(
|
||||
aux_mutex,
|
||||
linkno,
|
||||
routing_table,
|
||||
&Packet::CoreMgmtFlashAddDataRequest {
|
||||
destination: destination,
|
||||
last: last,
|
||||
@ -701,7 +531,7 @@ mod local_coremgmt {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn pull_log(stream: &mut TcpStream, pull_id: &Rc<RefCell<u32>>) -> Result<()> {
|
||||
pub async fn pull_log(stream: &mut TcpStream, pull_id: &RefCell<u32>) -> Result<()> {
|
||||
let id = {
|
||||
let mut guard = pull_id.borrow_mut();
|
||||
*guard += 1;
|
||||
@ -712,35 +542,19 @@ mod local_coremgmt {
|
||||
if id != *pull_id.borrow() {
|
||||
// another connection attempts to pull the log...
|
||||
// abort this connection...
|
||||
break;
|
||||
return Err(Error::OvertakeError);
|
||||
}
|
||||
let bytes = buffer.extract().as_bytes().to_vec();
|
||||
buffer.clear();
|
||||
core::mem::drop(buffer);
|
||||
write_chunk(stream, &bytes).await?;
|
||||
if log::max_level() == log::LevelFilter::Trace {
|
||||
// temporarily discard all trace level log
|
||||
if BufferLogger::get_logger().buffer_log_level() == log::LevelFilter::Trace {
|
||||
let logger = BufferLogger::get_logger();
|
||||
logger.set_buffer_log_level(log::LevelFilter::Debug);
|
||||
stream.flush().await?;
|
||||
logger.set_buffer_log_level(log::LevelFilter::Trace);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn set_log_filter(stream: &mut TcpStream, lvl: log::LevelFilter) -> Result<()> {
|
||||
info!("Changing log level to {}", lvl);
|
||||
log::set_max_level(lvl);
|
||||
write_i8(stream, Reply::Success as i8).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn set_uart_log_filter(stream: &mut TcpStream, lvl: log::LevelFilter) -> Result<()> {
|
||||
info!("Changing UART log level to {}", lvl);
|
||||
BufferLogger::get_logger().set_uart_log_level(lvl);
|
||||
write_i8(stream, Reply::Success as i8).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn config_read(stream: &mut TcpStream, key: &String) -> Result<()> {
|
||||
@ -756,34 +570,46 @@ mod local_coremgmt {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn config_write(
|
||||
stream: &mut TcpStream,
|
||||
key: &String,
|
||||
value: Vec<u8>,
|
||||
restart_idle: &Rc<Semaphore>,
|
||||
) -> Result<()> {
|
||||
let value = libconfig::write(&key, value);
|
||||
if value.is_ok() {
|
||||
pub async fn config_write(stream: &mut TcpStream, key: &String, value: Vec<u8>) -> Result<()> {
|
||||
let res = libconfig::write(&key, value.clone());
|
||||
if res.is_ok() {
|
||||
debug!("write success");
|
||||
if key == "idle_kernel" {
|
||||
restart_idle.signal();
|
||||
match key.as_str() {
|
||||
"idle_kernel" => {
|
||||
RESTART_IDLE.signal();
|
||||
}
|
||||
"log_level" | "uart_log_level" => {
|
||||
let value_str = core::str::from_utf8(&value).map_err(Error::from)?;
|
||||
let max_level = value_str
|
||||
.parse::<log::LevelFilter>()
|
||||
.map_err(|_| Error::UnknownLogLevel())?;
|
||||
|
||||
if key == "log_level" {
|
||||
BufferLogger::get_logger().set_buffer_log_level(max_level);
|
||||
info!("changing log level to {}", max_level);
|
||||
} else {
|
||||
BufferLogger::get_logger().set_uart_log_level(max_level);
|
||||
info!("changing UART log level to {}", max_level);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
write_i8(stream, Reply::Success as i8).await?;
|
||||
} else {
|
||||
// this is an error because we do not expect write to fail
|
||||
error!("failed to write: {:?}", value);
|
||||
error!("failed to write: {:?}", res);
|
||||
write_i8(stream, Reply::Error as i8).await?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn config_remove(stream: &mut TcpStream, key: &String, restart_idle: &Rc<Semaphore>) -> Result<()> {
|
||||
pub async fn config_remove(stream: &mut TcpStream, key: &String) -> Result<()> {
|
||||
debug!("erase key: {}", key);
|
||||
let value = libconfig::remove(&key);
|
||||
if value.is_ok() {
|
||||
debug!("erase success");
|
||||
if key == "idle_kernel" {
|
||||
restart_idle.signal();
|
||||
RESTART_IDLE.signal();
|
||||
}
|
||||
write_i8(stream, Reply::Success as i8).await?;
|
||||
} else {
|
||||
@ -801,6 +627,7 @@ mod local_coremgmt {
|
||||
|
||||
pub async fn reboot(stream: &mut TcpStream) -> Result<()> {
|
||||
info!("rebooting");
|
||||
log::logger().flush();
|
||||
write_i8(stream, Reply::RebootImminent as i8).await?;
|
||||
stream.flush().await?;
|
||||
slcr::reboot();
|
||||
@ -843,38 +670,25 @@ mod local_coremgmt {
|
||||
|
||||
#[cfg(has_drtio)]
|
||||
macro_rules! process {
|
||||
($stream: ident, $drtio_context:ident, $destination:expr, $func:ident $(, $param:expr)*) => {{
|
||||
if $destination == 0 {
|
||||
($stream: ident, $destination:expr, $func:ident $(, $param:expr)*) => {{
|
||||
let hop = ROUTING_TABLE.get().unwrap().0[$destination as usize][0];
|
||||
let linkno = hop - 1 as u8;
|
||||
if hop == 0 {
|
||||
local_coremgmt::$func($stream, $($param, )*).await
|
||||
} else if let Some(DrtioContext(ref aux_mutex, ref routing_table)) = $drtio_context {
|
||||
let routing_table = routing_table.borrow();
|
||||
let linkno = routing_table.0[$destination as usize][0] - 1 as u8;
|
||||
remote_coremgmt::$func($stream, &aux_mutex, &routing_table, linkno, $destination, $($param, )*).await
|
||||
} else {
|
||||
error!("coremgmt-over-drtio not supported for panicked device, please reboot");
|
||||
write_i8($stream, Reply::Error as i8).await?;
|
||||
Err(drtio::Error::LinkDown.into())
|
||||
remote_coremgmt::$func($stream, linkno, $destination, $($param, )*).await
|
||||
}
|
||||
}}
|
||||
}
|
||||
|
||||
#[cfg(not(has_drtio))]
|
||||
macro_rules! process {
|
||||
($stream: ident, $drtio_context:ident, $destination:expr, $func:ident $(, $param:expr)*) => {{
|
||||
($stream: ident, $destination:expr, $func:ident $(, $param:expr)*) => {{
|
||||
local_coremgmt::$func($stream, $($param, )*).await
|
||||
}}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Clone)]
|
||||
pub struct DrtioContext(pub Rc<Mutex<bool>>, pub Rc<RefCell<RoutingTable>>);
|
||||
|
||||
async fn handle_connection(
|
||||
stream: &mut TcpStream,
|
||||
pull_id: Rc<RefCell<u32>>,
|
||||
restart_idle: Rc<Semaphore>,
|
||||
_drtio_context: Option<DrtioContext>,
|
||||
) -> Result<()> {
|
||||
async fn handle_connection(stream: &mut TcpStream, pull_ids: Rc<[RefCell<u32>]>) -> Result<()> {
|
||||
if !expect(&stream, b"ARTIQ management\n").await? {
|
||||
return Err(Error::UnexpectedPattern);
|
||||
}
|
||||
@ -882,6 +696,8 @@ async fn handle_connection(
|
||||
let _destination: u8 = read_i8(stream).await? as u8;
|
||||
stream.send_slice("e".as_bytes()).await?;
|
||||
|
||||
let pull_id = &pull_ids[_destination as usize];
|
||||
|
||||
loop {
|
||||
let msg = read_i8(stream).await;
|
||||
if let Err(smoltcp::Error::Finished) = msg {
|
||||
@ -889,20 +705,12 @@ async fn handle_connection(
|
||||
}
|
||||
let msg: Request = FromPrimitive::from_i8(msg?).ok_or(Error::UnrecognizedPacket)?;
|
||||
match msg {
|
||||
Request::GetLog => process!(stream, _drtio_context, _destination, get_log),
|
||||
Request::ClearLog => process!(stream, _drtio_context, _destination, clear_log),
|
||||
Request::PullLog => process!(stream, _drtio_context, _destination, pull_log, &pull_id),
|
||||
Request::SetLogFilter => {
|
||||
let lvl = read_log_level_filter(stream).await?;
|
||||
process!(stream, _drtio_context, _destination, set_log_filter, lvl)
|
||||
}
|
||||
Request::SetUartLogFilter => {
|
||||
let lvl = read_log_level_filter(stream).await?;
|
||||
process!(stream, _drtio_context, _destination, set_uart_log_filter, lvl)
|
||||
}
|
||||
Request::GetLog => process!(stream, _destination, get_log),
|
||||
Request::ClearLog => process!(stream, _destination, clear_log),
|
||||
Request::PullLog => process!(stream, _destination, pull_log, pull_id),
|
||||
Request::ConfigRead => {
|
||||
let key = read_key(stream).await?;
|
||||
process!(stream, _drtio_context, _destination, config_read, &key)
|
||||
process!(stream, _destination, config_read, &key)
|
||||
}
|
||||
Request::ConfigWrite => {
|
||||
let key = read_key(stream).await?;
|
||||
@ -913,28 +721,20 @@ async fn handle_connection(
|
||||
buffer.set_len(len);
|
||||
}
|
||||
read_chunk(stream, &mut buffer).await?;
|
||||
process!(
|
||||
stream,
|
||||
_drtio_context,
|
||||
_destination,
|
||||
config_write,
|
||||
&key,
|
||||
buffer,
|
||||
&restart_idle
|
||||
)
|
||||
process!(stream, _destination, config_write, &key, buffer)
|
||||
}
|
||||
Request::ConfigRemove => {
|
||||
let key = read_key(stream).await?;
|
||||
process!(stream, _drtio_context, _destination, config_remove, &key, &restart_idle)
|
||||
process!(stream, _destination, config_remove, &key)
|
||||
}
|
||||
Request::Reboot => {
|
||||
process!(stream, _drtio_context, _destination, reboot)
|
||||
process!(stream, _destination, reboot)
|
||||
}
|
||||
Request::ConfigErase => {
|
||||
process!(stream, _drtio_context, _destination, config_erase)
|
||||
process!(stream, _destination, config_erase)
|
||||
}
|
||||
Request::DebugAllocator => {
|
||||
process!(stream, _drtio_context, _destination, debug_allocator)
|
||||
process!(stream, _destination, debug_allocator)
|
||||
}
|
||||
Request::Flash => {
|
||||
let len = read_i32(stream).await?;
|
||||
@ -947,23 +747,24 @@ async fn handle_connection(
|
||||
buffer.set_len(len as usize);
|
||||
}
|
||||
read_chunk(stream, &mut buffer).await?;
|
||||
process!(stream, _drtio_context, _destination, image_write, buffer)
|
||||
process!(stream, _destination, image_write, buffer)
|
||||
}
|
||||
}?;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn start(restart_idle: Rc<Semaphore>, drtio_context: Option<DrtioContext>) {
|
||||
pub fn start() {
|
||||
task::spawn(async move {
|
||||
let pull_id = Rc::new(RefCell::new(0u32));
|
||||
#[cfg(has_drtio)]
|
||||
let pull_ids = Rc::new([const { RefCell::new(0u32) }; drtio_routing::DEST_COUNT]);
|
||||
#[cfg(not(has_drtio))]
|
||||
let pull_ids = Rc::new([RefCell::new(0u32); 1]);
|
||||
loop {
|
||||
let mut stream = TcpStream::accept(1380, 2048, 2048).await.unwrap();
|
||||
let pull_id = pull_id.clone();
|
||||
let restart_idle = restart_idle.clone();
|
||||
let drtio_context = drtio_context.clone();
|
||||
let pull_ids = pull_ids.clone();
|
||||
task::spawn(async move {
|
||||
info!("received connection");
|
||||
let _ = handle_connection(&mut stream, pull_id, restart_idle, drtio_context)
|
||||
let _ = handle_connection(&mut stream, pull_ids)
|
||||
.await
|
||||
.map_err(|e| warn!("connection terminated: {:?}", e));
|
||||
let _ = stream.flush().await;
|
||||
|
||||
@ -1,15 +1,15 @@
|
||||
use alloc::{collections::BTreeMap, rc::Rc};
|
||||
use core::{cell::RefCell, fmt};
|
||||
use alloc::collections::BTreeMap;
|
||||
use core::fmt;
|
||||
|
||||
use futures::{FutureExt, pin_mut, select_biased};
|
||||
use libasync::{smoltcp::TcpStream, task};
|
||||
use libboard_artiq::drtio_routing;
|
||||
use libboard_zynq::{smoltcp, timer};
|
||||
use libcortex_a9::mutex::Mutex;
|
||||
use log::{debug, info, warn};
|
||||
use num_derive::{FromPrimitive, ToPrimitive};
|
||||
use num_traits::{FromPrimitive, ToPrimitive};
|
||||
|
||||
#[cfg(has_drtio)]
|
||||
use crate::comms::ROUTING_TABLE;
|
||||
use crate::proto_async::*;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
@ -57,20 +57,11 @@ mod remote_moninj {
|
||||
use log::error;
|
||||
|
||||
use super::*;
|
||||
use crate::rtio_mgt::{drtio, drtio::Error as DrtioError};
|
||||
use crate::rtio_mgt::drtio::{self, AUX_MUTEX, Error as DrtioError};
|
||||
|
||||
pub async fn read_probe(
|
||||
aux_mutex: &Rc<Mutex<bool>>,
|
||||
routing_table: &drtio_routing::RoutingTable,
|
||||
linkno: u8,
|
||||
destination: u8,
|
||||
channel: i32,
|
||||
probe: i8,
|
||||
) -> i64 {
|
||||
pub async fn read_probe(linkno: u8, destination: u8, channel: i32, probe: i8) -> i64 {
|
||||
let reply = drtio::aux_transact(
|
||||
aux_mutex,
|
||||
linkno,
|
||||
routing_table,
|
||||
&drtioaux_async::Packet::MonitorRequest {
|
||||
destination: destination,
|
||||
channel: channel as _,
|
||||
@ -89,16 +80,8 @@ mod remote_moninj {
|
||||
0
|
||||
}
|
||||
|
||||
pub async fn inject(
|
||||
aux_mutex: &Rc<Mutex<bool>>,
|
||||
_routing_table: &drtio_routing::RoutingTable,
|
||||
linkno: u8,
|
||||
destination: u8,
|
||||
channel: i32,
|
||||
overrd: i8,
|
||||
value: i8,
|
||||
) {
|
||||
let _lock = aux_mutex.async_lock().await;
|
||||
pub async fn inject(linkno: u8, destination: u8, channel: i32, overrd: i8, value: i8) {
|
||||
let _lock = AUX_MUTEX.async_lock().await;
|
||||
drtioaux_async::send(
|
||||
linkno,
|
||||
&drtioaux_async::Packet::InjectionRequest {
|
||||
@ -112,18 +95,9 @@ mod remote_moninj {
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
pub async fn read_injection_status(
|
||||
aux_mutex: &Rc<Mutex<bool>>,
|
||||
routing_table: &drtio_routing::RoutingTable,
|
||||
linkno: u8,
|
||||
destination: u8,
|
||||
channel: i32,
|
||||
overrd: i8,
|
||||
) -> i8 {
|
||||
pub async fn read_injection_status(linkno: u8, destination: u8, channel: i32, overrd: i8) -> i8 {
|
||||
let reply = drtio::aux_transact(
|
||||
aux_mutex,
|
||||
linkno,
|
||||
routing_table,
|
||||
&drtioaux_async::Packet::InjectionStatusRequest {
|
||||
destination: destination,
|
||||
channel: channel as _,
|
||||
@ -174,32 +148,28 @@ mod local_moninj {
|
||||
|
||||
#[cfg(has_drtio)]
|
||||
macro_rules! dispatch {
|
||||
($aux_mutex:ident, $routing_table:ident, $channel:expr, $func:ident $(, $param:expr)*) => {{
|
||||
($channel:expr, $func:ident $(, $param:expr)*) => {{
|
||||
let destination = ($channel >> 16) as u8;
|
||||
let channel = $channel;
|
||||
let hop = $routing_table.0[destination as usize][0];
|
||||
let hop = ROUTING_TABLE.get().unwrap().0[destination as usize][0];
|
||||
if hop == 0 {
|
||||
local_moninj::$func(channel.into(), $($param, )*)
|
||||
} else {
|
||||
let linkno = hop - 1 as u8;
|
||||
remote_moninj::$func($aux_mutex, $routing_table, linkno, destination, channel, $($param, )*).await
|
||||
remote_moninj::$func(linkno, destination, channel, $($param, )*).await
|
||||
}
|
||||
}}
|
||||
}
|
||||
|
||||
#[cfg(not(has_drtio))]
|
||||
macro_rules! dispatch {
|
||||
($aux_mutex:ident, $routing_table:ident, $channel:expr, $func:ident $(, $param:expr)*) => {{
|
||||
($channel:expr, $func:ident $(, $param:expr)*) => {{
|
||||
let channel = $channel as u16;
|
||||
local_moninj::$func(channel.into(), $($param, )*)
|
||||
}}
|
||||
}
|
||||
|
||||
async fn handle_connection(
|
||||
stream: &TcpStream,
|
||||
_aux_mutex: &Rc<Mutex<bool>>,
|
||||
_routing_table: &drtio_routing::RoutingTable,
|
||||
) -> Result<()> {
|
||||
async fn handle_connection(stream: &TcpStream) -> Result<()> {
|
||||
if !expect(&stream, b"ARTIQ moninj\n").await? {
|
||||
return Err(Error::UnexpectedPattern);
|
||||
}
|
||||
@ -247,13 +217,13 @@ async fn handle_connection(
|
||||
let channel = read_i32(&stream).await?;
|
||||
let overrd = read_i8(&stream).await?;
|
||||
let value = read_i8(&stream).await?;
|
||||
dispatch!(_aux_mutex, _routing_table, channel, inject, overrd, value);
|
||||
dispatch!(channel, inject, overrd, value);
|
||||
debug!("INJECT channel {}, overrd {}, value {}", channel, overrd, value);
|
||||
},
|
||||
HostMessage::GetInjectionStatus => {
|
||||
let channel = read_i32(&stream).await?;
|
||||
let overrd = read_i8(&stream).await?;
|
||||
let value = dispatch!(_aux_mutex, _routing_table, channel, read_injection_status, overrd);
|
||||
let value = dispatch!(channel, read_injection_status, overrd);
|
||||
write_i8(&stream, DeviceMessage::InjectionStatus.to_i8().unwrap()).await?;
|
||||
write_i32(&stream, channel).await?;
|
||||
write_i8(&stream, overrd).await?;
|
||||
@ -263,7 +233,7 @@ async fn handle_connection(
|
||||
},
|
||||
_ = timeout_f => {
|
||||
for (&(channel, probe), previous) in probe_watch_list.iter_mut() {
|
||||
let current = dispatch!(_aux_mutex, _routing_table, channel, read_probe, probe);
|
||||
let current = dispatch!(channel, read_probe, probe);
|
||||
if previous.is_none() || previous.unwrap() != current {
|
||||
write_i8(&stream, DeviceMessage::MonitorStatus.to_i8().unwrap()).await?;
|
||||
write_i32(&stream, channel).await?;
|
||||
@ -273,7 +243,7 @@ async fn handle_connection(
|
||||
}
|
||||
}
|
||||
for (&(channel, overrd), previous) in inject_watch_list.iter_mut() {
|
||||
let current = dispatch!(_aux_mutex, _routing_table, channel, read_injection_status, overrd);
|
||||
let current = dispatch!(channel, read_injection_status, overrd);
|
||||
if previous.is_none() || previous.unwrap() != current {
|
||||
write_i8(&stream, DeviceMessage::InjectionStatus.to_i8().unwrap()).await?;
|
||||
write_i32(&stream, channel).await?;
|
||||
@ -288,18 +258,13 @@ async fn handle_connection(
|
||||
}
|
||||
}
|
||||
|
||||
pub fn start(aux_mutex: &Rc<Mutex<bool>>, routing_table: &Rc<RefCell<drtio_routing::RoutingTable>>) {
|
||||
let aux_mutex = aux_mutex.clone();
|
||||
let routing_table = routing_table.clone();
|
||||
pub fn start() {
|
||||
task::spawn(async move {
|
||||
loop {
|
||||
let aux_mutex = aux_mutex.clone();
|
||||
let routing_table = routing_table.clone();
|
||||
let stream = TcpStream::accept(1383, 2048, 2048).await.unwrap();
|
||||
task::spawn(async move {
|
||||
info!("received connection");
|
||||
let routing_table = routing_table.borrow();
|
||||
let result = handle_connection(&stream, &aux_mutex, &routing_table).await;
|
||||
let result = handle_connection(&stream).await;
|
||||
match result {
|
||||
Err(Error::NetworkError(smoltcp::Error::Finished)) => info!("peer closed connection"),
|
||||
Err(error) => warn!("connection terminated: {}", error),
|
||||
|
||||
@ -1,11 +1,9 @@
|
||||
#[cfg(has_si5324)]
|
||||
use ksupport::kernel::i2c;
|
||||
#[cfg(not(feature = "target_ebaz4205"))]
|
||||
use libboard_artiq::pl;
|
||||
#[cfg(has_si549)]
|
||||
use libboard_artiq::si549;
|
||||
#[cfg(has_si5324)]
|
||||
use libboard_artiq::si5324;
|
||||
use libboard_artiq::{i2c, si5324};
|
||||
#[cfg(has_si5324)]
|
||||
use libboard_zynq::i2c::I2c;
|
||||
use libboard_zynq::timer;
|
||||
|
||||
@ -1,11 +1,10 @@
|
||||
use alloc::{collections::BTreeMap, rc::Rc, string::String, vec::Vec};
|
||||
use alloc::{collections::BTreeMap, string::String, vec::Vec};
|
||||
#[cfg(has_drtio)]
|
||||
use core::mem;
|
||||
|
||||
use ksupport::kernel::DmaRecorder;
|
||||
#[cfg(has_drtio)]
|
||||
use libasync::task;
|
||||
use libboard_artiq::drtio_routing::RoutingTable;
|
||||
use libcortex_a9::{cache::dcci_slice, mutex::Mutex};
|
||||
|
||||
const ALIGNMENT: usize = 16 * 8;
|
||||
@ -105,12 +104,11 @@ pub mod remote_dma {
|
||||
Ok(playback_state)
|
||||
}
|
||||
|
||||
pub async fn upload_traces(&mut self, aux_mutex: &Rc<Mutex<bool>>, routing_table: &RoutingTable) {
|
||||
pub async fn upload_traces(&mut self) {
|
||||
let mut lock = self.traces.async_lock().await;
|
||||
let trace_iter = lock.iter_mut();
|
||||
for (destination, trace) in trace_iter {
|
||||
match drtio::ddma_upload_trace(aux_mutex, routing_table, self.id, *destination, trace.get_trace()).await
|
||||
{
|
||||
match drtio::ddma_upload_trace(self.id, *destination, trace.get_trace()).await {
|
||||
Ok(_) => trace.state = RemoteState::Loaded,
|
||||
Err(e) => error!("Error adding DMA trace on destination {}: {}", destination, e),
|
||||
}
|
||||
@ -118,11 +116,11 @@ pub mod remote_dma {
|
||||
*(self.done_count.async_lock().await) = 0;
|
||||
}
|
||||
|
||||
pub async fn erase(&mut self, aux_mutex: &Rc<Mutex<bool>>, routing_table: &RoutingTable) {
|
||||
pub async fn erase(&mut self) {
|
||||
let lock = self.traces.async_lock().await;
|
||||
let trace_iter = lock.keys();
|
||||
for destination in trace_iter {
|
||||
match drtio::ddma_send_erase(aux_mutex, routing_table, self.id, *destination).await {
|
||||
match drtio::ddma_send_erase(self.id, *destination).await {
|
||||
Ok(_) => (),
|
||||
Err(e) => error!("Error adding DMA trace on destination {}: {}", destination, e),
|
||||
}
|
||||
@ -140,7 +138,7 @@ pub mod remote_dma {
|
||||
*(self.done_count.async_lock().await) += 1;
|
||||
}
|
||||
|
||||
pub async fn playback(&self, aux_mutex: &Rc<Mutex<bool>>, routing_table: &RoutingTable, timestamp: u64) {
|
||||
pub async fn playback(&self, timestamp: u64) {
|
||||
let mut dest_list: Vec<u8> = Vec::new();
|
||||
{
|
||||
let lock = self.traces.async_lock().await;
|
||||
@ -156,26 +154,18 @@ pub mod remote_dma {
|
||||
// mutex lock must be dropped before sending a playback request to avoid a deadlock,
|
||||
// if PlaybackStatus is sent from another satellite and the state must be updated.
|
||||
for destination in dest_list {
|
||||
match drtio::ddma_send_playback(aux_mutex, routing_table, self.id, destination, timestamp).await {
|
||||
match drtio::ddma_send_playback(self.id, destination, timestamp).await {
|
||||
Ok(_) => (),
|
||||
Err(e) => error!("Error during remote DMA playback: {}", e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn destination_changed(
|
||||
&mut self,
|
||||
aux_mutex: &Rc<Mutex<bool>>,
|
||||
routing_table: &RoutingTable,
|
||||
destination: u8,
|
||||
up: bool,
|
||||
) {
|
||||
pub async fn destination_changed(&mut self, destination: u8, up: bool) {
|
||||
// update state of the destination, resend traces if it's up
|
||||
if let Some(trace) = self.traces.async_lock().await.get_mut(&destination) {
|
||||
if up {
|
||||
match drtio::ddma_upload_trace(aux_mutex, routing_table, self.id, destination, trace.get_trace())
|
||||
.await
|
||||
{
|
||||
match drtio::ddma_upload_trace(self.id, destination, trace.get_trace()).await {
|
||||
Ok(_) => trace.state = RemoteState::Loaded,
|
||||
Err(e) => error!("Error adding DMA trace on destination {}: {}", destination, e),
|
||||
}
|
||||
@ -201,22 +191,22 @@ pub mod remote_dma {
|
||||
trace_set.await_done(timeout).await
|
||||
}
|
||||
|
||||
pub async fn erase(aux_mutex: &Rc<Mutex<bool>>, routing_table: &RoutingTable, id: u32) {
|
||||
pub async fn erase(id: u32) {
|
||||
let trace_set = unsafe { TRACES.get_mut(&id).unwrap() };
|
||||
trace_set.erase(aux_mutex, routing_table).await;
|
||||
trace_set.erase().await;
|
||||
unsafe {
|
||||
TRACES.remove(&id);
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn upload_traces(aux_mutex: &Rc<Mutex<bool>>, routing_table: &RoutingTable, id: u32) {
|
||||
pub async fn upload_traces(id: u32) {
|
||||
let trace_set = unsafe { TRACES.get_mut(&id).unwrap() };
|
||||
trace_set.upload_traces(aux_mutex, routing_table).await;
|
||||
trace_set.upload_traces().await;
|
||||
}
|
||||
|
||||
pub async fn playback(aux_mutex: &Rc<Mutex<bool>>, routing_table: &RoutingTable, id: u32, timestamp: u64) {
|
||||
pub async fn playback(id: u32, timestamp: u64) {
|
||||
let trace_set = unsafe { TRACES.get_mut(&id).unwrap() };
|
||||
trace_set.playback(aux_mutex, routing_table, timestamp).await;
|
||||
trace_set.playback(timestamp).await;
|
||||
}
|
||||
|
||||
pub async fn playback_done(id: u32, destination: u8, error: u8, channel: u32, timestamp: u64) {
|
||||
@ -224,17 +214,10 @@ pub mod remote_dma {
|
||||
trace_set.playback_done(destination, error, channel, timestamp).await;
|
||||
}
|
||||
|
||||
pub async fn destination_changed(
|
||||
aux_mutex: &Rc<Mutex<bool>>,
|
||||
routing_table: &RoutingTable,
|
||||
destination: u8,
|
||||
up: bool,
|
||||
) {
|
||||
pub async fn destination_changed(destination: u8, up: bool) {
|
||||
let trace_iter = unsafe { TRACES.values_mut() };
|
||||
for trace_set in trace_iter {
|
||||
trace_set
|
||||
.destination_changed(aux_mutex, routing_table, destination, up)
|
||||
.await;
|
||||
trace_set.destination_changed(destination, up).await;
|
||||
}
|
||||
}
|
||||
|
||||
@ -244,7 +227,7 @@ pub mod remote_dma {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn put_record(_aux_mutex: &Rc<Mutex<bool>>, _routing_table: &RoutingTable, mut recorder: DmaRecorder) -> u32 {
|
||||
pub async fn put_record(mut recorder: DmaRecorder) -> u32 {
|
||||
#[cfg(has_drtio)]
|
||||
let mut remote_traces: BTreeMap<u8, Vec<u8>> = BTreeMap::new();
|
||||
|
||||
@ -293,7 +276,7 @@ pub async fn put_record(_aux_mutex: &Rc<Mutex<bool>>, _routing_table: &RoutingTa
|
||||
#[cfg(has_drtio)]
|
||||
{
|
||||
if let Some((old_id, _v, _d)) = _old_record {
|
||||
remote_dma::erase(_aux_mutex, _routing_table, old_id).await;
|
||||
remote_dma::erase(old_id).await;
|
||||
}
|
||||
remote_dma::add_traces(ptr, remote_traces);
|
||||
}
|
||||
@ -301,11 +284,11 @@ pub async fn put_record(_aux_mutex: &Rc<Mutex<bool>>, _routing_table: &RoutingTa
|
||||
ptr
|
||||
}
|
||||
|
||||
pub async fn erase(name: String, _aux_mutex: &Rc<Mutex<bool>>, _routing_table: &RoutingTable) {
|
||||
pub async fn erase(name: String) {
|
||||
let _entry = DMA_RECORD_STORE.lock().remove(&name);
|
||||
#[cfg(has_drtio)]
|
||||
if let Some((id, _v, _d)) = _entry {
|
||||
remote_dma::erase(_aux_mutex, _routing_table, id).await;
|
||||
remote_dma::erase(id).await;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
use alloc::rc::Rc;
|
||||
use core::cell::RefCell;
|
||||
|
||||
use libboard_artiq::{drtio_routing, drtio_routing::RoutingTable, pl::csr};
|
||||
use libboard_artiq::{drtio_routing, pl::csr};
|
||||
use libconfig;
|
||||
use libcortex_a9::mutex::Mutex;
|
||||
use log::{info, warn};
|
||||
|
||||
#[cfg(has_drtio)]
|
||||
@ -11,25 +10,32 @@ pub mod drtio {
|
||||
use alloc::vec::Vec;
|
||||
use core::fmt;
|
||||
|
||||
use ksupport::{ASYNC_ERROR_BUSY, ASYNC_ERROR_COLLISION, ASYNC_ERROR_SEQUENCE_ERROR, SEEN_ASYNC_ERRORS,
|
||||
kernel::Message as KernelMessage, resolve_channel_name};
|
||||
use ksupport::kernel::Message as KernelMessage;
|
||||
use libasync::task;
|
||||
#[cfg(has_drtio_eem)]
|
||||
use libboard_artiq::drtio_eem;
|
||||
use libboard_artiq::{drtioaux::Error as DrtioError,
|
||||
drtioaux_async,
|
||||
drtioaux_async::Packet,
|
||||
drtioaux_proto::{MASTER_PAYLOAD_MAX_SIZE, PayloadStatus}};
|
||||
drtioaux_proto::{MASTER_PAYLOAD_MAX_SIZE, PayloadStatus},
|
||||
resolve_channel_name};
|
||||
use libboard_zynq::timer;
|
||||
use libcortex_a9::mutex::Mutex;
|
||||
use log::{error, info, warn};
|
||||
|
||||
use super::*;
|
||||
use crate::{analyzer::remote_analyzer::RemoteBuffer, rtio_dma::remote_dma, subkernel};
|
||||
use crate::{analyzer::remote_analyzer::RemoteBuffer,
|
||||
comms::{ASYNC_ERROR_BUSY, ASYNC_ERROR_COLLISION, ASYNC_ERROR_SEQUENCE_ERROR, ROUTING_TABLE,
|
||||
SEEN_ASYNC_ERRORS},
|
||||
rtio_dma::remote_dma,
|
||||
subkernel};
|
||||
|
||||
#[cfg(has_drtio_eem)]
|
||||
const DRTIO_EEM_LINKNOS: core::ops::Range<usize> =
|
||||
(csr::DRTIO.len() - csr::CONFIG_EEM_DRTIO_COUNT as usize)..csr::DRTIO.len();
|
||||
|
||||
pub static AUX_MUTEX: Mutex<bool> = Mutex::new(false);
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||
pub enum Error {
|
||||
Timeout,
|
||||
@ -65,17 +71,10 @@ pub mod drtio {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn startup(
|
||||
aux_mutex: &Rc<Mutex<bool>>,
|
||||
routing_table: &Rc<RefCell<RoutingTable>>,
|
||||
up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>,
|
||||
) {
|
||||
let aux_mutex = aux_mutex.clone();
|
||||
let routing_table = routing_table.clone();
|
||||
pub fn startup(up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>) {
|
||||
let up_destinations = up_destinations.clone();
|
||||
task::spawn(async move {
|
||||
let routing_table = routing_table.borrow();
|
||||
link_task(&aux_mutex, &routing_table, &up_destinations).await;
|
||||
link_task(&up_destinations).await;
|
||||
});
|
||||
}
|
||||
|
||||
@ -94,9 +93,9 @@ pub mod drtio {
|
||||
unsafe { (csr::DRTIO[linkno].rx_up_read)() == 1 }
|
||||
}
|
||||
|
||||
fn get_master_destination(routing_table: &RoutingTable) -> u8 {
|
||||
fn get_master_destination() -> u8 {
|
||||
for i in 0..drtio_routing::DEST_COUNT {
|
||||
if routing_table.0[i][0] == 0 {
|
||||
if ROUTING_TABLE.get().unwrap().0[i][0] == 0 {
|
||||
return i as u8;
|
||||
}
|
||||
}
|
||||
@ -104,8 +103,8 @@ pub mod drtio {
|
||||
0
|
||||
}
|
||||
|
||||
async fn route_packet(linkno: u8, routing_table: &RoutingTable, packet: Packet, destination: u8) {
|
||||
let dest_link = routing_table.0[destination as usize][0] - 1;
|
||||
async fn route_packet(linkno: u8, packet: Packet, destination: u8) {
|
||||
let dest_link = ROUTING_TABLE.get().unwrap().0[destination as usize][0] - 1;
|
||||
if dest_link == linkno {
|
||||
warn!(
|
||||
"[LINK#{}] Re-routed packet would return to the same link, dropping: {:?}",
|
||||
@ -116,8 +115,8 @@ pub mod drtio {
|
||||
}
|
||||
}
|
||||
|
||||
async fn process_async_packets(linkno: u8, routing_table: &RoutingTable, packet: Packet) -> Option<Packet> {
|
||||
let master_destination = get_master_destination(routing_table);
|
||||
async fn process_async_packets(linkno: u8, packet: Packet) -> Option<Packet> {
|
||||
let master_destination = get_master_destination();
|
||||
match packet {
|
||||
Packet::DmaPlaybackStatus {
|
||||
id,
|
||||
@ -130,7 +129,7 @@ pub mod drtio {
|
||||
if destination == master_destination {
|
||||
remote_dma::playback_done(id, source, error, channel, timestamp).await;
|
||||
} else {
|
||||
route_packet(linkno, routing_table, packet, destination).await;
|
||||
route_packet(linkno, packet, destination).await;
|
||||
}
|
||||
None
|
||||
}
|
||||
@ -143,7 +142,7 @@ pub mod drtio {
|
||||
if destination == master_destination {
|
||||
subkernel::subkernel_finished(id, with_exception, exception_src).await;
|
||||
} else {
|
||||
route_packet(linkno, routing_table, packet, destination).await;
|
||||
route_packet(linkno, packet, destination).await;
|
||||
}
|
||||
None
|
||||
}
|
||||
@ -162,7 +161,7 @@ pub mod drtio {
|
||||
.await
|
||||
.unwrap();
|
||||
} else {
|
||||
route_packet(linkno, routing_table, packet, destination).await;
|
||||
route_packet(linkno, packet, destination).await;
|
||||
}
|
||||
None
|
||||
}
|
||||
@ -181,7 +180,7 @@ pub mod drtio {
|
||||
if destination == master_destination {
|
||||
Some(packet)
|
||||
} else {
|
||||
route_packet(linkno, routing_table, packet, destination).await;
|
||||
route_packet(linkno, packet, destination).await;
|
||||
None
|
||||
}
|
||||
}
|
||||
@ -200,20 +199,15 @@ pub mod drtio {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn aux_transact(
|
||||
aux_mutex: &Mutex<bool>,
|
||||
linkno: u8,
|
||||
routing_table: &RoutingTable,
|
||||
request: &Packet,
|
||||
) -> Result<Packet, Error> {
|
||||
pub async fn aux_transact(linkno: u8, request: &Packet) -> Result<Packet, Error> {
|
||||
if !link_rx_up(linkno).await {
|
||||
return Err(Error::LinkDown);
|
||||
}
|
||||
let _lock = aux_mutex.async_lock().await;
|
||||
let _lock = AUX_MUTEX.async_lock().await;
|
||||
drtioaux_async::send(linkno, request).await.unwrap();
|
||||
loop {
|
||||
let packet = recv_aux_timeout(linkno, 200).await?;
|
||||
if let Some(packet) = process_async_packets(linkno, routing_table, packet).await {
|
||||
if let Some(packet) = process_async_packets(linkno, packet).await {
|
||||
return Ok(packet);
|
||||
}
|
||||
}
|
||||
@ -226,7 +220,7 @@ pub mod drtio {
|
||||
}
|
||||
}
|
||||
|
||||
async fn ping_remote(aux_mutex: &Rc<Mutex<bool>>, linkno: u8, routing_table: &RoutingTable) -> u32 {
|
||||
async fn ping_remote(linkno: u8) -> u32 {
|
||||
let mut count = 0;
|
||||
loop {
|
||||
if !link_rx_up(linkno).await {
|
||||
@ -236,7 +230,7 @@ pub mod drtio {
|
||||
if count > 100 {
|
||||
return 0;
|
||||
}
|
||||
let reply = aux_transact(aux_mutex, linkno, routing_table, &Packet::EchoRequest).await;
|
||||
let reply = aux_transact(linkno, &Packet::EchoRequest).await;
|
||||
match reply {
|
||||
Ok(Packet::EchoReply) => {
|
||||
// make sure receive buffer is drained
|
||||
@ -248,8 +242,8 @@ pub mod drtio {
|
||||
}
|
||||
}
|
||||
|
||||
async fn sync_tsc(aux_mutex: &Rc<Mutex<bool>>, linkno: u8) -> Result<(), Error> {
|
||||
let _lock = aux_mutex.async_lock().await;
|
||||
async fn sync_tsc(linkno: u8) -> Result<(), Error> {
|
||||
let _lock = AUX_MUTEX.async_lock().await;
|
||||
|
||||
unsafe {
|
||||
(csr::DRTIO[linkno as usize].set_time_write)(1);
|
||||
@ -265,19 +259,13 @@ pub mod drtio {
|
||||
}
|
||||
}
|
||||
|
||||
async fn load_routing_table(
|
||||
aux_mutex: &Rc<Mutex<bool>>,
|
||||
linkno: u8,
|
||||
routing_table: &RoutingTable,
|
||||
) -> Result<(), Error> {
|
||||
async fn load_routing_table(linkno: u8) -> Result<(), Error> {
|
||||
for i in 0..drtio_routing::DEST_COUNT {
|
||||
let reply = aux_transact(
|
||||
aux_mutex,
|
||||
linkno,
|
||||
routing_table,
|
||||
&Packet::RoutingSetPath {
|
||||
destination: i as u8,
|
||||
hops: routing_table.0[i],
|
||||
hops: ROUTING_TABLE.get().unwrap().0[i],
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
@ -288,13 +276,8 @@ pub mod drtio {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn set_rank(
|
||||
aux_mutex: &Rc<Mutex<bool>>,
|
||||
linkno: u8,
|
||||
rank: u8,
|
||||
routing_table: &RoutingTable,
|
||||
) -> Result<(), Error> {
|
||||
let reply = aux_transact(aux_mutex, linkno, routing_table, &Packet::RoutingSetRank { rank: rank }).await?;
|
||||
async fn set_rank(linkno: u8, rank: u8) -> Result<(), Error> {
|
||||
let reply = aux_transact(linkno, &Packet::RoutingSetRank { rank: rank }).await?;
|
||||
match reply {
|
||||
Packet::RoutingAck => Ok(()),
|
||||
_ => Err(Error::UnexpectedReply),
|
||||
@ -317,11 +300,11 @@ pub mod drtio {
|
||||
}
|
||||
}
|
||||
|
||||
async fn process_unsolicited_aux(aux_mutex: &Mutex<bool>, linkno: u8, routing_table: &RoutingTable) {
|
||||
let _lock = aux_mutex.async_lock().await;
|
||||
async fn process_unsolicited_aux(linkno: u8) {
|
||||
let _lock = AUX_MUTEX.async_lock().await;
|
||||
match drtioaux_async::recv(linkno).await {
|
||||
Ok(Some(packet)) => {
|
||||
if let Some(packet) = process_async_packets(linkno, routing_table, packet).await {
|
||||
if let Some(packet) = process_async_packets(linkno, packet).await {
|
||||
warn!("[LINK#{}] unsolicited aux packet: {:?}", linkno, packet);
|
||||
}
|
||||
}
|
||||
@ -352,7 +335,6 @@ pub mod drtio {
|
||||
}
|
||||
|
||||
async fn destination_set_up(
|
||||
routing_table: &RoutingTable,
|
||||
up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>,
|
||||
destination: u8,
|
||||
up: bool,
|
||||
@ -360,7 +342,7 @@ pub mod drtio {
|
||||
let mut up_destinations = up_destinations.borrow_mut();
|
||||
up_destinations[destination as usize] = up;
|
||||
if up {
|
||||
drtio_routing::interconnect_enable(routing_table, 0, destination);
|
||||
drtio_routing::interconnect_enable(ROUTING_TABLE.get().unwrap(), 0, destination);
|
||||
info!("[DEST#{}] destination is up", destination);
|
||||
} else {
|
||||
drtio_routing::interconnect_disable(destination);
|
||||
@ -373,14 +355,9 @@ pub mod drtio {
|
||||
up_destinations[destination as usize]
|
||||
}
|
||||
|
||||
async fn destination_survey(
|
||||
aux_mutex: &Rc<Mutex<bool>>,
|
||||
routing_table: &RoutingTable,
|
||||
up_links: &[bool],
|
||||
up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>,
|
||||
) {
|
||||
async fn destination_survey(up_links: &[bool], up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>) {
|
||||
for destination in 0..drtio_routing::DEST_COUNT {
|
||||
let hop = routing_table.0[destination][0];
|
||||
let hop = ROUTING_TABLE.get().unwrap().0[destination][0];
|
||||
let destination = destination as u8;
|
||||
|
||||
if hop > 0 && hop as usize <= csr::DRTIO.len() {
|
||||
@ -388,9 +365,7 @@ pub mod drtio {
|
||||
if destination_up(up_destinations, destination).await {
|
||||
if up_links[linkno as usize] {
|
||||
let reply = aux_transact(
|
||||
aux_mutex,
|
||||
linkno,
|
||||
routing_table,
|
||||
&Packet::DestinationStatusRequest {
|
||||
destination: destination,
|
||||
},
|
||||
@ -398,9 +373,9 @@ pub mod drtio {
|
||||
.await;
|
||||
match reply {
|
||||
Ok(Packet::DestinationDownReply) => {
|
||||
destination_set_up(routing_table, up_destinations, destination, false).await;
|
||||
remote_dma::destination_changed(aux_mutex, routing_table, destination, false).await;
|
||||
subkernel::destination_changed(aux_mutex, routing_table, destination, false).await;
|
||||
destination_set_up(up_destinations, destination, false).await;
|
||||
remote_dma::destination_changed(destination, false).await;
|
||||
subkernel::destination_changed(destination, false).await;
|
||||
}
|
||||
Ok(Packet::DestinationOkReply) => (),
|
||||
Ok(Packet::DestinationSequenceErrorReply { channel }) => {
|
||||
@ -437,16 +412,14 @@ pub mod drtio {
|
||||
Err(e) => error!("[DEST#{}] communication failed ({})", destination, e),
|
||||
}
|
||||
} else {
|
||||
destination_set_up(routing_table, up_destinations, destination, false).await;
|
||||
remote_dma::destination_changed(aux_mutex, routing_table, destination, false).await;
|
||||
subkernel::destination_changed(aux_mutex, routing_table, destination, false).await;
|
||||
destination_set_up(up_destinations, destination, false).await;
|
||||
remote_dma::destination_changed(destination, false).await;
|
||||
subkernel::destination_changed(destination, false).await;
|
||||
}
|
||||
} else {
|
||||
if up_links[linkno as usize] {
|
||||
let reply = aux_transact(
|
||||
aux_mutex,
|
||||
linkno,
|
||||
routing_table,
|
||||
&Packet::DestinationStatusRequest {
|
||||
destination: destination,
|
||||
},
|
||||
@ -455,10 +428,10 @@ pub mod drtio {
|
||||
match reply {
|
||||
Ok(Packet::DestinationDownReply) => (),
|
||||
Ok(Packet::DestinationOkReply) => {
|
||||
destination_set_up(routing_table, up_destinations, destination, true).await;
|
||||
destination_set_up(up_destinations, destination, true).await;
|
||||
init_buffer_space(destination as u8, linkno).await;
|
||||
remote_dma::destination_changed(aux_mutex, routing_table, destination, true).await;
|
||||
subkernel::destination_changed(aux_mutex, routing_table, destination, true).await;
|
||||
remote_dma::destination_changed(destination, true).await;
|
||||
subkernel::destination_changed(destination, true).await;
|
||||
}
|
||||
Ok(packet) => error!("[DEST#{}] received unexpected aux packet: {:?}", destination, packet),
|
||||
Err(e) => error!("[DEST#{}] communication failed ({})", destination, e),
|
||||
@ -469,23 +442,19 @@ pub mod drtio {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn link_task(
|
||||
aux_mutex: &Rc<Mutex<bool>>,
|
||||
routing_table: &RoutingTable,
|
||||
up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>,
|
||||
) {
|
||||
pub async fn link_task(up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>) {
|
||||
let mut up_links = [false; csr::DRTIO.len()];
|
||||
// set up local RTIO
|
||||
let master_destination = get_master_destination(routing_table);
|
||||
let master_destination = get_master_destination();
|
||||
|
||||
destination_set_up(routing_table, up_destinations, master_destination, true).await;
|
||||
destination_set_up(up_destinations, master_destination, true).await;
|
||||
loop {
|
||||
for linkno in 0..csr::DRTIO.len() {
|
||||
let linkno = linkno as u8;
|
||||
if up_links[linkno as usize] {
|
||||
/* link was previously up */
|
||||
if link_rx_up(linkno).await {
|
||||
process_unsolicited_aux(aux_mutex, linkno, routing_table).await;
|
||||
process_unsolicited_aux(linkno).await;
|
||||
process_local_errors(linkno).await;
|
||||
} else {
|
||||
info!("[LINK#{}] link is down", linkno);
|
||||
@ -514,17 +483,17 @@ pub mod drtio {
|
||||
|
||||
if link_rx_up(linkno).await {
|
||||
info!("[LINK#{}] link RX became up, pinging", linkno);
|
||||
let ping_count = ping_remote(aux_mutex, linkno, routing_table).await;
|
||||
let ping_count = ping_remote(linkno).await;
|
||||
if ping_count > 0 {
|
||||
info!("[LINK#{}] remote replied after {} packets", linkno, ping_count);
|
||||
up_links[linkno as usize] = true;
|
||||
if let Err(e) = sync_tsc(aux_mutex, linkno).await {
|
||||
if let Err(e) = sync_tsc(linkno).await {
|
||||
error!("[LINK#{}] failed to sync TSC ({})", linkno, e);
|
||||
}
|
||||
if let Err(e) = load_routing_table(aux_mutex, linkno, routing_table).await {
|
||||
if let Err(e) = load_routing_table(linkno).await {
|
||||
error!("[LINK#{}] failed to load routing table ({})", linkno, e);
|
||||
}
|
||||
if let Err(e) = set_rank(aux_mutex, linkno, 1 as u8, routing_table).await {
|
||||
if let Err(e) = set_rank(linkno, 1 as u8).await {
|
||||
error!("[LINK#{}] failed to set rank ({})", linkno, e);
|
||||
}
|
||||
info!("[LINK#{}] link initialization completed", linkno);
|
||||
@ -534,12 +503,12 @@ pub mod drtio {
|
||||
}
|
||||
}
|
||||
}
|
||||
destination_survey(aux_mutex, routing_table, &up_links, up_destinations).await;
|
||||
destination_survey(&up_links, up_destinations).await;
|
||||
timer::async_delay_ms(200).await;
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn reset(aux_mutex: &Rc<Mutex<bool>>, routing_table: &RoutingTable) {
|
||||
pub async fn reset() {
|
||||
for linkno in 0..csr::DRTIO.len() {
|
||||
unsafe {
|
||||
(csr::DRTIO[linkno].reset_write)(1);
|
||||
@ -555,7 +524,7 @@ pub mod drtio {
|
||||
for linkno in 0..csr::DRTIO.len() {
|
||||
let linkno = linkno as u8;
|
||||
if link_rx_up(linkno).await {
|
||||
let reply = aux_transact(&aux_mutex, linkno, routing_table, &Packet::ResetRequest).await;
|
||||
let reply = aux_transact(linkno, &Packet::ResetRequest).await;
|
||||
match reply {
|
||||
Ok(Packet::ResetAck) => (),
|
||||
Ok(_) => error!("[LINK#{}] reset failed, received unexpected aux packet", linkno),
|
||||
@ -567,8 +536,6 @@ pub mod drtio {
|
||||
|
||||
pub async fn partition_data<PacketF, HandlerF>(
|
||||
linkno: u8,
|
||||
aux_mutex: &Rc<Mutex<bool>>,
|
||||
routing_table: &RoutingTable,
|
||||
data: &[u8],
|
||||
packet_f: PacketF,
|
||||
reply_handler_f: HandlerF,
|
||||
@ -591,25 +558,17 @@ pub mod drtio {
|
||||
i += len;
|
||||
let status = PayloadStatus::from_status(first, last);
|
||||
let packet = packet_f(&slice, status, len);
|
||||
let reply = aux_transact(aux_mutex, linkno, routing_table, &packet).await?;
|
||||
let reply = aux_transact(linkno, &packet).await?;
|
||||
reply_handler_f(&reply)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn ddma_upload_trace(
|
||||
aux_mutex: &Rc<Mutex<bool>>,
|
||||
routing_table: &RoutingTable,
|
||||
id: u32,
|
||||
destination: u8,
|
||||
trace: &Vec<u8>,
|
||||
) -> Result<(), Error> {
|
||||
let linkno = routing_table.0[destination as usize][0] - 1;
|
||||
let master_destination = get_master_destination(routing_table);
|
||||
pub async fn ddma_upload_trace(id: u32, destination: u8, trace: &Vec<u8>) -> Result<(), Error> {
|
||||
let linkno = ROUTING_TABLE.get().unwrap().0[destination as usize][0] - 1;
|
||||
let master_destination = get_master_destination();
|
||||
partition_data(
|
||||
linkno,
|
||||
aux_mutex,
|
||||
routing_table,
|
||||
trace,
|
||||
|slice, status, len| Packet::DmaAddTraceRequest {
|
||||
id: id,
|
||||
@ -648,18 +607,11 @@ pub mod drtio {
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn ddma_send_erase(
|
||||
aux_mutex: &Rc<Mutex<bool>>,
|
||||
routing_table: &RoutingTable,
|
||||
id: u32,
|
||||
destination: u8,
|
||||
) -> Result<(), Error> {
|
||||
let linkno = routing_table.0[destination as usize][0] - 1;
|
||||
let master_destination = get_master_destination(routing_table);
|
||||
pub async fn ddma_send_erase(id: u32, destination: u8) -> Result<(), Error> {
|
||||
let linkno = ROUTING_TABLE.get().unwrap().0[destination as usize][0] - 1;
|
||||
let master_destination = get_master_destination();
|
||||
let reply = aux_transact(
|
||||
aux_mutex,
|
||||
linkno,
|
||||
routing_table,
|
||||
&Packet::DmaRemoveTraceRequest {
|
||||
id: id,
|
||||
source: master_destination,
|
||||
@ -692,19 +644,11 @@ pub mod drtio {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn ddma_send_playback(
|
||||
aux_mutex: &Rc<Mutex<bool>>,
|
||||
routing_table: &RoutingTable,
|
||||
id: u32,
|
||||
destination: u8,
|
||||
timestamp: u64,
|
||||
) -> Result<(), Error> {
|
||||
let linkno = routing_table.0[destination as usize][0] - 1;
|
||||
let master_destination = get_master_destination(routing_table);
|
||||
pub async fn ddma_send_playback(id: u32, destination: u8, timestamp: u64) -> Result<(), Error> {
|
||||
let linkno = ROUTING_TABLE.get().unwrap().0[destination as usize][0] - 1;
|
||||
let master_destination = get_master_destination();
|
||||
let reply = aux_transact(
|
||||
aux_mutex,
|
||||
linkno,
|
||||
routing_table,
|
||||
&Packet::DmaPlaybackRequest {
|
||||
id: id,
|
||||
source: master_destination,
|
||||
@ -738,16 +682,10 @@ pub mod drtio {
|
||||
}
|
||||
}
|
||||
|
||||
async fn analyzer_get_data(
|
||||
aux_mutex: &Rc<Mutex<bool>>,
|
||||
routing_table: &RoutingTable,
|
||||
destination: u8,
|
||||
) -> Result<RemoteBuffer, Error> {
|
||||
let linkno = routing_table.0[destination as usize][0] - 1;
|
||||
async fn analyzer_get_data(destination: u8) -> Result<RemoteBuffer, Error> {
|
||||
let linkno = ROUTING_TABLE.get().unwrap().0[destination as usize][0] - 1;
|
||||
let reply = aux_transact(
|
||||
aux_mutex,
|
||||
linkno,
|
||||
routing_table,
|
||||
&Packet::AnalyzerHeaderRequest {
|
||||
destination: destination,
|
||||
},
|
||||
@ -767,9 +705,7 @@ pub mod drtio {
|
||||
let mut last_packet = false;
|
||||
while !last_packet {
|
||||
let reply = aux_transact(
|
||||
aux_mutex,
|
||||
linkno,
|
||||
routing_table,
|
||||
&Packet::AnalyzerDataRequest {
|
||||
destination: destination,
|
||||
},
|
||||
@ -794,31 +730,21 @@ pub mod drtio {
|
||||
}
|
||||
|
||||
pub async fn analyzer_query(
|
||||
aux_mutex: &Rc<Mutex<bool>>,
|
||||
routing_table: &RoutingTable,
|
||||
up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>,
|
||||
) -> Result<Vec<RemoteBuffer>, Error> {
|
||||
let mut remote_buffers: Vec<RemoteBuffer> = Vec::new();
|
||||
for i in 1..drtio_routing::DEST_COUNT {
|
||||
if destination_up(up_destinations, i as u8).await {
|
||||
remote_buffers.push(analyzer_get_data(aux_mutex, routing_table, i as u8).await?);
|
||||
remote_buffers.push(analyzer_get_data(i as u8).await?);
|
||||
}
|
||||
}
|
||||
Ok(remote_buffers)
|
||||
}
|
||||
|
||||
pub async fn subkernel_upload(
|
||||
aux_mutex: &Rc<Mutex<bool>>,
|
||||
routing_table: &RoutingTable,
|
||||
id: u32,
|
||||
destination: u8,
|
||||
data: &Vec<u8>,
|
||||
) -> Result<(), Error> {
|
||||
let linkno = routing_table.0[destination as usize][0] - 1;
|
||||
pub async fn subkernel_upload(id: u32, destination: u8, data: &Vec<u8>) -> Result<(), Error> {
|
||||
let linkno = ROUTING_TABLE.get().unwrap().0[destination as usize][0] - 1;
|
||||
partition_data(
|
||||
linkno,
|
||||
aux_mutex,
|
||||
routing_table,
|
||||
data,
|
||||
|slice, status, len| Packet::SubkernelAddDataRequest {
|
||||
id: id,
|
||||
@ -836,20 +762,11 @@ pub mod drtio {
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn subkernel_load(
|
||||
aux_mutex: &Rc<Mutex<bool>>,
|
||||
routing_table: &RoutingTable,
|
||||
id: u32,
|
||||
destination: u8,
|
||||
run: bool,
|
||||
timestamp: u64,
|
||||
) -> Result<(), Error> {
|
||||
let linkno = routing_table.0[destination as usize][0] - 1;
|
||||
let master_destination = get_master_destination(routing_table);
|
||||
pub async fn subkernel_load(id: u32, destination: u8, run: bool, timestamp: u64) -> Result<(), Error> {
|
||||
let linkno = ROUTING_TABLE.get().unwrap().0[destination as usize][0] - 1;
|
||||
let master_destination = get_master_destination();
|
||||
let reply = aux_transact(
|
||||
aux_mutex,
|
||||
linkno,
|
||||
routing_table,
|
||||
&Packet::SubkernelLoadRunRequest {
|
||||
id: id,
|
||||
source: master_destination,
|
||||
@ -884,19 +801,13 @@ pub mod drtio {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn subkernel_retrieve_exception(
|
||||
aux_mutex: &Rc<Mutex<bool>>,
|
||||
routing_table: &RoutingTable,
|
||||
destination: u8,
|
||||
) -> Result<Vec<u8>, Error> {
|
||||
let linkno = routing_table.0[destination as usize][0] - 1;
|
||||
pub async fn subkernel_retrieve_exception(destination: u8) -> Result<Vec<u8>, Error> {
|
||||
let linkno = ROUTING_TABLE.get().unwrap().0[destination as usize][0] - 1;
|
||||
let mut remote_data: Vec<u8> = Vec::new();
|
||||
let master_destination = get_master_destination(routing_table);
|
||||
let master_destination = get_master_destination();
|
||||
loop {
|
||||
let reply = aux_transact(
|
||||
aux_mutex,
|
||||
linkno,
|
||||
routing_table,
|
||||
&Packet::SubkernelExceptionRequest {
|
||||
source: master_destination,
|
||||
destination: destination,
|
||||
@ -924,19 +835,11 @@ pub mod drtio {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn subkernel_send_message(
|
||||
aux_mutex: &Rc<Mutex<bool>>,
|
||||
routing_table: &RoutingTable,
|
||||
id: u32,
|
||||
destination: u8,
|
||||
message: &[u8],
|
||||
) -> Result<(), Error> {
|
||||
let linkno = routing_table.0[destination as usize][0] - 1;
|
||||
let master_destination = get_master_destination(routing_table);
|
||||
pub async fn subkernel_send_message(id: u32, destination: u8, message: &[u8]) -> Result<(), Error> {
|
||||
let linkno = ROUTING_TABLE.get().unwrap().0[destination as usize][0] - 1;
|
||||
let master_destination = get_master_destination();
|
||||
partition_data(
|
||||
linkno,
|
||||
aux_mutex,
|
||||
routing_table,
|
||||
message,
|
||||
|slice, status, len| Packet::SubkernelMessage {
|
||||
source: master_destination,
|
||||
@ -954,12 +857,7 @@ pub mod drtio {
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn i2c_send_basic(
|
||||
aux_mutex: &Rc<Mutex<bool>>,
|
||||
routing_table: &RoutingTable,
|
||||
request: &KernelMessage,
|
||||
busno: u32,
|
||||
) -> Result<bool, Error> {
|
||||
pub async fn i2c_send_basic(request: &KernelMessage, busno: u32) -> Result<bool, Error> {
|
||||
let destination = (busno >> 16) as u8;
|
||||
let busno = busno as u8;
|
||||
let packet = match request {
|
||||
@ -974,27 +872,20 @@ pub mod drtio {
|
||||
},
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let linkno = routing_table.0[destination as usize][0] - 1;
|
||||
let reply = aux_transact(aux_mutex, linkno, routing_table, &packet).await?;
|
||||
let linkno = ROUTING_TABLE.get().unwrap().0[destination as usize][0] - 1;
|
||||
let reply = aux_transact(linkno, &packet).await?;
|
||||
match reply {
|
||||
Packet::I2cBasicReply { succeeded } => Ok(succeeded),
|
||||
_ => Err(Error::UnexpectedReply),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn i2c_send_write(
|
||||
aux_mutex: &Rc<Mutex<bool>>,
|
||||
routing_table: &RoutingTable,
|
||||
busno: u32,
|
||||
data: u8,
|
||||
) -> Result<(bool, bool), Error> {
|
||||
pub async fn i2c_send_write(busno: u32, data: u8) -> Result<(bool, bool), Error> {
|
||||
let destination = (busno >> 16) as u8;
|
||||
let busno = busno as u8;
|
||||
let linkno = routing_table.0[destination as usize][0] - 1;
|
||||
let linkno = ROUTING_TABLE.get().unwrap().0[destination as usize][0] - 1;
|
||||
let reply = aux_transact(
|
||||
aux_mutex,
|
||||
linkno,
|
||||
routing_table,
|
||||
&Packet::I2cWriteRequest {
|
||||
destination,
|
||||
busno,
|
||||
@ -1008,19 +899,12 @@ pub mod drtio {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn i2c_send_read(
|
||||
aux_mutex: &Rc<Mutex<bool>>,
|
||||
routing_table: &RoutingTable,
|
||||
busno: u32,
|
||||
ack: bool,
|
||||
) -> Result<(bool, u8), Error> {
|
||||
pub async fn i2c_send_read(busno: u32, ack: bool) -> Result<(bool, u8), Error> {
|
||||
let destination = (busno >> 16) as u8;
|
||||
let busno = busno as u8;
|
||||
let linkno = routing_table.0[destination as usize][0] - 1;
|
||||
let linkno = ROUTING_TABLE.get().unwrap().0[destination as usize][0] - 1;
|
||||
let reply = aux_transact(
|
||||
aux_mutex,
|
||||
linkno,
|
||||
routing_table,
|
||||
&Packet::I2cReadRequest {
|
||||
destination,
|
||||
busno,
|
||||
@ -1039,15 +923,10 @@ pub mod drtio {
|
||||
pub mod drtio {
|
||||
use super::*;
|
||||
|
||||
pub fn startup(
|
||||
_aux_mutex: &Rc<Mutex<bool>>,
|
||||
_routing_table: &Rc<RefCell<RoutingTable>>,
|
||||
_up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>,
|
||||
) {
|
||||
}
|
||||
pub fn startup(_up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>) {}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn reset(_aux_mutex: Rc<Mutex<bool>>, _routing_table: &RoutingTable) {}
|
||||
pub fn reset() {}
|
||||
}
|
||||
|
||||
fn toggle_sed_spread(val: u8) {
|
||||
@ -1072,13 +951,9 @@ fn setup_sed_spread() {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn startup(
|
||||
aux_mutex: &Rc<Mutex<bool>>,
|
||||
routing_table: &Rc<RefCell<RoutingTable>>,
|
||||
up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>,
|
||||
) {
|
||||
pub fn startup(up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>) {
|
||||
setup_sed_spread();
|
||||
drtio::startup(aux_mutex, routing_table, up_destinations);
|
||||
drtio::startup(up_destinations);
|
||||
unsafe {
|
||||
csr::rtio_core::reset_phy_write(1);
|
||||
}
|
||||
|
||||
@ -1,8 +1,7 @@
|
||||
use alloc::{collections::BTreeMap, rc::Rc, vec::Vec};
|
||||
use alloc::{collections::BTreeMap, vec::Vec};
|
||||
|
||||
use libasync::task;
|
||||
use libboard_artiq::{drtio_routing::RoutingTable,
|
||||
drtioaux_proto::{MASTER_PAYLOAD_MAX_SIZE, PayloadStatus}};
|
||||
use libboard_artiq::drtioaux_proto::{MASTER_PAYLOAD_MAX_SIZE, PayloadStatus};
|
||||
use libboard_zynq::timer;
|
||||
use libcortex_a9::mutex::Mutex;
|
||||
use log::{error, warn};
|
||||
@ -72,9 +71,9 @@ pub async fn add_subkernel(id: u32, destination: u8, kernel: Vec<u8>) {
|
||||
.insert(id, Subkernel::new(destination, kernel));
|
||||
}
|
||||
|
||||
pub async fn upload(aux_mutex: &Rc<Mutex<bool>>, routing_table: &RoutingTable, id: u32) -> Result<(), Error> {
|
||||
pub async fn upload(id: u32) -> Result<(), Error> {
|
||||
if let Some(subkernel) = SUBKERNELS.async_lock().await.get_mut(&id) {
|
||||
drtio::subkernel_upload(aux_mutex, routing_table, id, subkernel.destination, &subkernel.data).await?;
|
||||
drtio::subkernel_upload(id, subkernel.destination, &subkernel.data).await?;
|
||||
subkernel.state = SubkernelState::Uploaded;
|
||||
Ok(())
|
||||
} else {
|
||||
@ -82,18 +81,12 @@ pub async fn upload(aux_mutex: &Rc<Mutex<bool>>, routing_table: &RoutingTable, i
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn load(
|
||||
aux_mutex: &Rc<Mutex<bool>>,
|
||||
routing_table: &RoutingTable,
|
||||
id: u32,
|
||||
run: bool,
|
||||
timestamp: u64,
|
||||
) -> Result<(), Error> {
|
||||
pub async fn load(id: u32, run: bool, timestamp: u64) -> Result<(), Error> {
|
||||
if let Some(subkernel) = SUBKERNELS.async_lock().await.get_mut(&id) {
|
||||
if subkernel.state != SubkernelState::Uploaded {
|
||||
return Err(Error::IncorrectState);
|
||||
}
|
||||
drtio::subkernel_load(aux_mutex, routing_table, id, subkernel.destination, run, timestamp).await?;
|
||||
drtio::subkernel_load(id, subkernel.destination, run, timestamp).await?;
|
||||
if run {
|
||||
subkernel.state = SubkernelState::Running;
|
||||
}
|
||||
@ -124,12 +117,12 @@ pub async fn subkernel_finished(id: u32, with_exception: bool, exception_src: u8
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn destination_changed(aux_mutex: &Rc<Mutex<bool>>, routing_table: &RoutingTable, destination: u8, up: bool) {
|
||||
pub async fn destination_changed(destination: u8, up: bool) {
|
||||
let mut locked_subkernels = SUBKERNELS.async_lock().await;
|
||||
for (id, subkernel) in locked_subkernels.iter_mut() {
|
||||
if subkernel.destination == destination {
|
||||
if up {
|
||||
match drtio::subkernel_upload(aux_mutex, routing_table, *id, destination, &subkernel.data).await {
|
||||
match drtio::subkernel_upload(*id, destination, &subkernel.data).await {
|
||||
Ok(_) => subkernel.state = SubkernelState::Uploaded,
|
||||
Err(e) => error!("Error adding subkernel on destination {}: {}", destination, e),
|
||||
}
|
||||
@ -145,12 +138,7 @@ pub async fn destination_changed(aux_mutex: &Rc<Mutex<bool>>, routing_table: &Ro
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn await_finish(
|
||||
aux_mutex: &Rc<Mutex<bool>>,
|
||||
routing_table: &RoutingTable,
|
||||
id: u32,
|
||||
timeout: i64,
|
||||
) -> Result<SubkernelFinished, Error> {
|
||||
pub async fn await_finish(id: u32, timeout: i64) -> Result<SubkernelFinished, Error> {
|
||||
match SUBKERNELS.async_lock().await.get(&id).unwrap().state {
|
||||
SubkernelState::Running | SubkernelState::Finished { .. } => (),
|
||||
_ => return Err(Error::IncorrectState),
|
||||
@ -186,7 +174,7 @@ pub async fn await_finish(
|
||||
id: id,
|
||||
status: status,
|
||||
exception: if let FinishStatus::Exception(dest) = status {
|
||||
Some(drtio::subkernel_retrieve_exception(aux_mutex, routing_table, dest).await?)
|
||||
Some(drtio::subkernel_retrieve_exception(dest).await?)
|
||||
} else {
|
||||
None
|
||||
},
|
||||
@ -293,12 +281,6 @@ pub async fn message_await(id: u32, timeout: i64) -> Result<Message, Error> {
|
||||
Err(Error::Timeout)
|
||||
}
|
||||
|
||||
pub async fn message_send<'a>(
|
||||
aux_mutex: &Rc<Mutex<bool>>,
|
||||
routing_table: &RoutingTable,
|
||||
id: u32,
|
||||
destination: u8,
|
||||
message: Vec<u8>,
|
||||
) -> Result<(), Error> {
|
||||
Ok(drtio::subkernel_send_message(aux_mutex, routing_table, id, destination, &message).await?)
|
||||
pub async fn message_send<'a>(id: u32, destination: u8, message: Vec<u8>) -> Result<(), Error> {
|
||||
Ok(drtio::subkernel_send_message(id, destination, &message).await?)
|
||||
}
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
use libboard_artiq::{drtio_routing, drtioaux, drtioaux_async,
|
||||
drtioaux_proto::{MASTER_PAYLOAD_MAX_SIZE, SAT_PAYLOAD_MAX_SIZE},
|
||||
logger,
|
||||
pl::csr};
|
||||
use libboard_zynq::{i2c::{Error as I2cError, I2c},
|
||||
slcr, timer};
|
||||
@ -977,50 +976,6 @@ async fn process_aux_packet<'a, 'b>(
|
||||
mgmt::clear_log();
|
||||
drtioaux_async::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded: true }).await
|
||||
}
|
||||
drtioaux::Packet::CoreMgmtSetLogLevelRequest {
|
||||
destination: _destination,
|
||||
log_level,
|
||||
} => {
|
||||
forward!(
|
||||
router,
|
||||
_routing_table,
|
||||
_destination,
|
||||
*rank,
|
||||
*self_destination,
|
||||
_repeaters,
|
||||
&packet,
|
||||
);
|
||||
|
||||
if let Ok(level_filter) = mgmt::byte_to_level_filter(log_level) {
|
||||
info!("Changing log level to {}", level_filter);
|
||||
log::set_max_level(level_filter);
|
||||
drtioaux_async::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded: true }).await
|
||||
} else {
|
||||
drtioaux_async::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded: false }).await
|
||||
}
|
||||
}
|
||||
drtioaux::Packet::CoreMgmtSetUartLogLevelRequest {
|
||||
destination: _destination,
|
||||
log_level,
|
||||
} => {
|
||||
forward!(
|
||||
router,
|
||||
_routing_table,
|
||||
_destination,
|
||||
*rank,
|
||||
*self_destination,
|
||||
_repeaters,
|
||||
&packet,
|
||||
);
|
||||
|
||||
if let Ok(level_filter) = mgmt::byte_to_level_filter(log_level) {
|
||||
info!("Changing UART log level to {}", level_filter);
|
||||
logger::BufferLogger::get_logger().set_uart_log_level(level_filter);
|
||||
drtioaux_async::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded: true }).await
|
||||
} else {
|
||||
drtioaux_async::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded: false }).await
|
||||
}
|
||||
}
|
||||
drtioaux::Packet::CoreMgmtConfigReadRequest {
|
||||
destination: _destination,
|
||||
length,
|
||||
@ -1168,6 +1123,7 @@ async fn process_aux_packet<'a, 'b>(
|
||||
|
||||
drtioaux_async::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded: true }).await?;
|
||||
info!("reboot imminent");
|
||||
log::logger().flush();
|
||||
slcr::reboot();
|
||||
|
||||
unreachable!();
|
||||
@ -1253,6 +1209,7 @@ async fn process_aux_packet<'a, 'b>(
|
||||
|
||||
core_manager.write_image();
|
||||
info!("reboot imminent");
|
||||
log::logger().flush();
|
||||
slcr::reboot();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -214,6 +214,29 @@ mod grabber {
|
||||
}
|
||||
}
|
||||
|
||||
fn setup_log_levels() {
|
||||
if let Ok(level_string) = libconfig::read_str("log_level") {
|
||||
if let Ok(level) = level_string.parse::<log::LevelFilter>() {
|
||||
info!("log level set to {} by `log_level` config key", level);
|
||||
logger::BufferLogger::get_logger().set_buffer_log_level(level);
|
||||
} else {
|
||||
info!("log level set to INFO by default");
|
||||
}
|
||||
} else {
|
||||
info!("log level set to INFO by default");
|
||||
}
|
||||
if let Ok(level_string) = libconfig::read_str("uart_log_level") {
|
||||
if let Ok(level) = level_string.parse::<log::LevelFilter>() {
|
||||
info!("UART log level set to {} by `uart_log_level` config key", level);
|
||||
logger::BufferLogger::get_logger().set_uart_log_level(level);
|
||||
} else {
|
||||
info!("UART log level set to INFO by default");
|
||||
}
|
||||
} else {
|
||||
info!("UART log level set to INFO by default");
|
||||
}
|
||||
}
|
||||
|
||||
static mut LOG_BUFFER: [u8; 1 << 17] = [0; 1 << 17];
|
||||
|
||||
#[no_mangle]
|
||||
@ -226,17 +249,16 @@ pub fn main_core0() {
|
||||
timer::start();
|
||||
|
||||
let buffer_logger = unsafe { logger::BufferLogger::new(&mut LOG_BUFFER[..]) };
|
||||
buffer_logger.set_uart_log_level(log::LevelFilter::Info);
|
||||
buffer_logger.register();
|
||||
log::set_max_level(log::LevelFilter::Info);
|
||||
log::set_max_level(log::LevelFilter::Trace);
|
||||
|
||||
info!("ARTIQ satellite manager starting...");
|
||||
info!("gateware ident {}", identifier_read(&mut [0; 64]));
|
||||
|
||||
ram::init_alloc_core0();
|
||||
|
||||
ksupport::kernel::i2c::init();
|
||||
let i2c = ksupport::kernel::i2c::get_bus();
|
||||
libboard_artiq::i2c::init();
|
||||
let i2c = libboard_artiq::i2c::get_bus();
|
||||
|
||||
#[cfg(feature = "target_kasli_soc")]
|
||||
let (mut io_expander0, mut io_expander1);
|
||||
@ -260,6 +282,11 @@ pub fn main_core0() {
|
||||
io_expander1.set(0, 1, false);
|
||||
io_expander0.set(1, 1, false);
|
||||
io_expander1.set(1, 1, false);
|
||||
|
||||
// Enable EEM power
|
||||
#[cfg(hw_rev = "v1.2")]
|
||||
io_expander1.set(0, 7, true);
|
||||
|
||||
io_expander0.service(i2c).unwrap();
|
||||
io_expander1.service(i2c).unwrap();
|
||||
}
|
||||
@ -298,6 +325,8 @@ pub fn main_core0() {
|
||||
warn!("config initialization failed: {}", err);
|
||||
}
|
||||
|
||||
setup_log_levels();
|
||||
|
||||
if let Ok(spread_enable) = libconfig::read_str("sed_spread_enable") {
|
||||
match spread_enable.as_ref() {
|
||||
"1" => toggle_sed_spread(1),
|
||||
@ -324,7 +353,7 @@ pub fn main_core0() {
|
||||
#[cfg(has_cxp_grabber)]
|
||||
{
|
||||
cxp_phys::setup();
|
||||
task::spawn(cxp_grabber::thread(ksupport::kernel::i2c::get_bus()));
|
||||
task::spawn(cxp_grabber::thread(libboard_artiq::i2c::get_bus()));
|
||||
}
|
||||
|
||||
#[cfg(has_drtio_routing)]
|
||||
|
||||
@ -12,21 +12,6 @@ use crate::routing::{SliceMeta, Sliceable};
|
||||
|
||||
type Result<T> = core::result::Result<T, ()>;
|
||||
|
||||
pub fn byte_to_level_filter(level_byte: u8) -> Result<LevelFilter> {
|
||||
Ok(match level_byte {
|
||||
0 => LevelFilter::Off,
|
||||
1 => LevelFilter::Error,
|
||||
2 => LevelFilter::Warn,
|
||||
3 => LevelFilter::Info,
|
||||
4 => LevelFilter::Debug,
|
||||
5 => LevelFilter::Trace,
|
||||
lv => {
|
||||
error!("unknown log level: {}", lv);
|
||||
return Err(());
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn get_logger_buffer() -> LogBufferRef<'static> {
|
||||
let logger = BufferLogger::get_logger();
|
||||
loop {
|
||||
@ -100,9 +85,36 @@ impl Manager {
|
||||
debug!("write key: {}", key);
|
||||
let value = payload.read_bytes::<NativeEndian>().unwrap();
|
||||
|
||||
let mut delay_set_flag = false;
|
||||
if key == "log_level" || key == "uart_log_level" {
|
||||
let value_str = core::str::from_utf8(&value).map_err(|err| error!("invalid UTF_8: {:?}", err))?;
|
||||
let max_level = value_str
|
||||
.parse::<LevelFilter>()
|
||||
.map_err(|err| error!("unknown log level: {:?}", err))?;
|
||||
|
||||
if key == "log_level" {
|
||||
info!("Changing log level to {}", max_level);
|
||||
BufferLogger::get_logger().set_buffer_log_level(max_level);
|
||||
} else {
|
||||
if max_level == LevelFilter::Trace {
|
||||
delay_set_flag = true;
|
||||
BufferLogger::get_logger().set_uart_log_level(LevelFilter::Debug);
|
||||
} else {
|
||||
info!("Changing UART log level to {}", max_level);
|
||||
BufferLogger::get_logger().set_uart_log_level(max_level);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
libconfig::write(&key, value)
|
||||
.map(|()| debug!("write success"))
|
||||
.map_err(|err| error!("failed to write: {:?}", err))
|
||||
.map_err(|err| error!("failed to write: {:?}", err))?;
|
||||
|
||||
if delay_set_flag {
|
||||
info!("Changing UART log level to {}", LevelFilter::Trace);
|
||||
BufferLogger::get_logger().set_uart_log_level(LevelFilter::Trace);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn remove_config(&mut self, key: &str) -> Result<()> {
|
||||
|
||||
@ -465,7 +465,6 @@ impl<'a> Manager<'a> {
|
||||
current_backtrace_size: 0,
|
||||
}],
|
||||
&[],
|
||||
0,
|
||||
) {
|
||||
Ok(_) => self.session.last_exception = Some(Sliceable::new(0, writer.into_inner())),
|
||||
Err(_) => error!("Error writing exception data"),
|
||||
@ -732,12 +731,12 @@ impl<'a> Manager<'a> {
|
||||
) -> Result<bool, Error> {
|
||||
let reply = self.control.borrow_mut().rx.try_recv()?;
|
||||
match reply {
|
||||
kernel::Message::KernelFinished(_async_errors) => {
|
||||
kernel::Message::KernelFinished => {
|
||||
self.kernel_stop();
|
||||
dma_manager.cleanup(router, rank, self_destination, routing_table);
|
||||
return Ok(true);
|
||||
}
|
||||
kernel::Message::KernelException(exceptions, stack_pointers, backtrace, async_errors) => {
|
||||
kernel::Message::KernelException(exceptions, stack_pointers, backtrace) => {
|
||||
error!("exception in kernel");
|
||||
for exception in exceptions {
|
||||
error!("{:?}", exception.unwrap());
|
||||
@ -746,7 +745,7 @@ impl<'a> Manager<'a> {
|
||||
error!("backtrace: {:?}", backtrace);
|
||||
let buf: Vec<u8> = Vec::new();
|
||||
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) {
|
||||
Ok(()) => (),
|
||||
Err(_) => error!("Error writing exception data"),
|
||||
}
|
||||
@ -1008,10 +1007,10 @@ impl<'a> Manager<'a> {
|
||||
.await;
|
||||
match recv_w_timeout(&mut self.control.borrow_mut().rx, 100).await {
|
||||
Ok(kernel::Message::RpcRecvRequest(slot)) => slot,
|
||||
Ok(kernel::Message::KernelException(exceptions, stack_pointers, backtrace, async_errors)) => {
|
||||
Ok(kernel::Message::KernelException(exceptions, stack_pointers, backtrace)) => {
|
||||
let buf: Vec<u8> = Vec::new();
|
||||
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) {
|
||||
Ok(()) => {
|
||||
exception = Some(Sliceable::new(0, writer.into_inner()));
|
||||
}
|
||||
@ -1057,7 +1056,6 @@ fn write_exception<W: ProtoWrite>(
|
||||
exceptions: &[Option<eh_artiq::Exception>],
|
||||
stack_pointers: &[eh_artiq::StackPointerBacktrace],
|
||||
backtrace: &[(usize, usize)],
|
||||
async_errors: u8,
|
||||
) -> Result<(), Error> {
|
||||
/* header */
|
||||
writer.write_bytes::<NativeEndian>(&[0x5a, 0x5a, 0x5a, 0x5a, /*Reply::KernelException*/ 9])?;
|
||||
@ -1079,7 +1077,7 @@ fn write_exception<W: ProtoWrite>(
|
||||
&format!(
|
||||
"0x{:04x}:{}",
|
||||
exception.param[0],
|
||||
ksupport::resolve_channel_name(exception.param[0] as u32)
|
||||
libboard_artiq::resolve_channel_name(exception.param[0] as u32)
|
||||
),
|
||||
);
|
||||
writer.write_string::<NativeEndian>(&msg)?;
|
||||
@ -1103,7 +1101,7 @@ fn write_exception<W: ProtoWrite>(
|
||||
writer.write_u32::<NativeEndian>(addr as u32)?;
|
||||
writer.write_u32::<NativeEndian>(sp as u32)?;
|
||||
}
|
||||
writer.write_u8(async_errors as u8)?;
|
||||
writer.write_u8(0u8)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user