Compare commits

...

31 Commits

Author SHA1 Message Date
eaf3f3ee01 flake: remove deprecated pytest-runner 2024-12-20 13:59:22 +08:00
e03efe8845 flake: update fastnumbers 2024-12-20 13:20:29 +08:00
f975b949a2 flake: update dependencies, switch to zynq-rs release-8, switch to oxalica rust overlay 2024-12-20 13:14:11 +08:00
2bb4464fe5 drtio: restore copy_work_buffer for transmission 2024-12-11 12:10:06 +08:00
451b4f4419 gateware: add extra ident info, source version 2024-12-11 11:49:24 +08:00
39afe20646 kasli_soc: fix acpki import 2024-12-11 11:45:36 +08:00
a0200ad1f7 drtio: add InjectionRequest to expects_response 2024-11-26 13:26:54 +08:00
3c258660ba flake: update artiq 2024-11-20 20:01:04 +08:00
9921dcaabc Fix DWARF parser treating catch blocks as unconditional
Signed-off-by: Jonathan Coates <jonathan.coates@oxionics.com>
2024-11-20 09:33:58 +08:00
427b5ea9e6 README: general update 2024-11-08 16:54:46 +08:00
6fa6e7c1e5 cargo fmt 2024-10-18 17:44:54 +08:00
d3545a774a subkernels: pass now_mu when calling subkernels 2024-10-18 15:03:52 +08:00
76dde22f21 runtime: fix drtio inject lock 2024-09-09 16:43:22 +08:00
118f096c5a flake: update dependencies 2024-08-23 17:39:05 +08:00
953e60b4d2 firmware: restore exception id order 2024-08-23 14:12:50 +08:00
0e48524999 flake: update dependencies 2024-08-21 18:57:20 +08:00
e9a8c3fe10 firmware: add unit tests for exception sync 2024-08-21 18:45:33 +08:00
84bcdec2d2 firmware: sync exception names and ids 2024-08-21 18:44:50 +08:00
367061aab8 cargo fmt 2024-08-05 19:37:39 +08:00
f348ea140a comms: remove idle kernel DRTIO error case 2024-08-05 19:28:43 +08:00
6e5cbf8abf comms: run idle kernel on start-up 2024-08-05 19:28:43 +08:00
a67e45a2bc subkernels: support exceptions from subkernels 2024-07-31 17:23:56 +08:00
a9b43e8ae2 subkernels: raise exceptions to kernel 2024-07-31 17:23:56 +08:00
8e72f28f24 flake: update dependencies 2024-07-31 17:22:46 +08:00
4248d71555 repeater: handle async messages 2024-07-09 17:05:16 +02:00
836e266a36 allow toggling SED spread with flash config key 2024-07-09 17:00:09 +02:00
c58256fdd4 flake: update dependencies 2024-07-09 16:59:33 +02:00
25e858f2e9 kernel/api: add rint api 2024-07-05 08:55:13 +02:00
50c63b2c93 repeater: clear buffer after ping 2024-07-04 13:40:32 +02:00
f87adab53f flake: update dependencies 2024-06-06 13:55:46 +08:00
cae316fe10 flake: follow ARTIQ release-8 2024-06-06 10:19:58 +08:00
22 changed files with 975 additions and 331 deletions

View File

