Compare commits

...

44 Commits

Author SHA1 Message Date
c65b130275 jsons: base -> drtio_role
"base" is deprecated.
2025-12-01 13:04:44 +08:00
efd45316e7 cargo fmt 2025-11-28 22:32:13 +08:00
1f8c9c3ee3 flake: add zc706 acpki hitl tests 2025-11-28 22:17:14 +08:00
4a1dc628d9 acpki: fix wait delay, rtio output waits only in gateware 2025-11-28 22:14:46 +08:00
72407a19a3 rtio_acp: decrease latency for rtio events
move the status clear to after the status is read, rather than beginning
this saves the time for slow volatile write
fixes test_exceptions RTIO underflow test
2025-11-28 22:14:45 +08:00
d9871ed0a7 libkernel: acp: refactor, shortening the functions 2025-11-28 22:14:45 +08:00
90db06a9e1 kasli soc: add phaser_drtio support
kasli soc: refactor and move drtio over eem peripheral into a list
kasli soc: raise error when using drito over eem in standalone
2025-11-24 12:10:51 +08:00
446384d787 flake: update dependencies 2025-11-22 10:39:40 +08:00
dly04
f3d4793fcb deal with setting uart filter level to trace, to prevent drtioaux timeout 2025-11-19 11:15:43 +08:00
dly04
00c4d48211 use coremgmt config to set runtime and stored log level 2025-11-19 10:58:20 +08:00
fd1b2453d7 flake: format 2025-11-18 18:19:45 +08:00
6ff895c0bf flake: update dependencies 2025-11-18 18:06:23 +08:00
dly04
b55f629486 fix format 2025-11-18 16:30:04 +08:00
dly
61dbb6a0f1 fix handling of the various log levels
Fix the global log level at TRACE, modifying only buffer log level when calling `artiq_coremgmt log set_level`.
By replacing `set_max_level` being called after `artiq_coremgmt log set_level` by `set_buffer_log_level`.
So that `artiq_coremgmt log set_level` won't affect UART log level.
Tested on Kasli-Soc.

Co-authored-by: dly04 <yliujc@connect.ust.hk>
Reviewed-on: M-Labs/artiq-zynq#429
Reviewed-by: mwojcik <mw@m-labs.hk>
Reviewed-by: srenblad <srenblad@m-labs.hk>
Co-authored-by: dly <dly@m-labs.hk>
Co-committed-by: dly <dly@m-labs.hk>
2025-11-18 12:24:36 +08:00
159987a64b remote_run: fix target host name 2025-11-14 10:50:27 +08:00
3be9250978 flake: use artiq-build (artiq with minimal dependencies) 2025-11-10 18:39:08 +08:00
b88bb90139 flake: update dependencies 2025-11-10 18:38:38 +08:00
3b0b52ef2c si549: clean up remaining GlobalTimer usage
Missing as it did not show up in testing / searching.
2025-11-10 14:10:11 +08:00
982828bde1 flake: update dependencies 2025-11-04 22:34:12 +08:00
db0231956e firmware: expose ldexp 2025-11-04 21:24:43 +08:00
d9bf878d03 flake: update dependencies 2025-10-09 17:12:06 +08:00
beb98b52fd flake: update artiq and dependencies for SoC v1.2
For including the system description JSON schema change in
https://github.com/m-labs/artiq/pull/2857, so that a hw_rev of v1.2 for
the Kasli-SoC could be specified for building.
2025-09-12 13:30:20 +08:00
d57f308765 Add minimal support for Kasli-SoC v1.2
- Update cfg directives to consider a hw_rev of 1.2.
- Turn on EEM power, without checking for faults for the time being.
2025-09-12 13:30:10 +08:00
d9f2f84480 update cargo lockfile 2025-08-22 14:57:48 +08:00
c317b3a0ac satman: async_errors is always 0 2025-08-22 14:57:26 +08:00
54ce700fde ksupport: move async error reporting to runtime 2025-08-22 14:57:26 +08:00
7f28167279 ksupport: move device map to core0 2025-08-22 12:00:47 +08:00
307ced4585 ksupport: move i2c to core0
In order for the firmware to interop with Kasli v2, all inter core comms
need to be through the message passing interface (sync_channel/mailbox).
2025-08-20 12:35:01 +08:00
3f497e08a4 runtime: cleanup imports 2025-08-19 16:24:53 +08:00
Harry Poon
9a816e1d5b coremgmt: fix formatting 2025-08-15 11:08:46 +08:00
7cceda9353 terminate old aqctl_corelog connections when receiving new ones
M-Labs/artiq-zynq#424
Co-authored-by: harryp <thpoonaa@connect.ust.hk>
Co-committed-by: harryp <thpoonaa@connect.ust.hk>
2025-08-14 19:01:26 +08:00
a325d5ce78 flake: update dependencies 2025-08-11 23:18:28 +08:00
40f1c94ecf satman: flush uart before reboot 2025-08-11 15:10:18 +08:00
92c586d266 runtime: flush uart before rebooting 2025-08-11 15:10:18 +08:00
96928b7d0d logger: implement flush for BufferLogger 2025-08-11 15:10:18 +08:00
59266fd141 runtime: make routing table static OnceLock 2025-08-04 12:55:40 +08:00
78080eae2b flake: add new required fields for buildPythonPackage 2025-07-31 15:17:07 +08:00
f1e79310ec update cargo lock 2025-07-31 15:07:04 +08:00
3a65d6c2a5 libksupport: wrap RTIO_DEVICE_MAP in OnceLock 2025-07-31 15:07:04 +08:00
734fd11ad6 libboard_artiq: wrap LOGGER in OnceLock 2025-07-31 15:07:04 +08:00
5843138a8e flake: update dependencies 2025-07-31 15:06:03 +08:00
1ab755838a ksupport: expose libc/compiler-rt strlen and bcmp 2025-07-30 18:17:09 +08:00
e21873d227 runtime: make aux_mutex static 2025-07-25 16:27:01 +08:00
767b725db7 runtime: make restart_idle static
Semaphore is already Send/Sync so there is no need to wrap it in an Rc
and pass it around.
2025-07-16 14:00:36 +08:00
36 changed files with 1358 additions and 1650 deletions

View File

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

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

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

View File

@ -2,7 +2,7 @@
"target": "kasli_soc",
"variant": "master",
"hw_rev": "v1.0",
"base": "master",
"drtio_role": "master",
"peripherals": [
{
"type": "coaxpress_sfp"

View File

@ -2,7 +2,7 @@
"target": "kasli_soc",
"variant": "satellite",
"hw_rev": "v1.0",
"base": "satellite",
"drtio_role": "satellite",
"peripherals": [
{
"type": "coaxpress_sfp"

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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