@ -4,60 +4,92 @@ ARTIQ on Zynq
How to use
----------
1. Install the ARTIQ version that corresponds to the artiq-zynq version you are targeting.
2. To obtain firmware binaries, select the latest successful build on [Hydra](https://nixbld.m-labs.hk/) for the targeted artiq-zynq version, or use AFWS. If using Hydra, search for the job named ``<board>-<variant>-sd`` (for example: ``zc706-nist_clock-sd`` or ``zc706-nist_qc2-sd``).
3. Place the ``boot.bin`` file, obtained from Hydra's "binary distribution" download link or from AFWS, at the root of a FAT-formatted SD card.
4. Optionally, create a ``config.txt`` configuration file at the root of the SD card containing ``key=value`` pairs on each line. Use the ``ip``, ``ip6`` and ``mac`` keys to respectively set the IPv4, IPv6 and MAC address of the board. Configuring an IPv6 address is entirely optional. If these keys are not found, the firmware will use default values that may or may not be compatible with your network.
5. Insert the SD card into the board and set up the board to boot from the SD card. For the ZC706, this is achieved by placing the large DIP switch SW11 in the 00110 position.
6. Power up the board. After the firmware starts successfully, it should respond to ping at its IP addresses, and boot messages can be observed from its UART at 115200bps.
7. Create and use an ARTIQ device database as usual, but set ``"target": "cortexa9"`` in the arguments of the core device.
1. [Install ARTIQ](https://m-labs.hk/artiq/manual/installing.html). Get the corresponding version to the ``artiq-zynq`` version you are targeting.
2. To obtain firmware binaries, use AFWS or build your own; see [the ARTIQ manual](https://m-labs.hk/artiq/manual/building_developing.html) for detailed instructions or skip to "Development" below. ZC706 variants only can also be downloaded from latest successful build on [Hydra](https://nixbld.m-labs.hk/).
3. Place ``boot.bin`` file at the root ``/`` of a FAT-formatted SD card.
4. Optionally, create a ``config.txt`` configuration file containing ``key=value`` pairs on each line and place it at the root of the SD card. See below for valid keys. The ``ip``, ``ip6`` and ``mac`` keys can be used to set networking information. If these keys are not found, the firmware will use default values which may or may not be compatible with your network.
5. Insert the SD card into the board and set the board to boot from the SD card. For ZC706, this is achieved by placing the large DIP switch SW11 into the 00110 position. On Kasli-SoC, place the BOOT MODE switches to SD.
6. Power up the board. After successful boot the firmware should respond to ping at its IP addresses. Boot output can be observed from UART at 115200bps 8-N-1.
7. Create and use an ARTIQ device database as usual.
Configuration
-------------
Configuring the device is done using the ``config.txt`` text file at the root of the SD card, plus the contents of the ``config`` folder. When searching for a configuration key, the firmware first looks for a file named ``/config/[key].bin`` and, if it exists, returns the contents of that file. If not, it looks into ``/config.txt``, which contains a list of ``key=value`` pairs, one per line. The ``config`` folder allows configuration values that consist in binary data, such as the startup kernel.
Configuring the device is done using the ``config.txt`` text file at the root of the SD card plus optionally a ``config`` folder. When searching for a configuration key, the firmware first looks for a file named ``/config/[key].bin`` and, if it exists, returns the contents of that file. If not, it looks into ``/config.txt``, which should contain a list of ``key=value`` pairs, one per line. ``config.txt`` should be used for most keys but the ``config`` folder allows for setting configuration values which consist of binary data, such as the startup kernel.
The following configuration keys are available:
The following configuration keys are available among others:
- ``mac``: Ethernet MAC address.
- ``ip``: IPv4 address.
- ``ip6``: IPv6 address.
- ``startup``: startup kernel in ELF format (as produced by ``artiq_compile``).
- ``idle_kernel``: idle kernel in ELF format (as produced by ``artiq_compile``).
- ``startup_kernel``: startup kernel in ELF format (as produced by ``artiq_compile``).
- ``rtio_clock``: source of RTIO clock; valid values are ``ext0_bypass`` and ``int_125``.
- ``boot``: SD card "boot.bin" file, for replacing the boot firmware/gateware. Write only.
Configurations can be read/written/removed via ``artiq_coremgmt``. Config erase is
not implemented as it seems not very useful.
See [ARTIQ manual](https://m-labs.hk/artiq/manual-beta/core_device.html#configuration-storage) for full list. Configurations can be read/written/removed with ``artiq_coremgmt``. Config erase is not implemented, as it isn't particularly useful.
For convenience, the ``boot`` key can be used with ``artiq_coremgmt`` and a ``boot.bin`` file to replace firmware/gateware in a running system. This key is read-only. When loading ``boot.bin`` onto the SD card directly, place it at the root and not in the ``config`` folder.
Development instructions
------------------------
ARTIQ on Zynq is packaged using the [Nix](https://nixos.org) Flakes system. Install Nix 2.8+ and enable flakes by adding ``experimental-features = nix-command flakes`` to ``nix.conf`` (e.g. ``~/.config/nix/nix.conf``).
ARTIQ on Zynq is packaged using [Nix](https://nixos.org) Flakes. Install Nix 2.8+ and enable flakes by adding ``experimental-features = nix-command flakes`` to ``nix.conf`` (e.g. ``~/.config/nix/nix.conf``).
Pure build with Nix and execution on a remote JTAG server:
**Pure build with Nix:**
```shell
nix build .#zc706-nist_clock-jtag # or zc706-nist_qc2-jtag or zc706-nist_clock_satellite-jtag etc.
./remote_run.sh
nix build .#zc706-nist_clock-jtag # or zc706-nist_qc2-jtag or zc706-nist_clock-sd or etc
```
Impure incremental build and execution on a remote JTAG server:
Run ``nix flake show`` to see all valid build targets. Targets suffixed with ``-jtag`` produce separate firmware and gateware files, intended for use in booting via JTAG server/Ethernet, e.g. ``./remote_run.sh -i`` with a remote JTAG server. Targets suffixed with ``-sd`` will produce ``boot.bin`` file suitable for SD card boot. ``-firmware`` and ``-gateware`` respectively build firmware and gateware only.
The Kasli-SoC target requires a system description file as input. See ARTIQ manual for exact instructions or use incremental build.
**Impure incremental build:**
For boards with fixed variants, i.e. ZC706, etc. :
```shell
nix develop
cd src
gateware/zc706.py -g ../build/gateware -V <variant> # build gateware
make GWARGS="-V <variant>" <runtime/satman> # build firmware
cd ..
./remote_run.sh -i
gateware/<board>.py -g ../build/gateware -V <variant> # gateware
make GWARGS="-V <variant>" <runtime/satman> # firmware
```
For boards with system descriptions, i.e. Kasli-SoC, etc. :
```shell
nix develop
cd src
gateware/<board>.py -g ../build/gateware <description.json> # gateware
make TARGET=<board> GWARGS="path/to/description.json" <runtime/satman> # firmware
```
``szl.elf`` can be obtained with:
```shell
nix build git+https://git.m-labs.hk/m-labs/zynq-rs#<board>-szl
```
To generate ``boot.bin`` use ``mkbootimage``, e.g.:
```shell
echo "the_ROM_image:
{
[bootloader]result/szl.elf
gateware/top.bit
firmware/armv7-none-eabihf/release/<runtime/satman>
}
EOF" >> boot.bif
mkbootimage boot.bif boot.bin
```
Notes:
- The impure build process is also compatible with non-Nix systems.
- When calling make, you need to specify both the variant and firmware type.
- Firmware type must be either ``runtime`` for DRTIO-less or DRTIO master variants, or ``satman`` for DRTIO satellite.
- If the board is connected to the local machine, use the ``local_run.sh`` script.
- If the board is connected to the local machine by JTAG, use the ``local_run.sh`` script.
- A known Xilinx hardware bug prevents repeatedly loading the bootloader over JTAG without a POR reset. If booting over JTAG, install a jumper on ``PS_POR_B`` and use the POR reset script [here](https://git.m-labs.hk/M-Labs/zynq-rs/src/branch/master/kasli_soc_por.py).
License
-------

121
flake.lock generated
View File

@ -11,15 +11,16 @@
"src-pythonparser": "src-pythonparser"
},
"locked": {
"lastModified": 1717638354,
"narHash": "sha256-eyI8OsOrn/j8ChbCpyFpS5VXBW8xSNGGIboFGQj/d4I=",
"ref": "refs/heads/master",
"rev": "ebc1e3fb767d6c0eac6eac20c3afeaba2ab70d1a",
"revCount": 8833,
"lastModified": 1734418881,
"narHash": "sha256-h5OCxE0mPHa0GzipT3Q9YRk6pPtUkCLKvNoUZgNGx0k=",
"ref": "release-8",
"rev": "4a2bc0c005ba23ec78b82e08b900c1e126fa3b2e",
"revCount": 8991,
"type": "git",
"url": "https://github.com/m-labs/artiq.git"
},
"original": {
"ref": "release-8",
"type": "git",
"url": "https://github.com/m-labs/artiq.git"
}
@ -37,11 +38,11 @@
]
},
"locked": {
"lastModified": 1717637438,
"narHash": "sha256-BXFidNm3Em8iChPGu1L0s2bY+f2yQ0VVid4MuOoTehw=",
"lastModified": 1720768567,
"narHash": "sha256-3VoK7o5MtHtbHLrc6Pv+eQWFtaz5Gd/YWyV5TD3c5Ss=",
"owner": "m-labs",
"repo": "artiq-comtools",
"rev": "78d27026efe76a13f7b4698a554f55811369ec4d",
"rev": "f93570d8f2ed5a3cfb3e1c16ab00f2540551e994",
"type": "github"
},
"original": {
@ -71,43 +72,11 @@
"mozilla-overlay": {
"flake": false,
"locked": {
"lastModified": 1704373101,
"narHash": "sha256-+gi59LRWRQmwROrmE1E2b3mtocwueCQqZ60CwLG+gbg=",
"lastModified": 1733136220,
"narHash": "sha256-Ga8AP/YPsKDVF5LcNN8v3RiLgnEeW7zBk9GyX7wa9Ug=",
"owner": "mozilla",
"repo": "nixpkgs-mozilla",
"rev": "9b11a87c0cc54e308fa83aac5b4ee1816d5418a2",
"type": "github"
},
"original": {
"owner": "mozilla",
"repo": "nixpkgs-mozilla",
"type": "github"
}
},
"mozilla-overlay_2": {
"flake": false,
"locked": {
"lastModified": 1704373101,
"narHash": "sha256-+gi59LRWRQmwROrmE1E2b3mtocwueCQqZ60CwLG+gbg=",
"owner": "mozilla",
"repo": "nixpkgs-mozilla",
"rev": "9b11a87c0cc54e308fa83aac5b4ee1816d5418a2",
"type": "github"
},
"original": {
"owner": "mozilla",
"repo": "nixpkgs-mozilla",
"type": "github"
}
},
"mozilla-overlay_3": {
"flake": false,
"locked": {
"lastModified": 1704373101,
"narHash": "sha256-+gi59LRWRQmwROrmE1E2b3mtocwueCQqZ60CwLG+gbg=",
"owner": "mozilla",
"repo": "nixpkgs-mozilla",
"rev": "9b11a87c0cc54e308fa83aac5b4ee1816d5418a2",
"rev": "ad7af231a95acf65ccc4afa0c766f5c0674ad3f1",
"type": "github"
},
"original": {
@ -118,16 +87,16 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1717281328,
"narHash": "sha256-evZPzpf59oNcDUXxh2GHcxHkTEG4fjae2ytWP85jXRo=",
"lastModified": 1733550349,
"narHash": "sha256-NcGumB4Lr6KSDq+nIqXtNA8QwAQKDSZT7N9OTGWbTrs=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "b3b2b28c1daa04fe2ae47c21bb76fd226eac4ca1",
"rev": "e2605d0744c2417b09f8bf850dfca42fcf537d34",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-24.05",
"ref": "nixos-24.11",
"repo": "nixpkgs",
"type": "github"
}
@ -135,10 +104,31 @@
"root": {
"inputs": {
"artiq": "artiq",
"mozilla-overlay": "mozilla-overlay_2",
"zynq-rs": "zynq-rs"
}
},
"rust-overlay": {
"inputs": {
"nixpkgs": [
"zynq-rs",
"nixpkgs"
]
},
"locked": {
"lastModified": 1719454714,
"narHash": "sha256-MojqG0lyUINkEk0b3kM2drsU5vyaF8DFZe/FAlZVOGs=",
"owner": "oxalica",
"repo": "rust-overlay",
"rev": "d1c527659cf076ecc4b96a91c702d080b213801e",
"type": "github"
},
"original": {
"owner": "oxalica",
"ref": "snapshot/2024-08-01",
"repo": "rust-overlay",
"type": "github"
}
},
"sipyco": {
"inputs": {
"nixpkgs": [
@ -147,11 +137,11 @@
]
},
"locked": {
"lastModified": 1717637367,
"narHash": "sha256-4mSm9wl5EMgzzrW6w86IDUevkEOT99FESHGcxcyQbD0=",
"lastModified": 1733319649,
"narHash": "sha256-ATJV2UV9FXEiTF6/1BvZ2HmB0goF5TZ2ytgRBwD/BGg=",
"owner": "m-labs",
"repo": "sipyco",
"rev": "02b96ec2473a3c3d3c980899de2564ddce949dab",
"rev": "27312727bdb8a182bd6e222e4cbdd3f39ae41d4e",
"type": "github"
},
"original": {
@ -163,11 +153,11 @@
"src-migen": {
"flake": false,
"locked": {
"lastModified": 1715484909,
"narHash": "sha256-4DCHBUBfc/VA+7NW2Hr0+JP4NnKPru2uVJyZjCCk0Ws=",
"lastModified": 1727677091,
"narHash": "sha256-Zg3SQnTwMM/VkOGKogbPyuCC2NhLy8HB2SPEUWWNgCU=",
"owner": "m-labs",
"repo": "migen",
"rev": "4790bb577681a8c3a8d226bc196a4e5deb39e4df",
"rev": "c19ae9f8ae162ffe2d310a92bfce53ac2a821bc8",
"type": "github"
},
"original": {
@ -179,11 +169,11 @@
"src-misoc": {
"flake": false,
"locked": {
"lastModified": 1715647536,
"narHash": "sha256-q+USDcaKHABwW56Jzq8u94iGPWlyLXMyVt0j/Gyg+IE=",
"lastModified": 1729234629,
"narHash": "sha256-TLsTCXV5AC2xh+bS7EhBVBKqdqIU3eKrnlWcFF9LtAM=",
"ref": "refs/heads/master",
"rev": "fea9de558c730bc394a5936094ae95bb9d6fa726",
"revCount": 2455,
"rev": "6085a312bca26adeca6584e37d08c8ba2e1d6e38",
"revCount": 2460,
"submodules": true,
"type": "git",
"url": "https://github.com/m-labs/misoc.git"
@ -227,22 +217,23 @@
},
"zynq-rs": {
"inputs": {
"mozilla-overlay": "mozilla-overlay_3",
"nixpkgs": [
"artiq",
"nixpkgs"
]
],
"rust-overlay": "rust-overlay"
},
"locked": {
"lastModified": 1716889070,
"narHash": "sha256-w+M5NfukmcMTt73+u6Cmltjn4qpQH8bcoTGskB2IzBE=",
"ref": "refs/heads/master",
"rev": "51b8111e799ebe90ca231ae4d02f84ede32632d5",
"revCount": 646,
"lastModified": 1731749494,
"narHash": "sha256-WGigAhvVCGN5YZ1dHPyvoqAh47W1Gtph036O1aKFlLE=",
"ref": "release-8",
"rev": "12975de2e110d7948bf47b768559f727d0abc8fc",
"revCount": 655,
"type": "git",
"url": "https://git.m-labs.hk/m-labs/zynq-rs"
},
"original": {
"ref": "release-8",
"type": "git",
"url": "https://git.m-labs.hk/m-labs/zynq-rs"
}

View File

@ -1,28 +1,28 @@
{
description = "ARTIQ port to the Zynq-7000 platform";
inputs.artiq.url = git+https://github.com/m-labs/artiq.git;
inputs.mozilla-overlay = { url = github:mozilla/nixpkgs-mozilla; flake = false; };
inputs.zynq-rs.url = git+https://git.m-labs.hk/m-labs/zynq-rs;
inputs.artiq.url = git+https://github.com/m-labs/artiq.git?ref=release-8;
inputs.zynq-rs.url = git+https://git.m-labs.hk/m-labs/zynq-rs?ref=release-8;
inputs.zynq-rs.inputs.nixpkgs.follows = "artiq/nixpkgs";
outputs = { self, mozilla-overlay, zynq-rs, artiq }:
outputs = { self, zynq-rs, artiq }:
let
pkgs = import artiq.inputs.nixpkgs { system = "x86_64-linux"; overlays = [ (import mozilla-overlay) ]; };
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;
llvmPackages_11 = zynq-rs.llvmPackages_11;
zynqRev = self.sourceInfo.rev or "unknown";
rust = zynq-rs.rust;
rustPlatform = zynq-rs.rustPlatform;
fastnumbers = pkgs.python3Packages.buildPythonPackage rec {
pname = "fastnumbers";
version = "2.2.1";
version = "5.1.0";
src = pkgs.python3Packages.fetchPypi {
inherit pname version;
sha256 = "0j15i54p7nri6hkzn1wal9pxri4pgql01wgjccig6ar0v5jjbvsy";
sha256 = "sha256-4JLTP4uVwxcaL7NOV57+DFSwKQ3X+W/6onYkN2AdkKc=";
};
};
@ -75,7 +75,7 @@
propagatedBuildInputs = with pkgs.python3Packages; [ setuptools click numpy toolz jinja2 ramda artiqpkgs.migen artiqpkgs.misoc ];
checkInputs = with pkgs.python3Packages; [ pytest-runner pytestCheckHook pytest-timeout ];
checkInputs = with pkgs.python3Packages; [ pytestCheckHook pytest-timeout ];
# migen/misoc version checks are broken with pyproject for some reason
postPatch = ''
@ -137,6 +137,7 @@
llvmPackages_11.clang-unwrapped
];
buildPhase = ''
export ZYNQ_REV=${zynqRev}
export XARGO_RUST_SRC="${rust}/lib/rustlib/src/rust/library"
export CLANG_EXTRA_INCLUDE_DIR="${llvmPackages_11.clang-unwrapped.lib}/lib/clang/11.1.0/include"
export CARGO_HOME=$(mktemp -d cargo-home.XXX)
@ -164,6 +165,7 @@
];
}
''
export ZYNQ_REV=${zynqRev}
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
@ -384,6 +386,7 @@
artiqpkgs.vivado
binutils-arm
];
ZYNQ_REV="${zynqRev}";
XARGO_RUST_SRC = "${rust}/lib/rustlib/src/rust/library";
CLANG_EXTRA_INCLUDE_DIR = "${llvmPackages_11.clang-unwrapped.lib}/lib/clang/11.1.0/include";
ZYNQ_RS = "${zynq-rs}";

View File

@ -1,5 +1,15 @@
import os
from artiq._version import get_version
from misoc.integration import cpu_interface
def generate_ident(variant):
return "{}+{};{}".format(
get_version().split(".")[0],
os.getenv("ZYNQ_REV", default="unknown")[:8],
variant,
)
def write_csr_file(soc, filename):
with open(filename, "w") as f:
f.write(cpu_interface.get_csr_rust(

View File

@ -24,10 +24,10 @@ from artiq.gateware.wrpll import wrpll
import dma
import analyzer
import acpki
import acpki as acpki_lib
import drtio_aux_controller
import zynq_clocking
from config import write_csr_file, write_mem_file, write_rustc_cfg_file
from config import generate_ident, write_csr_file, write_mem_file, write_rustc_cfg_file
eem_iostandard_dict = {
0: "LVDS_25",
@ -115,7 +115,7 @@ class GenericStandalone(SoCCore):
platform.toolchain.bitstream_commands.extend([
"set_property BITSTREAM.GENERAL.COMPRESS True [current_design]",
])
ident = description["variant"]
ident = generate_ident(description["variant"])
if self.acpki:
ident = "acpki_" + ident
SoCCore.__init__(self, platform=platform, csr_data_width=32, ident=ident, ps_cd_sys=False)
@ -184,10 +184,10 @@ class GenericStandalone(SoCCore):
if self.acpki:
self.config["KI_IMPL"] = "acp"
self.submodules.rtio = acpki.KernelInitiator(self.rtio_tsc,
bus=self.ps7.s_axi_acp,
user=self.ps7.s_axi_acp_user,
evento=self.ps7.event.o)
self.submodules.rtio = acpki_lib.KernelInitiator(self.rtio_tsc,
bus=self.ps7.s_axi_acp,
user=self.ps7.s_axi_acp_user,
evento=self.ps7.event.o)
self.csr_devices.append("rtio")
else:
self.config["KI_IMPL"] = "csr"
@ -229,7 +229,7 @@ class GenericMaster(SoCCore):
platform.toolchain.bitstream_commands.extend([
"set_property BITSTREAM.GENERAL.COMPRESS True [current_design]",
])
ident = description["variant"]
ident = generate_ident(description["variant"])
if self.acpki:
ident = "acpki_" + ident
SoCCore.__init__(self, platform=platform, csr_data_width=32, ident=ident, ps_cd_sys=False)
@ -349,10 +349,10 @@ class GenericMaster(SoCCore):
if self.acpki:
self.config["KI_IMPL"] = "acp"
self.submodules.rtio = acpki.KernelInitiator(self.rtio_tsc,
bus=self.ps7.s_axi_acp,
user=self.ps7.s_axi_acp_user,
evento=self.ps7.event.o)
self.submodules.rtio = acpki_lib.KernelInitiator(self.rtio_tsc,
bus=self.ps7.s_axi_acp,
user=self.ps7.s_axi_acp_user,
evento=self.ps7.event.o)
self.csr_devices.append("rtio")
else:
self.config["KI_IMPL"] = "csr"
@ -438,7 +438,7 @@ class GenericSatellite(SoCCore):
platform.toolchain.bitstream_commands.extend([
"set_property BITSTREAM.GENERAL.COMPRESS True [current_design]",
])
ident = description["variant"]
ident = generate_ident(description["variant"])
if self.acpki:
ident = "acpki_" + ident
SoCCore.__init__(self, platform=platform, csr_data_width=32, ident=ident, ps_cd_sys=False)
@ -544,10 +544,10 @@ class GenericSatellite(SoCCore):
if self.acpki:
self.config["KI_IMPL"] = "acp"
self.submodules.rtio = acpki.KernelInitiator(self.rtio_tsc,
bus=self.ps7.s_axi_acp,
user=self.ps7.s_axi_acp_user,
evento=self.ps7.event.o)
self.submodules.rtio = acpki_lib.KernelInitiator(self.rtio_tsc,
bus=self.ps7.s_axi_acp,
user=self.ps7.s_axi_acp_user,
evento=self.ps7.event.o)
self.csr_devices.append("rtio")
else:
self.config["KI_IMPL"] = "csr"
@ -560,7 +560,10 @@ class GenericSatellite(SoCCore):
self.submodules.local_io = SyncRTIO(
self.rtio_tsc, self.rtio_channels, lane_count=description["sed_lanes"]
)
self.comb += self.drtiosat.async_errors.eq(self.local_io.async_errors)
self.comb += [
self.drtiosat.async_errors.eq(self.local_io.async_errors),
self.local_io.sed_spread_enable.eq(self.drtiosat.sed_spread_enable.storage)
]
self.submodules.cri_con = rtio.CRIInterconnectShared(
[self.drtiosat.cri, self.rtio_dma.cri, self.rtio.cri],

View File

@ -25,7 +25,7 @@ import analyzer
import acpki
import drtio_aux_controller
import zynq_clocking
from config import write_csr_file, write_mem_file, write_rustc_cfg_file
from config import generate_ident, write_csr_file, write_mem_file, write_rustc_cfg_file
class SMAClkinForward(Module):
def __init__(self, platform):
@ -130,7 +130,7 @@ class ZC706(SoCCore):
platform = zc706.Platform()
prepare_zc706_platform(platform)
ident = self.__class__.__name__
ident = generate_ident(self.__class__.__name__)
if self.acpki:
ident = "acpki_" + ident
SoCCore.__init__(self, platform=platform, csr_data_width=32, ident=ident, ps_cd_sys=False)
@ -203,7 +203,7 @@ class _MasterBase(SoCCore):
platform = zc706.Platform()
prepare_zc706_platform(platform)
ident = self.__class__.__name__
ident = generate_ident(self.__class__.__name__)
if self.acpki:
ident = "acpki_" + ident
SoCCore.__init__(self, platform=platform, csr_data_width=32, ident=ident, ps_cd_sys=False)
@ -344,7 +344,7 @@ class _SatelliteBase(SoCCore):
platform = zc706.Platform()
prepare_zc706_platform(platform)
ident = self.__class__.__name__
ident = generate_ident(self.__class__.__name__)
if self.acpki:
ident = "acpki_" + ident
SoCCore.__init__(self, platform=platform, csr_data_width=32, ident=ident, ps_cd_sys=False)
@ -487,6 +487,10 @@ class _SatelliteBase(SoCCore):
self.csr_devices.append("rtio_dma")
self.submodules.local_io = SyncRTIO(self.rtio_tsc, rtio_channels)
self.comb += [
self.drtiosat.async_errors.eq(self.local_io.async_errors),
self.local_io.sed_spread_enable.eq(self.drtiosat.sed_spread_enable.storage)
]
self.submodules.cri_con = rtio.CRIInterconnectShared(
[self.drtiosat.cri, self.rtio_dma.cri, self.rtio.cri],
[self.local_io.cri] + self.drtio_cri,

View File

@ -6,7 +6,7 @@ use io::{proto::{ProtoRead, ProtoWrite},
Cursor};
use libboard_zynq::{time::Milliseconds, timer::GlobalTimer};
pub use crate::drtioaux_proto::Packet;
pub use crate::drtioaux_proto::{Packet, MAX_PACKET};
use crate::{drtioaux_proto::Error as ProtocolError, mem::mem::DRTIOAUX_MEM, pl::csr::DRTIOAUX};
#[derive(Debug)]
@ -35,6 +35,15 @@ impl From<IoError> for Error {
}
}
pub fn copy_work_buffer(src: *mut u32, dst: *mut u32, len: isize) {
// fix for artiq-zynq#344
unsafe {
for i in 0..(len / 4) {
*dst.offset(i) = *src.offset(i);
}
}
}
pub fn reset(linkno: u8) {
let linkno = linkno as usize;
unsafe {
@ -115,7 +124,9 @@ where F: FnOnce(&mut [u8]) -> Result<usize, Error> {
unsafe {
while (DRTIOAUX[linkno].aux_tx_read)() != 0 {}
let ptr = DRTIOAUX_MEM[linkno].base as *mut u32;
let len = f(slice::from_raw_parts_mut(ptr as *mut u8, 0x400 as usize))?;
let mut buf: [u8; MAX_PACKET] = [0; MAX_PACKET];
let len = f(&mut buf)?;
copy_work_buffer(buf.as_mut_ptr() as *mut u32, ptr, len as isize);
(DRTIOAUX[linkno].aux_tx_length_write)(len as u16);
(DRTIOAUX[linkno].aux_tx_write)(1);
Ok(())

View File

@ -9,8 +9,8 @@ use libboard_zynq::{time::Milliseconds, timer::GlobalTimer};
use nb;
use void::Void;
pub use crate::drtioaux_proto::Packet;
use crate::{drtioaux::{has_rx_error, Error},
pub use crate::drtioaux_proto::{Packet, MAX_PACKET};
use crate::{drtioaux::{copy_work_buffer, has_rx_error, Error},
mem::mem::DRTIOAUX_MEM,
pl::csr::DRTIOAUX};
@ -102,7 +102,9 @@ where F: FnOnce(&mut [u8]) -> Result<usize, Error> {
unsafe {
let _ = block_async!(tx_ready(linkno)).await;
let ptr = DRTIOAUX_MEM[linkno].base as *mut u32;
let len = f(slice::from_raw_parts_mut(ptr as *mut u8, 0x400 as usize))?;
let mut buf: [u8; MAX_PACKET] = [0; MAX_PACKET];
let len = f(&mut buf)?;
copy_work_buffer(buf.as_mut_ptr() as *mut u32, ptr, len as isize);
(DRTIOAUX[linkno].aux_tx_length_write)(len as u16);
(DRTIOAUX[linkno].aux_tx_write)(1);
Ok(())

View File

@ -1,7 +1,7 @@
use core_io::{Error as IoError, Read, Write};
use io::proto::{ProtoRead, ProtoWrite};
const MAX_PACKET: usize = 1024;
pub const MAX_PACKET: usize = 1024;
// maximum size of arbitrary payloads
// used by satellite -> master analyzer, subkernel exceptions
@ -255,6 +255,7 @@ pub enum Packet {
destination: u8,
id: u32,
run: bool,
timestamp: u64,
},
SubkernelLoadRunReply {
destination: u8,
@ -267,12 +268,14 @@ pub enum Packet {
exception_src: u8,
},
SubkernelExceptionRequest {
source: u8,
destination: u8,
},
SubkernelException {
destination: u8,
last: bool,
length: u16,
data: [u8; SAT_PAYLOAD_MAX_SIZE],
data: [u8; MASTER_PAYLOAD_MAX_SIZE],
},
SubkernelMessage {
source: u8,
@ -512,6 +515,7 @@ impl Packet {
destination: reader.read_u8()?,
id: reader.read_u32()?,
run: reader.read_bool()?,
timestamp: reader.read_u64()?,
},
0xc5 => Packet::SubkernelLoadRunReply {
destination: reader.read_u8()?,
@ -524,14 +528,17 @@ impl Packet {
exception_src: reader.read_u8()?,
},
0xc9 => Packet::SubkernelExceptionRequest {
source: reader.read_u8()?,
destination: reader.read_u8()?,
},
0xca => {
let destination = reader.read_u8()?;
let last = reader.read_bool()?;
let length = reader.read_u16()?;
let mut data: [u8; SAT_PAYLOAD_MAX_SIZE] = [0; SAT_PAYLOAD_MAX_SIZE];
let mut data: [u8; MASTER_PAYLOAD_MAX_SIZE] = [0; MASTER_PAYLOAD_MAX_SIZE];
reader.read_exact(&mut data[0..length as usize])?;
Packet::SubkernelException {
destination: destination,
last: last,
length: length,
data: data,
@ -872,12 +879,14 @@ impl Packet {
destination,
id,
run,
timestamp,
} => {
writer.write_u8(0xc4)?;
writer.write_u8(source)?;
writer.write_u8(destination)?;
writer.write_u32(id)?;
writer.write_bool(run)?;
writer.write_u64(timestamp)?;
}
Packet::SubkernelLoadRunReply { destination, succeeded } => {
writer.write_u8(0xc5)?;
@ -896,12 +905,19 @@ impl Packet {
writer.write_bool(with_exception)?;
writer.write_u8(exception_src)?;
}
Packet::SubkernelExceptionRequest { destination } => {
Packet::SubkernelExceptionRequest { source, destination } => {
writer.write_u8(0xc9)?;
writer.write_u8(source)?;
writer.write_u8(destination)?;
}
Packet::SubkernelException { last, length, data } => {
Packet::SubkernelException {
destination,
last,
length,
data,
} => {
writer.write_u8(0xca)?;
writer.write_u8(destination)?;
writer.write_bool(last)?;
writer.write_u16(length)?;
writer.write_all(&data[0..length as usize])?;
@ -943,6 +959,8 @@ impl Packet {
Packet::SubkernelLoadRunReply { destination, .. } => Some(*destination),
Packet::SubkernelMessage { destination, .. } => Some(*destination),
Packet::SubkernelMessageAck { destination } => Some(*destination),
Packet::SubkernelExceptionRequest { destination, .. } => Some(*destination),
Packet::SubkernelException { destination, .. } => Some(*destination),
Packet::DmaPlaybackStatus { destination, .. } => Some(*destination),
Packet::SubkernelFinished { destination, .. } => Some(*destination),
_ => None,
@ -960,7 +978,8 @@ impl Packet {
| Packet::SubkernelLoadRunReply { .. }
| Packet::SubkernelMessageAck { .. }
| Packet::DmaPlaybackStatus { .. }
| Packet::SubkernelFinished { .. } => false,
| Packet::SubkernelFinished { .. }
| Packet::InjectionRequest { .. } => false,
_ => true,
}
}

View File

@ -85,10 +85,7 @@ unsafe fn get_ttype_entry(
encoding | DW_EH_PE_pcrel,
ttype_base,
)
.map(|v| match v {
ttype_base => None,
ttype_entry => Some(ttype_entry as *const u8),
})
.map(|v| (v != ttype_base).then(|| v as *const u8))
}
pub unsafe fn find_eh_action(

View File

@ -14,8 +14,10 @@
use core::mem;
use cslice::CSlice;
use core_io::Error as ReadError;
use cslice::{AsCSlice, CSlice};
use dwarf::eh::{self, EHAction, EHContext};
use io::{Cursor, ProtoRead};
use libc::{c_int, c_void, uintptr_t};
use log::{error, trace};
use unwind as uw;
@ -220,8 +222,6 @@ pub unsafe fn artiq_personality(
}
pub unsafe extern "C" fn raise(exception: *const Exception) -> ! {
use cslice::AsCSlice;
let count = EXCEPTION_BUFFER.exception_count;
let stack = &mut EXCEPTION_BUFFER.exception_stack;
let diff = exception as isize - EXCEPTION_BUFFER.exceptions.as_ptr() as isize;
@ -295,6 +295,60 @@ pub unsafe extern "C" fn raise(exception: *const Exception) -> ! {
unreachable!();
}
fn read_exception_string<'a>(reader: &mut Cursor<&[u8]>) -> Result<CSlice<'a, u8>, ReadError> {
let len = reader.read_u32()? as usize;
if len == usize::MAX {
let data = reader.read_u32()?;
Ok(unsafe { CSlice::new(data as *const u8, len) })
} else {
let pos = reader.position();
let slice = unsafe {
let ptr = reader.get_ref().as_ptr().offset(pos as isize);
CSlice::new(ptr, len)
};
reader.set_position(pos + len);
Ok(slice)
}
}
fn read_exception(raw_exception: &[u8]) -> Result<Exception, ReadError> {
let mut reader = Cursor::new(raw_exception);
let mut byte = reader.read_u8()?;
// to sync
while byte != 0x5a {
byte = reader.read_u8()?;
}
// skip sync bytes, 0x09 indicates exception
while byte != 0x09 {
byte = reader.read_u8()?;
}
let _len = reader.read_u32()?;
// ignore the remaining exceptions, stack traces etc. - unwinding from another device would be unwise anyway
Ok(Exception {
id: reader.read_u32()?,
message: read_exception_string(&mut reader)?,
param: [
reader.read_u64()? as i64,
reader.read_u64()? as i64,
reader.read_u64()? as i64,
],
file: read_exception_string(&mut reader)?,
line: reader.read_u32()?,
column: reader.read_u32()?,
function: read_exception_string(&mut reader)?,
})
}
pub fn raise_raw(raw_exception: &[u8]) -> ! {
use crate::artiq_raise;
if let Ok(exception) = read_exception(raw_exception) {
unsafe { raise(&exception) };
} else {
artiq_raise!("SubkernelError", "Error passing exception");
}
}
pub unsafe extern "C" fn resume() -> ! {
trace!("resume");
assert!(EXCEPTION_BUFFER.exception_count != 0);
@ -421,7 +475,7 @@ extern "C" fn stop_fn(
}
}
// Must be kept in sync with preallocate_runtime_exception_names() in artiq/language/embedding_map.py
// Must be kept in sync with preallocate_runtime_exception_names() in `artiq.compiler.embedding`
static EXCEPTION_ID_LOOKUP: [(&str, u32); 12] = [
("RuntimeError", 0),
("RTIOUnderflow", 1),
@ -469,3 +523,29 @@ macro_rules! artiq_raise {
}};
($name:expr, $message:expr) => {{ artiq_raise!($name, $message, 0, 0, 0) }};
}
/// Takes as input exception id from host
/// Generates a new exception with:
/// * `id` set to `exn_id`
/// * `message` set to corresponding exception name from `EXCEPTION_ID_LOOKUP`
///
/// The message is matched on host to ensure correct exception is being referred
/// This test checks the synchronization of exception ids for runtime errors
#[no_mangle]
pub extern "C" fn test_exception_id_sync(exn_id: u32) {
let message = EXCEPTION_ID_LOOKUP
.iter()
.find_map(|&(name, id)| if id == exn_id { Some(name) } else { None })
.unwrap_or("unallocated internal exception id");
let exn = Exception {
id: exn_id,
file: file!().as_c_slice(),
line: 0,
column: 0,
function: "test_exception_id_sync".as_c_slice(),
message: message.as_c_slice(),
param: [0, 0, 0],
};
unsafe { raise(&exn) };
}

View File

@ -303,6 +303,7 @@ pub fn resolve(required: &[u8]) -> Option<u32> {
api_libm_f64f64f64!(nextafter),
api_libm_f64f64f64!(pow),
api_libm_f64f64!(round),
api_libm_f64f64!(rint),
api_libm_f64f64!(sin),
api_libm_f64f64!(sinh),
api_libm_f64f64!(sqrt),
@ -318,6 +319,13 @@ pub fn resolve(required: &[u8]) -> Option<u32> {
}
api!(yn = yn)
},
/*
* syscall for unit tests
* Used in `artiq.tests.coredevice.test_exceptions.ExceptionTest.test_raise_exceptions_kernel`
* This syscall checks that the exception IDs used in the Python `EmbeddingMap` (in `artiq.language.embedding`)
* match the `EXCEPTION_ID_LOOKUP` defined in the firmware (`libksupport::src::eh_artiq`)
*/
api!(test_exception_id_sync = eh_artiq::test_exception_id_sync)
];
api.iter()
.find(|&&(exported, _)| exported.as_bytes() == required)

View File

@ -23,6 +23,7 @@ pub enum SubkernelStatus {
Timeout,
IncorrectState,
CommLost,
Exception(Vec<u8>),
OtherError,
}
@ -79,6 +80,7 @@ pub enum Message {
id: u32,
destination: u8,
run: bool,
timestamp: u64,
},
#[cfg(has_drtio)]
SubkernelLoadRunReply {
@ -90,9 +92,7 @@ pub enum Message {
timeout: i64,
},
#[cfg(has_drtio)]
SubkernelAwaitFinishReply {
status: SubkernelStatus,
},
SubkernelAwaitFinishReply,
#[cfg(has_drtio)]
SubkernelMsgSend {
id: u32,
@ -109,9 +109,10 @@ pub enum Message {
},
#[cfg(has_drtio)]
SubkernelMsgRecvReply {
status: SubkernelStatus,
count: u8,
},
#[cfg(has_drtio)]
SubkernelError(SubkernelStatus),
}
static CHANNEL_0TO1: Mutex<Option<sync_channel::Sender<'static, Message>>> = Mutex::new(None);

View File

@ -3,7 +3,7 @@ use alloc::vec::Vec;
use cslice::CSlice;
use super::{Message, SubkernelStatus, KERNEL_CHANNEL_0TO1, KERNEL_CHANNEL_1TO0};
use crate::{artiq_raise, rpc::send_args};
use crate::{artiq_raise, eh_artiq, rpc::send_args, rtio::now_mu};
pub extern "C" fn load_run(id: u32, destination: u8, run: bool) {
unsafe {
@ -14,6 +14,7 @@ pub extern "C" fn load_run(id: u32, destination: u8, run: bool) {
id: id,
destination: destination,
run: run,
timestamp: now_mu() as u64,
});
}
match unsafe { KERNEL_CHANNEL_0TO1.as_mut().unwrap() }.recv() {
@ -36,21 +37,18 @@ pub extern "C" fn await_finish(id: u32, timeout: i64) {
});
}
match unsafe { KERNEL_CHANNEL_0TO1.as_mut().unwrap() }.recv() {
Message::SubkernelAwaitFinishReply {
status: SubkernelStatus::NoError,
} => (),
Message::SubkernelAwaitFinishReply {
status: SubkernelStatus::IncorrectState,
} => artiq_raise!("SubkernelError", "Subkernel not running"),
Message::SubkernelAwaitFinishReply {
status: SubkernelStatus::Timeout,
} => artiq_raise!("SubkernelError", "Subkernel timed out"),
Message::SubkernelAwaitFinishReply {
status: SubkernelStatus::CommLost,
} => artiq_raise!("SubkernelError", "Lost communication with satellite"),
Message::SubkernelAwaitFinishReply {
status: SubkernelStatus::OtherError,
} => artiq_raise!("SubkernelError", "An error occurred during subkernel operation"),
Message::SubkernelAwaitFinishReply => (),
Message::SubkernelError(SubkernelStatus::IncorrectState) => {
artiq_raise!("SubkernelError", "Subkernel not running")
}
Message::SubkernelError(SubkernelStatus::Timeout) => artiq_raise!("SubkernelError", "Subkernel timed out"),
Message::SubkernelError(SubkernelStatus::CommLost) => {
artiq_raise!("SubkernelError", "Lost communication with satellite")
}
Message::SubkernelError(SubkernelStatus::OtherError) => {
artiq_raise!("SubkernelError", "An error occurred during subkernel operation")
}
Message::SubkernelError(SubkernelStatus::Exception(raw_exception)) => eh_artiq::raise_raw(&raw_exception),
_ => panic!("expected SubkernelAwaitFinishReply after SubkernelAwaitFinishRequest"),
}
}
@ -92,30 +90,22 @@ pub extern "C" fn await_message(id: i32, timeout: i64, tags: &CSlice<u8>, min: u
});
}
match unsafe { KERNEL_CHANNEL_0TO1.as_mut().unwrap() }.recv() {
Message::SubkernelMsgRecvReply {
status: SubkernelStatus::NoError,
count,
} => {
Message::SubkernelMsgRecvReply { count } => {
if min > count || count > max {
artiq_raise!("SubkernelError", "Received more or less arguments than required")
}
}
Message::SubkernelMsgRecvReply {
status: SubkernelStatus::IncorrectState,
..
} => artiq_raise!("SubkernelError", "Subkernel not running"),
Message::SubkernelMsgRecvReply {
status: SubkernelStatus::Timeout,
..
} => artiq_raise!("SubkernelError", "Subkernel timed out"),
Message::SubkernelMsgRecvReply {
status: SubkernelStatus::CommLost,
..
} => artiq_raise!("SubkernelError", "Lost communication with satellite"),
Message::SubkernelMsgRecvReply {
status: SubkernelStatus::OtherError,
..
} => artiq_raise!("SubkernelError", "An error occurred during subkernel operation"),
Message::SubkernelError(SubkernelStatus::IncorrectState) => {
artiq_raise!("SubkernelError", "Subkernel not running")
}
Message::SubkernelError(SubkernelStatus::Timeout) => artiq_raise!("SubkernelError", "Subkernel timed out"),
Message::SubkernelError(SubkernelStatus::CommLost) => {
artiq_raise!("SubkernelError", "Lost communication with satellite")
}
Message::SubkernelError(SubkernelStatus::OtherError) => {
artiq_raise!("SubkernelError", "An error occurred during subkernel operation")
}
Message::SubkernelError(SubkernelStatus::Exception(raw_exception)) => eh_artiq::raise_raw(&raw_exception),
_ => panic!("expected SubkernelMsgRecvReply after SubkernelMsgRecvRequest"),
}
// RpcRecvRequest should be called after this to receive message data

View File

@ -405,8 +405,9 @@ async fn handle_run_kernel(
id,
destination: _,
run,
timestamp,
} => {
let succeeded = match subkernel::load(aux_mutex, routing_table, timer, id, run).await {
let succeeded = match subkernel::load(aux_mutex, routing_table, timer, id, run, timestamp).await {
Ok(()) => true,
Err(e) => {
error!("Error loading subkernel: {:?}", e);
@ -422,33 +423,23 @@ async fn handle_run_kernel(
#[cfg(has_drtio)]
kernel::Message::SubkernelAwaitFinishRequest { id, timeout } => {
let res = subkernel::await_finish(aux_mutex, routing_table, timer, id, timeout).await;
let status = match res {
Ok(ref res) => {
let response = match res {
Ok(res) => {
if res.status == subkernel::FinishStatus::CommLost {
kernel::SubkernelStatus::CommLost
} else if let Some(exception) = &res.exception {
error!("Exception in subkernel");
match stream {
None => (),
Some(stream) => {
write_chunk(stream, exception).await?;
}
}
// will not be called after exception is served
kernel::SubkernelStatus::OtherError
kernel::Message::SubkernelError(kernel::SubkernelStatus::CommLost)
} else if let Some(exception) = res.exception {
kernel::Message::SubkernelError(kernel::SubkernelStatus::Exception(exception))
} else {
kernel::SubkernelStatus::NoError
kernel::Message::SubkernelAwaitFinishReply
}
}
Err(SubkernelError::Timeout) => kernel::SubkernelStatus::Timeout,
Err(SubkernelError::IncorrectState) => kernel::SubkernelStatus::IncorrectState,
Err(_) => kernel::SubkernelStatus::OtherError,
Err(SubkernelError::Timeout) => kernel::Message::SubkernelError(kernel::SubkernelStatus::Timeout),
Err(SubkernelError::IncorrectState) => {
kernel::Message::SubkernelError(kernel::SubkernelStatus::IncorrectState)
}
Err(_) => kernel::Message::SubkernelError(kernel::SubkernelStatus::OtherError),
};
control
.borrow_mut()
.tx
.async_send(kernel::Message::SubkernelAwaitFinishReply { status: status })
.await;
control.borrow_mut().tx.async_send(response).await;
}
#[cfg(has_drtio)]
kernel::Message::SubkernelMsgSend { id, destination, data } => {
@ -469,35 +460,23 @@ async fn handle_run_kernel(
#[cfg(has_drtio)]
kernel::Message::SubkernelMsgRecvRequest { id, timeout, tags } => {
let message_received = subkernel::message_await(id as u32, timeout, timer).await;
let (status, count) = match message_received {
Ok(ref message) => (kernel::SubkernelStatus::NoError, message.count),
Err(SubkernelError::Timeout) => (kernel::SubkernelStatus::Timeout, 0),
Err(SubkernelError::IncorrectState) => (kernel::SubkernelStatus::IncorrectState, 0),
Err(SubkernelError::CommLost) => (kernel::SubkernelStatus::CommLost, 0),
let response = match message_received {
Ok(ref message) => kernel::Message::SubkernelMsgRecvReply { count: message.count },
Err(SubkernelError::Timeout) => kernel::Message::SubkernelError(kernel::SubkernelStatus::Timeout),
Err(SubkernelError::IncorrectState) => {
kernel::Message::SubkernelError(kernel::SubkernelStatus::IncorrectState)
}
Err(SubkernelError::CommLost) => kernel::Message::SubkernelError(kernel::SubkernelStatus::CommLost),
Err(SubkernelError::SubkernelException) => {
error!("Exception in subkernel");
// just retrieve the exception
let status = subkernel::await_finish(aux_mutex, routing_table, timer, id as u32, timeout)
.await
.unwrap();
match stream {
None => (),
Some(stream) => {
write_chunk(stream, &status.exception.unwrap()).await?;
}
}
(kernel::SubkernelStatus::OtherError, 0)
kernel::Message::SubkernelError(kernel::SubkernelStatus::Exception(status.exception.unwrap()))
}
Err(_) => (kernel::SubkernelStatus::OtherError, 0),
Err(_) => kernel::Message::SubkernelError(kernel::SubkernelStatus::OtherError),
};
control
.borrow_mut()
.tx
.async_send(kernel::Message::SubkernelMsgRecvReply {
status: status,
count: count,
})
.await;
control.borrow_mut().tx.async_send(response).await;
if let Ok(message) = message_received {
// receive code almost identical to RPC recv, except we are not reading from a stream
let mut reader = Cursor::new(message.data);
@ -529,7 +508,7 @@ async fn handle_run_kernel(
.async_send(kernel::Message::RpcRecvReply(Ok(0)))
.await;
i += 1;
if i < count {
if i < message.count {
current_tags = remaining_tags;
} else {
break;
@ -718,6 +697,27 @@ async fn handle_connection(
}
}
async fn load_and_run_idle_kernel(
buffer: &Vec<u8>,
control: &Rc<RefCell<kernel::Control>>,
up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>,
aux_mutex: &Rc<Mutex<bool>>,
routing_table: &drtio_routing::RoutingTable,
timer: GlobalTimer,
) {
info!("Loading idle kernel");
let res = handle_flash_kernel(buffer, control, up_destinations, aux_mutex, routing_table, timer).await;
match res {
Err(_) => warn!("error loading idle kernel"),
_ => (),
}
info!("Running idle kernel");
let _ = handle_run_kernel(None, control, up_destinations, aux_mutex, routing_table, timer)
.await
.map_err(|_| warn!("error running idle kernel"));
info!("Idle kernel terminated");
}
pub fn main(timer: GlobalTimer, cfg: Config) {
let net_addresses = net_settings::get_addresses(&cfg);
info!("network addresses: {}", net_addresses);
@ -771,7 +771,7 @@ pub fn main(timer: GlobalTimer, cfg: Config) {
#[cfg(has_drtio_routing)]
drtio_routing::interconnect_disable_all();
rtio_mgt::startup(&aux_mutex, &drtio_routing_table, &up_destinations, timer);
rtio_mgt::startup(&aux_mutex, &drtio_routing_table, &up_destinations, &cfg, timer);
ksupport::setup_device_map(&cfg);
analyzer::start(&aux_mutex, &drtio_routing_table, &up_destinations, timer);
@ -808,8 +808,30 @@ pub fn main(timer: GlobalTimer, cfg: Config) {
mgmt::start(cfg);
task::spawn(async move {
let connection = Rc::new(Semaphore::new(1, 1));
let connection = Rc::new(Semaphore::new(0, 1));
let terminate = Rc::new(Semaphore::new(0, 1));
{
let control = control.clone();
let idle_kernel = idle_kernel.clone();
let connection = connection.clone();
let terminate = terminate.clone();
let up_destinations = up_destinations.clone();
let aux_mutex = aux_mutex.clone();
let routing_table = drtio_routing_table.clone();
task::spawn(async move {
let routing_table = routing_table.borrow();
select_biased! {
_ = (async {
if let Some(buffer) = &*idle_kernel {
load_and_run_idle_kernel(&buffer, &control, &up_destinations, &aux_mutex, &routing_table, timer).await;
}
}).fuse() => (),
_ = terminate.async_wait().fuse() => ()
}
connection.signal();
});
}
loop {
let mut stream = TcpStream::accept(1381, 0x10_000, 0x10_000).await.unwrap();
@ -837,22 +859,7 @@ pub fn main(timer: GlobalTimer, cfg: Config) {
.await
.map_err(|e| warn!("connection terminated: {}", e));
if let Some(buffer) = &*idle_kernel {
info!("Loading idle kernel");
let res = handle_flash_kernel(&buffer, &control, &up_destinations, &aux_mutex, &routing_table, timer)
.await;
match res {
#[cfg(has_drtio)]
Err(Error::DestinationDown) => {
let mut countdown = timer.countdown();
delay(&mut countdown, Milliseconds(500)).await;
}
Err(_) => warn!("error loading idle kernel"),
_ => (),
}
info!("Running idle kernel");
let _ = handle_run_kernel(None, &control, &up_destinations, &aux_mutex, &routing_table, timer)
.await.map_err(|_| warn!("error running idle kernel"));
info!("Idle kernel terminated");
load_and_run_idle_kernel(&buffer, &control, &up_destinations, &aux_mutex, &routing_table, timer).await;
}
}).fuse() => (),
_ = terminate.async_wait().fuse() => ()

View File

@ -102,7 +102,7 @@ mod remote_moninj {
overrd: i8,
value: i8,
) {
let _lock = aux_mutex.lock();
let _lock = aux_mutex.async_lock().await;
drtioaux_async::send(
linkno,
&drtioaux_async::Packet::InjectionRequest {

View File

@ -3,7 +3,9 @@ use core::cell::RefCell;
use libboard_artiq::{drtio_routing, drtio_routing::RoutingTable, pl::csr};
use libboard_zynq::timer::GlobalTimer;
use libconfig::Config;
use libcortex_a9::mutex::Mutex;
use log::{info, warn};
#[cfg(has_drtio)]
pub mod drtio {
@ -127,6 +129,8 @@ pub mod drtio {
| Packet::SubkernelLoadRunReply { destination, .. }
| Packet::SubkernelMessage { destination, .. }
| Packet::SubkernelMessageAck { destination, .. }
| Packet::SubkernelException { destination, .. }
| Packet::SubkernelExceptionRequest { destination, .. }
| Packet::DmaPlaybackStatus { destination, .. }
| Packet::SubkernelFinished { destination, .. } => {
if destination == 0 {
@ -181,10 +185,7 @@ pub mod drtio {
async fn drain_buffer(linkno: u8, draining_time: Milliseconds, timer: GlobalTimer) {
let max_time = timer.get_time() + draining_time;
loop {
if timer.get_time() > max_time {
return;
}
while timer.get_time() < max_time {
let _ = drtioaux_async::recv(linkno).await;
}
}
@ -791,6 +792,7 @@ pub mod drtio {
id: u32,
destination: u8,
run: bool,
timestamp: u64,
) -> Result<(), Error> {
let linkno = routing_table.0[destination as usize][0] - 1;
let reply = aux_transact(
@ -802,6 +804,7 @@ pub mod drtio {
source: 0,
destination: destination,
run: run,
timestamp,
},
timer,
)
@ -833,13 +836,19 @@ pub mod drtio {
linkno,
routing_table,
&Packet::SubkernelExceptionRequest {
source: 0,
destination: destination,
},
timer,
)
.await?;
match reply {
Packet::SubkernelException { last, length, data } => {
Packet::SubkernelException {
destination: 0,
last,
length,
data,
} => {
remote_data.extend(&data[0..length as usize]);
if last {
return Ok(remote_data);
@ -898,12 +907,36 @@ pub mod drtio {
pub fn reset(_aux_mutex: Rc<Mutex<bool>>, _routing_table: &RoutingTable, mut _timer: GlobalTimer) {}
}
fn toggle_sed_spread(val: u8) {
unsafe {
csr::rtio_core::sed_spread_enable_write(val);
}
}
fn setup_sed_spread(cfg: &Config) {
if let Ok(spread_enable) = cfg.read_str("sed_spread_enable") {
match spread_enable.as_ref() {
"1" => toggle_sed_spread(1),
"0" => toggle_sed_spread(0),
_ => {
warn!("sed_spread_enable value not supported (only 1, 0 allowed), disabling by default");
toggle_sed_spread(0)
}
};
} else {
info!("SED spreading disabled by default");
toggle_sed_spread(0);
}
}
pub fn startup(
aux_mutex: &Rc<Mutex<bool>>,
routing_table: &Rc<RefCell<RoutingTable>>,
up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>,
cfg: &Config,
timer: GlobalTimer,
) {
setup_sed_spread(cfg);
drtio::startup(aux_mutex, routing_table, up_destinations, timer);
unsafe {
csr::rtio_core::reset_phy_write(1);

View File

@ -100,12 +100,22 @@ pub async fn load(
timer: GlobalTimer,
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, timer, id, subkernel.destination, run).await?;
drtio::subkernel_load(
aux_mutex,
routing_table,
timer,
id,
subkernel.destination,
run,
timestamp,
)
.await?;
if run {
subkernel.state = SubkernelState::Running;
}

View File

@ -12,6 +12,7 @@ extern crate io;
extern crate ksupport;
extern crate libboard_artiq;
extern crate libboard_zynq;
extern crate libconfig;
extern crate libcortex_a9;
extern crate libregister;
extern crate libsupport_zynq;
@ -38,6 +39,7 @@ use libboard_artiq::{drtio_routing, drtioaux,
#[cfg(feature = "target_kasli_soc")]
use libboard_zynq::error_led::ErrorLED;
use libboard_zynq::{i2c::I2c, print, println, time::Milliseconds, timer::GlobalTimer};
use libconfig::Config;
use libcortex_a9::{l2c::enable_l2_cache, regs::MPIDR};
use libregister::RegisterR;
use libsupport_zynq::{exception_vectors, ram};
@ -81,15 +83,37 @@ fn drtiosat_tsc_loaded() -> bool {
}
}
fn toggle_sed_spread(val: u8) {
unsafe {
csr::drtiosat::sed_spread_enable_write(val);
}
}
#[cfg(has_drtio_routing)]
macro_rules! forward {
($routing_table:expr, $destination:expr, $rank:expr, $repeaters:expr, $packet:expr, $timer:expr) => {{
(
$router:expr,
$routing_table:expr,
$destination:expr,
$rank:expr,
$self_destination:expr,
$repeaters:expr,
$packet:expr,
$timer:expr
) => {{
let hop = $routing_table.0[$destination as usize][$rank as usize];
if hop != 0 {
let repno = (hop - 1) as usize;
if repno < $repeaters.len() {
if $packet.expects_response() {
return $repeaters[repno].aux_forward($packet, $timer);
return $repeaters[repno].aux_forward(
$packet,
$router,
$routing_table,
$rank,
$self_destination,
$timer,
);
} else {
return $repeaters[repno].aux_send($packet);
}
@ -102,7 +126,16 @@ macro_rules! forward {
#[cfg(not(has_drtio_routing))]
macro_rules! forward {
($routing_table:expr, $destination:expr, $rank:expr, $repeaters:expr, $packet:expr, $timer:expr) => {};
(
$router:expr,
$routing_table:expr,
$destination:expr,
$rank:expr,
$self_destination:expr,
$repeaters:expr,
$packet:expr,
$timer:expr
) => {};
}
fn process_aux_packet(
@ -183,6 +216,10 @@ fn process_aux_packet(
&drtioaux::Packet::DestinationStatusRequest {
destination: destination,
},
router,
_routing_table,
*rank,
*self_destination,
timer,
) {
Ok(()) => (),
@ -244,7 +281,16 @@ fn process_aux_packet(
channel,
probe,
} => {
forward!(_routing_table, _destination, *rank, _repeaters, &packet, timer);
forward!(
router,
_routing_table,
_destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
let value;
#[cfg(has_rtio_moninj)]
unsafe {
@ -266,7 +312,16 @@ fn process_aux_packet(
overrd,
value,
} => {
forward!(_routing_table, _destination, *rank, _repeaters, &packet, timer);
forward!(
router,
_routing_table,
_destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
#[cfg(has_rtio_moninj)]
unsafe {
csr::rtio_moninj::inj_chan_sel_write(channel as _);
@ -280,7 +335,16 @@ fn process_aux_packet(
channel,
overrd,
} => {
forward!(_routing_table, _destination, *rank, _repeaters, &packet, timer);
forward!(
router,
_routing_table,
_destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
let value;
#[cfg(has_rtio_moninj)]
unsafe {
@ -299,7 +363,16 @@ fn process_aux_packet(
destination: _destination,
busno: _busno,
} => {
forward!(_routing_table, _destination, *rank, _repeaters, &packet, timer);
forward!(
router,
_routing_table,
_destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
let succeeded = i2c.start().is_ok();
drtioaux::send(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded })
}
@ -307,7 +380,16 @@ fn process_aux_packet(
destination: _destination,
busno: _busno,
} => {
forward!(_routing_table, _destination, *rank, _repeaters, &packet, timer);
forward!(
router,
_routing_table,
_destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
let succeeded = i2c.restart().is_ok();
drtioaux::send(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded })
}
@ -315,7 +397,16 @@ fn process_aux_packet(
destination: _destination,
busno: _busno,
} => {
forward!(_routing_table, _destination, *rank, _repeaters, &packet, timer);
forward!(
router,
_routing_table,
_destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
let succeeded = i2c.stop().is_ok();
drtioaux::send(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded })
}
@ -324,7 +415,16 @@ fn process_aux_packet(
busno: _busno,
data,
} => {
forward!(_routing_table, _destination, *rank, _repeaters, &packet, timer);
forward!(
router,
_routing_table,
_destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
match i2c.write(data) {
Ok(ack) => drtioaux::send(
0,
@ -347,7 +447,16 @@ fn process_aux_packet(
busno: _busno,
ack,
} => {
forward!(_routing_table, _destination, *rank, _repeaters, &packet, timer);
forward!(
router,
_routing_table,
_destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
match i2c.read(ack) {
Ok(data) => drtioaux::send(
0,
@ -371,7 +480,16 @@ fn process_aux_packet(
address,
mask,
} => {
forward!(_routing_table, _destination, *rank, _repeaters, &packet, timer);
forward!(
router,
_routing_table,
_destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
let ch = match mask {
//decode from mainline, PCA9548-centric API
0x00 => None,
@ -397,7 +515,16 @@ fn process_aux_packet(
div: _div,
cs: _cs,
} => {
forward!(_routing_table, _destination, *rank, _repeaters, &packet, timer);
forward!(
router,
_routing_table,
_destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
// todo: reimplement when/if SPI is available
//let succeeded = spi::set_config(busno, flags, length, div, cs).is_ok();
drtioaux::send(0, &drtioaux::Packet::SpiBasicReply { succeeded: false })
@ -407,7 +534,16 @@ fn process_aux_packet(
busno: _busno,
data: _data,
} => {
forward!(_routing_table, _destination, *rank, _repeaters, &packet, timer);
forward!(
router,
_routing_table,
_destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
// todo: reimplement when/if SPI is available
//let succeeded = spi::write(busno, data).is_ok();
drtioaux::send(0, &drtioaux::Packet::SpiBasicReply { succeeded: false })
@ -416,7 +552,16 @@ fn process_aux_packet(
destination: _destination,
busno: _busno,
} => {
forward!(_routing_table, _destination, *rank, _repeaters, &packet, timer);
forward!(
router,
_routing_table,
_destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
// todo: reimplement when/if SPI is available
// match spi::read(busno) {
// Ok(data) => drtioaux::send(0,
@ -436,7 +581,16 @@ fn process_aux_packet(
drtioaux::Packet::AnalyzerHeaderRequest {
destination: _destination,
} => {
forward!(_routing_table, _destination, *rank, _repeaters, &packet, timer);
forward!(
router,
_routing_table,
_destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
let header = analyzer.get_header();
drtioaux::send(
0,
@ -450,7 +604,16 @@ fn process_aux_packet(
drtioaux::Packet::AnalyzerDataRequest {
destination: _destination,
} => {
forward!(_routing_table, _destination, *rank, _repeaters, &packet, timer);
forward!(
router,
_routing_table,
_destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
let mut data_slice: [u8; SAT_PAYLOAD_MAX_SIZE] = [0; SAT_PAYLOAD_MAX_SIZE];
let meta = analyzer.get_data(&mut data_slice);
drtioaux::send(
@ -471,7 +634,16 @@ fn process_aux_packet(
length,
trace,
} => {
forward!(_routing_table, destination, *rank, _repeaters, &packet, timer);
forward!(
router,
_routing_table,
destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
*self_destination = destination;
let succeeded = dma_manager.add(source, id, status, &trace, length as usize).is_ok();
router.send(
@ -492,7 +664,16 @@ fn process_aux_packet(
id,
succeeded,
} => {
forward!(_routing_table, _destination, *rank, _repeaters, &packet, timer);
forward!(
router,
_routing_table,
_destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
dma_manager.ack_upload(
kernel_manager,
source,
@ -510,7 +691,16 @@ fn process_aux_packet(
destination: _destination,
id,
} => {
forward!(_routing_table, _destination, *rank, _repeaters, &packet, timer);
forward!(
router,
_routing_table,
_destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
let succeeded = dma_manager.erase(source, id).is_ok();
router.send(
drtioaux::Packet::DmaRemoveTraceReply {
@ -526,7 +716,16 @@ fn process_aux_packet(
destination: _destination,
succeeded: _,
} => {
forward!(_routing_table, _destination, *rank, _repeaters, &packet, timer);
forward!(
router,
_routing_table,
_destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
Ok(())
}
drtioaux::Packet::DmaPlaybackRequest {
@ -535,7 +734,16 @@ fn process_aux_packet(
id,
timestamp,
} => {
forward!(_routing_table, _destination, *rank, _repeaters, &packet, timer);
forward!(
router,
_routing_table,
_destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
let succeeded = if !kernel_manager.running() {
dma_manager.playback(source, id, timestamp).is_ok()
} else {
@ -555,7 +763,16 @@ fn process_aux_packet(
destination: _destination,
succeeded,
} => {
forward!(_routing_table, _destination, *rank, _repeaters, &packet, timer);
forward!(
router,
_routing_table,
_destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
if !succeeded {
kernel_manager.ddma_nack();
}
@ -569,7 +786,16 @@ fn process_aux_packet(
channel,
timestamp,
} => {
forward!(_routing_table, _destination, *rank, _repeaters, &packet, timer);
forward!(
router,
_routing_table,
_destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
dma_manager.remote_finished(kernel_manager, id, error, channel, timestamp);
Ok(())
}
@ -581,7 +807,16 @@ fn process_aux_packet(
length,
data,
} => {
forward!(_routing_table, destination, *rank, _repeaters, &packet, timer);
forward!(
router,
_routing_table,
destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
*self_destination = destination;
let succeeded = kernel_manager.add(id, status, &data, length as usize).is_ok();
drtioaux::send(0, &drtioaux::Packet::SubkernelAddDataReply { succeeded: succeeded })
@ -591,8 +826,18 @@ fn process_aux_packet(
destination: _destination,
id,
run,
timestamp,
} => {
forward!(_routing_table, _destination, *rank, _repeaters, &packet, timer);
forward!(
router,
_routing_table,
_destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
let mut succeeded = kernel_manager.load(id).is_ok();
// allow preloading a kernel with delayed run
if run {
@ -600,7 +845,7 @@ fn process_aux_packet(
// cannot run kernel while DDMA is running
succeeded = false;
} else {
succeeded |= kernel_manager.run(source, id).is_ok();
succeeded |= kernel_manager.run(source, id, timestamp).is_ok();
}
}
router.send(
@ -617,7 +862,16 @@ fn process_aux_packet(
destination: _destination,
succeeded,
} => {
forward!(_routing_table, _destination, *rank, _repeaters, &packet, timer);
forward!(
router,
_routing_table,
_destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
// received if local subkernel started another, remote subkernel
kernel_manager.subkernel_load_run_reply(succeeded);
Ok(())
@ -628,25 +882,73 @@ fn process_aux_packet(
with_exception,
exception_src,
} => {
forward!(_routing_table, _destination, *rank, _repeaters, &packet, timer);
forward!(
router,
_routing_table,
_destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
kernel_manager.remote_subkernel_finished(id, with_exception, exception_src);
Ok(())
}
drtioaux::Packet::SubkernelExceptionRequest {
source,
destination: _destination,
} => {
forward!(_routing_table, _destination, *rank, _repeaters, &packet, timer);
let mut data_slice: [u8; SAT_PAYLOAD_MAX_SIZE] = [0; SAT_PAYLOAD_MAX_SIZE];
forward!(
router,
_routing_table,
_destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
let mut data_slice: [u8; MASTER_PAYLOAD_MAX_SIZE] = [0; MASTER_PAYLOAD_MAX_SIZE];
let meta = kernel_manager.exception_get_slice(&mut data_slice);
drtioaux::send(
0,
&drtioaux::Packet::SubkernelException {
router.send(
drtioaux::Packet::SubkernelException {
destination: source,
last: meta.status.is_last(),
length: meta.len,
data: data_slice,
},
_routing_table,
*rank,
*self_destination,
)
}
drtioaux::Packet::SubkernelException {
destination: _destination,
last,
length,
data,
} => {
forward!(
router,
_routing_table,
_destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
kernel_manager.received_exception(
&data[..length as usize],
last,
router,
_routing_table,
*rank,
*self_destination,
);
Ok(())
}
drtioaux::Packet::SubkernelMessage {
source,
destination: _destination,
@ -655,7 +957,16 @@ fn process_aux_packet(
length,
data,
} => {
forward!(_routing_table, _destination, *rank, _repeaters, &packet, timer);
forward!(
router,
_routing_table,
_destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
kernel_manager.message_handle_incoming(status, id, length as usize, &data);
router.send(
drtioaux::Packet::SubkernelMessageAck { destination: source },
@ -667,7 +978,16 @@ fn process_aux_packet(
drtioaux::Packet::SubkernelMessageAck {
destination: _destination,
} => {
forward!(_routing_table, _destination, *rank, _repeaters, &packet, timer);
forward!(
router,
_routing_table,
_destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
if kernel_manager.message_ack_slice() {
let mut data_slice: [u8; MASTER_PAYLOAD_MAX_SIZE] = [0; MASTER_PAYLOAD_MAX_SIZE];
if let Some(meta) = kernel_manager.message_get_slice(&mut data_slice) {
@ -920,6 +1240,28 @@ pub extern "C" fn main_core0() -> i32 {
#[cfg(has_si549)]
si549::helper_setup(&mut timer, &SI549_SETTINGS).expect("cannot initialize helper Si549");
let cfg = match Config::new() {
Ok(cfg) => cfg,
Err(err) => {
warn!("config initialization failed: {}", err);
Config::new_dummy()
}
};
if let Ok(spread_enable) = cfg.read_str("sed_spread_enable") {
match spread_enable.as_ref() {
"1" => toggle_sed_spread(1),
"0" => toggle_sed_spread(0),
_ => {
warn!("sed_spread_enable value not supported (only 1, 0 allowed), disabling by default");
toggle_sed_spread(0)
}
};
} else {
info!("SED spreading disabled by default");
toggle_sed_spread(0);
}
#[cfg(has_drtio_routing)]
let mut repeaters = [repeater::Repeater::default(); csr::DRTIOREP.len()];
#[cfg(not(has_drtio_routing))]

View File

@ -87,6 +87,10 @@ impl Repeater {
if rep_link_rx_up(self.repno) {
if let Ok(Some(drtioaux::Packet::EchoReply)) = drtioaux::recv(self.auxno) {
info!("[REP#{}] remote replied after {} packets", self.repno, ping_count);
let max_time = timer.get_time() + Milliseconds(200);
while timer.get_time() < max_time {
let _ = drtioaux::recv(self.auxno);
}
self.state = RepeaterState::Up;
if let Err(e) = self.sync_tsc(timer) {
error!("[REP#{}] failed to sync TSC ({:?})", self.repno, e);
@ -204,10 +208,37 @@ impl Repeater {
}
}
pub fn aux_forward(&self, request: &drtioaux::Packet, timer: &mut GlobalTimer) -> Result<(), drtioaux::Error> {
pub fn aux_forward(
&self,
request: &drtioaux::Packet,
router: &mut Router,
routing_table: &drtio_routing::RoutingTable,
rank: u8,
self_destination: u8,
timer: &mut GlobalTimer,
) -> Result<(), drtioaux::Error> {
self.aux_send(request)?;
let reply = self.recv_aux_timeout(200, timer)?;
drtioaux::send(0, &reply).unwrap();
loop {
let reply = self.recv_aux_timeout(200, timer)?;
match reply {
// async/locally requested packets to be consumed or routed
// these may come while a packet would be forwarded
drtioaux::Packet::DmaPlaybackStatus { .. }
| drtioaux::Packet::SubkernelFinished { .. }
| drtioaux::Packet::SubkernelMessage { .. }
| drtioaux::Packet::SubkernelMessageAck { .. }
| drtioaux::Packet::SubkernelLoadRunReply { .. }
| drtioaux::Packet::SubkernelException { .. }
| drtioaux::Packet::DmaAddTraceReply { .. }
| drtioaux::Packet::DmaPlaybackReply { .. } => {
router.route(reply, routing_table, rank, self_destination);
}
_ => {
drtioaux::send(0, &reply).unwrap();
break;
}
}
}
Ok(())
}

View File

@ -4,7 +4,7 @@ use core::cmp::min;
#[cfg(has_drtio_routing)]
use libboard_artiq::pl::csr;
use libboard_artiq::{drtio_routing, drtioaux,
drtioaux_proto::{PayloadStatus, MASTER_PAYLOAD_MAX_SIZE, SAT_PAYLOAD_MAX_SIZE}};
drtioaux_proto::{PayloadStatus, MASTER_PAYLOAD_MAX_SIZE}};
pub struct SliceMeta {
pub destination: u8,
@ -57,7 +57,6 @@ impl Sliceable {
self.data.extend(data);
}
get_slice_fn!(get_slice_sat, SAT_PAYLOAD_MAX_SIZE);
get_slice_fn!(get_slice_master, MASTER_PAYLOAD_MAX_SIZE);
}

View File

@ -8,10 +8,10 @@ use core_io::{Error as IoError, Write};
use cslice::AsCSlice;
use dma::{Error as DmaError, Manager as DmaManager};
use io::{Cursor, ProtoWrite};
use ksupport::{eh_artiq, kernel, rpc};
use ksupport::{eh_artiq, kernel, rpc, rtio};
use libboard_artiq::{drtio_routing::RoutingTable,
drtioaux,
drtioaux_proto::{PayloadStatus, MASTER_PAYLOAD_MAX_SIZE, SAT_PAYLOAD_MAX_SIZE},
drtioaux_proto::{PayloadStatus, MASTER_PAYLOAD_MAX_SIZE},
pl::csr};
use libboard_zynq::{time::Milliseconds, timer::GlobalTimer};
use libcortex_a9::sync_channel::Receiver;
@ -47,6 +47,9 @@ enum KernelState {
DmaAwait {
max_time: Milliseconds,
},
SubkernelRetrievingException {
destination: u8,
},
}
#[derive(Debug)]
@ -123,10 +126,11 @@ struct MessageManager {
struct Session {
id: u32,
kernel_state: KernelState,
last_exception: Option<Sliceable>,
last_exception: Option<Sliceable>, // exceptions raised locally
external_exception: Option<Vec<u8>>, // exceptions from sub-subkernels
messages: MessageManager,
source: u8, // which destination requested running the kernel
subkernels_finished: Vec<u32>,
subkernels_finished: Vec<(u32, Option<u8>)>,
}
impl Session {
@ -135,6 +139,7 @@ impl Session {
id: id,
kernel_state: KernelState::Absent,
last_exception: None,
external_exception: None,
messages: MessageManager::new(),
source: 0,
subkernels_finished: Vec::new(),
@ -344,7 +349,7 @@ impl<'a> Manager<'_> {
}
}
pub fn run(&mut self, source: u8, id: u32) -> Result<(), Error> {
pub fn run(&mut self, source: u8, id: u32, timestamp: u64) -> Result<(), Error> {
if self.session.kernel_state != KernelState::Loaded || self.session.id != id {
self.load(id)?;
}
@ -354,6 +359,7 @@ impl<'a> Manager<'_> {
csr::cri_con::selected_write(2);
}
rtio::at_mu(timestamp as i64);
self.control.tx.send(kernel::Message::StartRequest);
Ok(())
}
@ -410,9 +416,9 @@ impl<'a> Manager<'_> {
}
}
pub fn exception_get_slice(&mut self, data_slice: &mut [u8; SAT_PAYLOAD_MAX_SIZE]) -> SliceMeta {
pub fn exception_get_slice(&mut self, data_slice: &mut [u8; MASTER_PAYLOAD_MAX_SIZE]) -> SliceMeta {
match self.session.last_exception.as_mut() {
Some(exception) => exception.get_slice_sat(data_slice),
Some(exception) => exception.get_slice_master(data_slice),
None => SliceMeta {
destination: 0,
len: 0,
@ -540,7 +546,7 @@ impl<'a> Manager<'_> {
return;
}
match self.process_external_messages(timer) {
match self.process_external_messages(router, routing_table, rank, destination, timer) {
Ok(()) => (),
Err(Error::AwaitingMessage) => return, // kernel still waiting, do not process kernel messages
Err(Error::KernelException(exception)) => {
@ -596,6 +602,41 @@ impl<'a> Manager<'_> {
}
}
fn check_finished_kernels(
&mut self,
id: u32,
router: &mut Router,
routing_table: &RoutingTable,
rank: u8,
self_destination: u8,
) {
for (i, (status, exception_source)) in self.session.subkernels_finished.iter().enumerate() {
if *status == id {
if exception_source.is_none() {
self.control.tx.send(kernel::Message::SubkernelAwaitFinishReply);
self.session.kernel_state = KernelState::Running;
self.session.subkernels_finished.swap_remove(i);
} else {
let destination = exception_source.unwrap();
self.session.external_exception = Some(Vec::new());
self.session.kernel_state = KernelState::SubkernelRetrievingException {
destination: destination,
};
router.route(
drtioaux::Packet::SubkernelExceptionRequest {
source: self_destination,
destination: destination,
},
&routing_table,
rank,
self_destination,
);
}
break;
}
}
}
pub fn subkernel_load_run_reply(&mut self, succeeded: bool) {
if self.session.kernel_state == KernelState::SubkernelAwaitLoad {
self.control
@ -608,16 +649,46 @@ impl<'a> Manager<'_> {
}
pub fn remote_subkernel_finished(&mut self, id: u32, with_exception: bool, exception_source: u8) {
if with_exception {
self.kernel_stop();
self.last_finished = Some(SubkernelFinished {
source: self.session.source,
id: self.session.id,
with_exception: true,
exception_source: exception_source,
})
let exception_src = if with_exception { Some(exception_source) } else { None };
self.session.subkernels_finished.push((id, exception_src));
}
pub fn received_exception(
&mut self,
exception_data: &[u8],
last: bool,
router: &mut Router,
routing_table: &RoutingTable,
rank: u8,
self_destination: u8,
) {
if let KernelState::SubkernelRetrievingException { destination } = self.session.kernel_state {
self.session
.external_exception
.as_mut()
.unwrap()
.extend_from_slice(exception_data);
if last {
self.control
.tx
.send(kernel::Message::SubkernelError(kernel::SubkernelStatus::Exception(
self.session.external_exception.take().unwrap(),
)));
self.session.kernel_state = KernelState::Running;
} else {
/* fetch another slice */
router.route(
drtioaux::Packet::SubkernelExceptionRequest {
source: self_destination,
destination: destination,
},
routing_table,
rank,
self_destination,
);
}
} else {
self.session.subkernels_finished.push(id);
warn!("Received unsolicited exception data");
}
}
@ -742,6 +813,7 @@ impl<'a> Manager<'_> {
id,
destination: sk_destination,
run,
timestamp,
} => {
self.session.kernel_state = KernelState::SubkernelAwaitLoad;
router.route(
@ -750,6 +822,7 @@ impl<'a> Manager<'_> {
destination: sk_destination,
id: id,
run: run,
timestamp,
},
routing_table,
rank,
@ -780,28 +853,35 @@ impl<'a> Manager<'_> {
Ok(false)
}
fn process_external_messages(&mut self, timer: &GlobalTimer) -> Result<(), Error> {
fn process_external_messages(
&mut self,
router: &mut Router,
routing_table: &RoutingTable,
rank: u8,
self_destination: u8,
timer: &GlobalTimer,
) -> Result<(), Error> {
match &self.session.kernel_state {
KernelState::MsgAwait { max_time, id, tags } => {
if let Some(max_time) = *max_time {
if timer.get_time() > max_time {
self.control.tx.send(kernel::Message::SubkernelMsgRecvReply {
status: kernel::SubkernelStatus::Timeout,
count: 0,
});
self.control
.tx
.send(kernel::Message::SubkernelError(kernel::SubkernelStatus::Timeout));
self.session.kernel_state = KernelState::Running;
return Ok(());
}
}
if let Some(message) = self.session.messages.get_incoming(*id) {
self.control.tx.send(kernel::Message::SubkernelMsgRecvReply {
status: kernel::SubkernelStatus::NoError,
count: message.count,
});
self.control
.tx
.send(kernel::Message::SubkernelMsgRecvReply { count: message.count });
let tags = tags.clone();
self.session.kernel_state = KernelState::Running;
self.pass_message_to_kernel(&message, tags, timer)
} else {
let id = *id;
self.check_finished_kernels(id, router, routing_table, rank, self_destination);
Err(Error::AwaitingMessage)
}
}
@ -817,27 +897,18 @@ impl<'a> Manager<'_> {
KernelState::SubkernelAwaitFinish { max_time, id } => {
if let Some(max_time) = *max_time {
if timer.get_time() > max_time {
self.control.tx.send(kernel::Message::SubkernelAwaitFinishReply {
status: kernel::SubkernelStatus::Timeout,
});
self.control
.tx
.send(kernel::Message::SubkernelError(kernel::SubkernelStatus::Timeout));
self.session.kernel_state = KernelState::Running;
return Ok(());
}
}
let mut i = 0;
for status in &self.session.subkernels_finished {
if *status == *id {
self.control.tx.send(kernel::Message::SubkernelAwaitFinishReply {
status: kernel::SubkernelStatus::NoError,
});
self.session.kernel_state = KernelState::Running;
self.session.subkernels_finished.swap_remove(i);
break;
}
i += 1;
}
let id = *id;
self.check_finished_kernels(id, router, routing_table, rank, self_destination);
Ok(())
}
KernelState::SubkernelRetrievingException { .. } => Err(Error::AwaitingMessage),
KernelState::DmaAwait { max_time } | KernelState::DmaPendingAwait { max_time, .. } => {
if timer.get_time() > *max_time {
self.control.tx.send(kernel::Message::DmaAwaitRemoteReply {