forked from M-Labs/artiq-zynq
Compare commits
17 Commits
Author | SHA1 | Date |
---|---|---|
architeuthidae | 24a4d79f0f | |
Sébastien Bourdeauducq | 9ce3aadb15 | |
mwojcik | 3390abd5a1 | |
newell | a410c40b50 | |
newell | 030247be18 | |
newell | 61df939c87 | |
newell | aba97175c6 | |
newell | 81790257a5 | |
Sebastien Bourdeauducq | 1f81d038e0 | |
Sebastien Bourdeauducq | 1e42228aac | |
Sebastien Bourdeauducq | c84653b500 | |
Sebastien Bourdeauducq | 6585b9b441 | |
Simon Renblad | 873dd86b4d | |
Simon Renblad | e7614d2e8e | |
Simon Renblad | 491e426222 | |
Simon Renblad | ccd3bf3003 | |
Sebastien Bourdeauducq | 3fdb7e80a8 |
90
README.md
90
README.md
|
@ -4,60 +4,102 @@ ARTIQ on Zynq
|
||||||
How to use
|
How to use
|
||||||
----------
|
----------
|
||||||
|
|
||||||
1. Install the ARTIQ version that corresponds to the artiq-zynq version you are targeting.
|
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, 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``).
|
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 the ``boot.bin`` file, obtained from Hydra's "binary distribution" download link or from AFWS, at the root of a FAT-formatted SD card.
|
3. Place ``boot.bin`` file 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.
|
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 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.
|
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 the firmware starts successfully, it should respond to ping at its IP addresses, and boot messages can be observed from its UART at 115200bps.
|
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, but set ``"target": "cortexa9"`` in the arguments of the core device.
|
7. Create and use an ARTIQ device database as usual.
|
||||||
|
|
||||||
Configuration
|
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.
|
- ``mac``: Ethernet MAC address.
|
||||||
- ``ip``: IPv4 address.
|
- ``ip``: IPv4 address.
|
||||||
- ``ip6``: IPv6 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``.
|
- ``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
|
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.
|
||||||
not implemented as it seems not very 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
|
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
|
```shell
|
||||||
nix build .#zc706-nist_clock-jtag # or zc706-nist_qc2-jtag or zc706-nist_clock_satellite-jtag etc.
|
nix build .#zc706-nist_clock-jtag # or zc706-nist_qc2-jtag or zc706-nist_clock-sd or etc
|
||||||
./remote_run.sh
|
|
||||||
```
|
```
|
||||||
|
|
||||||
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
|
```shell
|
||||||
nix develop
|
nix develop
|
||||||
cd src
|
cd src
|
||||||
gateware/zc706.py -g ../build/gateware -V <variant> # build gateware
|
gateware/<board>.py -g ../build/gateware -V <variant> # gateware
|
||||||
make GWARGS="-V <variant>" <runtime/satman> # build firmware
|
make GWARGS="-V <variant>" <runtime/satman> # firmware
|
||||||
cd ..
|
```
|
||||||
./remote_run.sh -i
|
|
||||||
|
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:
|
Notes:
|
||||||
|
|
||||||
- The impure build process is also compatible with non-Nix systems.
|
- 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.
|
- 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).
|
||||||
|
|
||||||
|
Pre-Commit Hooks
|
||||||
|
----------------
|
||||||
|
|
||||||
|
You are strongly recommended to use the provided pre-commit hooks to automatically reformat files and check for non-optimal Rust/C/C++ practices. Run `pre-commit install` to install the hook and `pre-commit` will automatically run `cargo fmt`, `cargo clippy`, and `clang-format` for you.
|
||||||
|
|
||||||
|
Several things to note:
|
||||||
|
|
||||||
|
- If `cargo fmt`, `cargo clippy`, or `clang-format` returns an error, the pre-commit hook will fail. You should fix all errors before trying to commit again.
|
||||||
|
- If `cargo fmt` or `clang-format` reformats some files, the pre-commit hook will also fail. You should review the changes and, if satisfied, try to commit again.
|
||||||
|
|
||||||
License
|
License
|
||||||
-------
|
-------
|
||||||
|
|
|
@ -0,0 +1,70 @@
|
||||||
|
core_addr = "192.168.1.57"
|
||||||
|
|
||||||
|
device_db = {
|
||||||
|
"core": {
|
||||||
|
"type": "local",
|
||||||
|
"module": "artiq.coredevice.core",
|
||||||
|
"class": "Core",
|
||||||
|
"arguments": {
|
||||||
|
"host": core_addr,
|
||||||
|
"ref_period": 1e-9,
|
||||||
|
"target": "cortexa9",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"core_log": {
|
||||||
|
"type": "controller",
|
||||||
|
"host": "::1",
|
||||||
|
"port": 1068,
|
||||||
|
"command": "aqctl_corelog -p {port} --bind {bind} " + core_addr,
|
||||||
|
},
|
||||||
|
"core_moninj": {
|
||||||
|
"type": "controller",
|
||||||
|
"host": "::1",
|
||||||
|
"port_proxy": 1383,
|
||||||
|
"port": 1384,
|
||||||
|
"command": "aqctl_moninj_proxy --port-proxy {port_proxy} --port-control {port} --bind {bind} "
|
||||||
|
+ core_addr,
|
||||||
|
},
|
||||||
|
"core_analyzer": {
|
||||||
|
"type": "controller",
|
||||||
|
"host": "::1",
|
||||||
|
"port_proxy": 1385,
|
||||||
|
"port": 1386,
|
||||||
|
"command": "aqctl_coreanalyzer_proxy --port-proxy {port_proxy} --port-control {port} --bind {bind} "
|
||||||
|
+ core_addr,
|
||||||
|
},
|
||||||
|
"core_cache": {
|
||||||
|
"type": "local",
|
||||||
|
"module": "artiq.coredevice.cache",
|
||||||
|
"class": "CoreCache",
|
||||||
|
},
|
||||||
|
"core_dma": {"type": "local", "module": "artiq.coredevice.dma", "class": "CoreDMA"},
|
||||||
|
"led0": {
|
||||||
|
"type": "local",
|
||||||
|
"module": "artiq.coredevice.ttl",
|
||||||
|
"class": "TTLOut",
|
||||||
|
"arguments": {"channel": 0},
|
||||||
|
},
|
||||||
|
"led1": {
|
||||||
|
"type": "local",
|
||||||
|
"module": "artiq.coredevice.ttl",
|
||||||
|
"class": "TTLOut",
|
||||||
|
"arguments": {"channel": 1},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
device_db.update(
|
||||||
|
spi0={
|
||||||
|
"type": "local",
|
||||||
|
"module": "artiq.coredevice.spi2",
|
||||||
|
"class": "SPIMaster",
|
||||||
|
"arguments": {"channel": 2},
|
||||||
|
},
|
||||||
|
dds0={
|
||||||
|
"type": "local",
|
||||||
|
"module": "artiq.coredevice.ad9834",
|
||||||
|
"class": "AD9834",
|
||||||
|
"arguments": {"spi_device": "spi0"},
|
||||||
|
},
|
||||||
|
)
|
34
flake.lock
34
flake.lock
|
@ -11,11 +11,11 @@
|
||||||
"src-pythonparser": "src-pythonparser"
|
"src-pythonparser": "src-pythonparser"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1724210813,
|
"lastModified": 1727765117,
|
||||||
"narHash": "sha256-OqQdE2lC0jKNS2fFq0Fda1nBpyT8ijmSXqdkO8xeOJ8=",
|
"narHash": "sha256-P4PgnsXNL4kXjSAhRpXzkq17j8bEaJAqNLSH2Vt+DY0=",
|
||||||
"ref": "refs/heads/master",
|
"ref": "refs/heads/master",
|
||||||
"rev": "61e96b37f9c4345e2d7bf71d47ba0b5e947de83e",
|
"rev": "333623e24bdec00783bc89c1e8b6b49a74bc9e1c",
|
||||||
"revCount": 8985,
|
"revCount": 9020,
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/m-labs/artiq.git"
|
"url": "https://github.com/m-labs/artiq.git"
|
||||||
},
|
},
|
||||||
|
@ -102,11 +102,11 @@
|
||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1723362943,
|
"lastModified": 1727348695,
|
||||||
"narHash": "sha256-dFZRVSgmJkyM0bkPpaYRtG/kRMRTorUIDj8BxoOt1T4=",
|
"narHash": "sha256-J+PeFKSDV+pHL7ukkfpVzCOO7mBSrrpJ3svwBFABbhI=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "a58bc8ad779655e790115244571758e8de055e3d",
|
"rev": "1925c603f17fc89f4c8f6bf6f631a802ad85d784",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -153,11 +153,11 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1717637367,
|
"lastModified": 1724921939,
|
||||||
"narHash": "sha256-4mSm9wl5EMgzzrW6w86IDUevkEOT99FESHGcxcyQbD0=",
|
"narHash": "sha256-/S5iip1LHLiCP2VY7PwClDteP9ZMRZvzzKR1LZuV3fs=",
|
||||||
"owner": "m-labs",
|
"owner": "m-labs",
|
||||||
"repo": "sipyco",
|
"repo": "sipyco",
|
||||||
"rev": "02b96ec2473a3c3d3c980899de2564ddce949dab",
|
"rev": "32ddd78ff3641b75054793ea0d5681c951766754",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -169,11 +169,11 @@
|
||||||
"src-migen": {
|
"src-migen": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1721561053,
|
"lastModified": 1727677091,
|
||||||
"narHash": "sha256-z3LRhNmKZrjr6rFD0yxtccSa/SWvFIYmb+G/D5d2Jd8=",
|
"narHash": "sha256-Zg3SQnTwMM/VkOGKogbPyuCC2NhLy8HB2SPEUWWNgCU=",
|
||||||
"owner": "m-labs",
|
"owner": "m-labs",
|
||||||
"repo": "migen",
|
"repo": "migen",
|
||||||
"rev": "9279e8623f8433bc4f23ac51e5e2331bfe544417",
|
"rev": "c19ae9f8ae162ffe2d310a92bfce53ac2a821bc8",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -240,11 +240,11 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1720537402,
|
"lastModified": 1728110308,
|
||||||
"narHash": "sha256-ybvaQ48SVBqYVqgYmGUdefGZkni7PJ90qYQPHnFOwDs=",
|
"narHash": "sha256-MAoFbcDgr+ZjptFCWfthK+tTnR1NcfuO6tvYhNM2Pwo=",
|
||||||
"ref": "refs/heads/master",
|
"ref": "refs/heads/master",
|
||||||
"rev": "b2b3e5c933cbc4b7cb14adde480d7561a3ae71ee",
|
"rev": "cc20478d91e30e1448a4304df7003caed2981b71",
|
||||||
"revCount": 648,
|
"revCount": 651,
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://git.m-labs.hk/m-labs/zynq-rs"
|
"url": "https://git.m-labs.hk/m-labs/zynq-rs"
|
||||||
},
|
},
|
||||||
|
|
|
@ -75,7 +75,7 @@
|
||||||
|
|
||||||
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; [ pytest-runner pytestCheckHook pytest-timeout ];
|
checkInputs = with pkgs.python3Packages; [ pytestCheckHook pytest-timeout ];
|
||||||
|
|
||||||
# migen/misoc version checks are broken with pyproject for some reason
|
# migen/misoc version checks are broken with pyproject for some reason
|
||||||
postPatch = ''
|
postPatch = ''
|
||||||
|
@ -364,7 +364,8 @@
|
||||||
(board-package-set { target = "zc706"; variant = "acpki_nist_qc2_satellite_100mhz"; }) //
|
(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 = "demo"; json = ./demo.json; }) //
|
||||||
(board-package-set { target = "kasli_soc"; variant = "master"; json = ./kasli-soc-master.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 = "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 gateware-sim; inherit fmt-check; };
|
||||||
|
|
||||||
|
@ -384,6 +385,7 @@
|
||||||
artiqpkgs.artiq
|
artiqpkgs.artiq
|
||||||
artiqpkgs.vivado
|
artiqpkgs.vivado
|
||||||
binutils-arm
|
binutils-arm
|
||||||
|
pre-commit
|
||||||
];
|
];
|
||||||
XARGO_RUST_SRC = "${rust}/lib/rustlib/src/rust/library";
|
XARGO_RUST_SRC = "${rust}/lib/rustlib/src/rust/library";
|
||||||
CLANG_EXTRA_INCLUDE_DIR = "${llvmPackages_11.clang-unwrapped.lib}/lib/clang/11.1.0/include";
|
CLANG_EXTRA_INCLUDE_DIR = "${llvmPackages_11.clang-unwrapped.lib}/lib/clang/11.1.0/include";
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
BasedOnStyle: LLVM
|
||||||
|
|
||||||
|
Language: Cpp
|
||||||
|
Standard: Cpp11
|
||||||
|
|
||||||
|
AccessModifierOffset: -1
|
||||||
|
AlignEscapedNewlines: Left
|
||||||
|
AlwaysBreakAfterReturnType: None
|
||||||
|
AlwaysBreakTemplateDeclarations: Yes
|
||||||
|
AllowAllParametersOfDeclarationOnNextLine: false
|
||||||
|
AllowShortFunctionsOnASingleLine: Inline
|
||||||
|
BinPackParameters: false
|
||||||
|
BreakBeforeBinaryOperators: NonAssignment
|
||||||
|
BreakBeforeTernaryOperators: true
|
||||||
|
BreakConstructorInitializers: AfterColon
|
||||||
|
BreakInheritanceList: AfterColon
|
||||||
|
ColumnLimit: 120
|
||||||
|
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||||
|
ContinuationIndentWidth: 4
|
||||||
|
DerivePointerAlignment: false
|
||||||
|
IndentCaseLabels: true
|
||||||
|
IndentPPDirectives: None
|
||||||
|
IndentWidth: 4
|
||||||
|
MaxEmptyLinesToKeep: 1
|
||||||
|
PointerAlignment: Left
|
||||||
|
ReflowComments: true
|
||||||
|
SortIncludes: false
|
||||||
|
SortUsingDeclarations: true
|
||||||
|
SpaceAfterTemplateKeyword: false
|
||||||
|
SpacesBeforeTrailingComments: 2
|
||||||
|
TabWidth: 4
|
||||||
|
UseTab: Never
|
|
@ -0,0 +1 @@
|
||||||
|
doc-valid-idents = ["CPython", "NumPy", ".."]
|
|
@ -0,0 +1,32 @@
|
||||||
|
# See https://pre-commit.com for more information
|
||||||
|
# See https://pre-commit.com/hooks.html for more hooks
|
||||||
|
|
||||||
|
default_stages: [commit]
|
||||||
|
|
||||||
|
repos:
|
||||||
|
- repo: local
|
||||||
|
hooks:
|
||||||
|
- id: cargo-fmt
|
||||||
|
name: artiq-zynq cargo format
|
||||||
|
entry: nix
|
||||||
|
language: system
|
||||||
|
types: [file, rust]
|
||||||
|
pass_filenames: false
|
||||||
|
description: Runs cargo fmt on the codebase.
|
||||||
|
args: [develop, -c, cargo, fmt, --manifest-path, src/Cargo.toml, --all]
|
||||||
|
- id: cargo-clippy
|
||||||
|
name: artiq-zynq cargo clippy
|
||||||
|
entry: nix
|
||||||
|
language: system
|
||||||
|
types: [file, rust]
|
||||||
|
pass_filenames: false
|
||||||
|
description: Runs cargo clippy on the codebase.
|
||||||
|
args: [develop, -c, cargo, clippy, --manifest-path, src/Cargo.toml, --tests]
|
||||||
|
- repo: https://github.com/pre-commit/mirrors-clang-format
|
||||||
|
rev: v19.1.0
|
||||||
|
hooks:
|
||||||
|
- id: clang-format
|
||||||
|
name: artiq-zynq clang-format
|
||||||
|
description: Runs clang-format on the codebase.
|
||||||
|
files: \.(cpp|h|hpp|c)$
|
||||||
|
args: [-style=file, -fallback-style=none, -assume-filename=src/.clang-format]
|
|
@ -0,0 +1,288 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
|
||||||
|
import analyzer
|
||||||
|
import dma
|
||||||
|
from artiq.gateware import rtio
|
||||||
|
from artiq.gateware.rtio.phy import dds, spi2, ttl_simple
|
||||||
|
from artiq.gateware.rtio.xilinx_clocking import fix_serdes_timing_path
|
||||||
|
from config import write_csr_file, write_mem_file, write_rustc_cfg_file
|
||||||
|
from migen import *
|
||||||
|
from migen.build.generic_platform import IOStandard, Misc, Pins, Subsignal
|
||||||
|
from migen.build.platforms import ebaz4205
|
||||||
|
from migen_axi.integration.soc_core import SoCCore
|
||||||
|
from misoc.interconnect.csr import *
|
||||||
|
|
||||||
|
_ps = [
|
||||||
|
(
|
||||||
|
"ps",
|
||||||
|
0,
|
||||||
|
Subsignal("clk", Pins("E7"), IOStandard("LVCMOS33"), Misc("SLEW=FAST")),
|
||||||
|
Subsignal("por_b", Pins("C7"), IOStandard("LVCMOS33"), Misc("SLEW=FAST")),
|
||||||
|
Subsignal("srst_b", Pins("B10"), IOStandard("LVCMOS18"), Misc("SLEW=FAST")),
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
|
_ddr = [
|
||||||
|
(
|
||||||
|
"ddr",
|
||||||
|
0,
|
||||||
|
Subsignal(
|
||||||
|
"a",
|
||||||
|
Pins("N2 K2 M3 K3 M4 L1 L4 K4 K1 J4 F5 G4 E4 D4 F4"),
|
||||||
|
IOStandard("SSTL15"),
|
||||||
|
),
|
||||||
|
Subsignal("ba", Pins("L5 R4 J5"), IOStandard("SSTL15")),
|
||||||
|
Subsignal("cas_n", Pins("P5"), IOStandard("SSTL15")),
|
||||||
|
Subsignal("cke", Pins("N3"), IOStandard("SSTL15")),
|
||||||
|
Subsignal("cs_n", Pins("N1"), IOStandard("SSTL15")),
|
||||||
|
Subsignal("ck_n", Pins("M2"), IOStandard("DIFF_SSTL15"), Misc("SLEW=FAST")),
|
||||||
|
Subsignal("ck_p", Pins("L2"), IOStandard("DIFF_SSTL15"), Misc("SLEW=FAST")),
|
||||||
|
# Pins "T1 Y1" not connected
|
||||||
|
Subsignal("dm", Pins("A1 F1"), IOStandard("SSTL15_T_DCI"), Misc("SLEW=FAST")),
|
||||||
|
Subsignal(
|
||||||
|
"dq",
|
||||||
|
Pins("C3 B3 A2 A4 D3 D1 C1 E1 E2 E3 G3 H3 J3 H2 H1 J1"),
|
||||||
|
# Pins "P1 P3 R3 R1 T4 U4 U2 U3 V1 Y3 W1 Y4 Y2 W3 V2 V3" not connected
|
||||||
|
IOStandard("SSTL15_T_DCI"),
|
||||||
|
Misc("SLEW=FAST"),
|
||||||
|
),
|
||||||
|
Subsignal(
|
||||||
|
"dqs_n",
|
||||||
|
Pins("B2 F2"), # Pins "T2 W4" not connected
|
||||||
|
IOStandard("DIFF_SSTL15_T_DCI"),
|
||||||
|
Misc("SLEW=FAST"),
|
||||||
|
),
|
||||||
|
Subsignal(
|
||||||
|
"dqs_p",
|
||||||
|
Pins("C2 G2"), # Pins "R2 W5" not connected
|
||||||
|
IOStandard("DIFF_SSTL15_T_DCI"),
|
||||||
|
Misc("SLEW=FAST"),
|
||||||
|
),
|
||||||
|
Subsignal("vrn", Pins("G5"), IOStandard("SSTL15_T_DCI"), Misc("SLEW=FAST")),
|
||||||
|
Subsignal("vrp", Pins("H5"), IOStandard("SSTL15_T_DCI"), Misc("SLEW=FAST")),
|
||||||
|
Subsignal("drst_n", Pins("B4"), IOStandard("SSTL15"), Misc("SLEW=FAST")),
|
||||||
|
Subsignal("odt", Pins("N5"), IOStandard("SSTL15")),
|
||||||
|
Subsignal("ras_n", Pins("P4"), IOStandard("SSTL15")),
|
||||||
|
Subsignal("we_n", Pins("M5"), IOStandard("SSTL15")),
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
|
# Connector J3
|
||||||
|
_i2c = [
|
||||||
|
(
|
||||||
|
"i2c",
|
||||||
|
0,
|
||||||
|
Subsignal("scl", Pins("U12"), IOStandard("LVCMOS33")),
|
||||||
|
Subsignal("sda", Pins("V13"), IOStandard("LVCMOS33")),
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
|
_spi = [
|
||||||
|
(
|
||||||
|
"spi",
|
||||||
|
0,
|
||||||
|
Subsignal("clk", Pins("V20")),
|
||||||
|
Subsignal("mosi", Pins("U20")),
|
||||||
|
Subsignal("cs_n", Pins("P19")),
|
||||||
|
IOStandard("LVCMOS33"),
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class EBAZ4205(SoCCore):
|
||||||
|
def __init__(self, rtio_clk=125e6, acpki=False):
|
||||||
|
self.acpki = acpki
|
||||||
|
|
||||||
|
platform = ebaz4205.Platform()
|
||||||
|
platform.toolchain.bitstream_commands.extend(
|
||||||
|
[
|
||||||
|
"set_property BITSTREAM.GENERAL.COMPRESS True [current_design]",
|
||||||
|
]
|
||||||
|
)
|
||||||
|
platform.add_extension(_ps)
|
||||||
|
platform.add_extension(_ddr)
|
||||||
|
platform.add_extension(_i2c)
|
||||||
|
platform.add_extension(_spi)
|
||||||
|
|
||||||
|
gmii = platform.request("gmii")
|
||||||
|
platform.add_period_constraint(gmii.rx_clk, 10)
|
||||||
|
platform.add_period_constraint(gmii.tx_clk, 10)
|
||||||
|
platform.add_platform_command(
|
||||||
|
"set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets gmii_tx_clk_IBUF]"
|
||||||
|
)
|
||||||
|
|
||||||
|
ident = self.__class__.__name__
|
||||||
|
if self.acpki:
|
||||||
|
ident = "acpki_" + ident
|
||||||
|
SoCCore.__init__(self, platform=platform, csr_data_width=32, ident=ident)
|
||||||
|
fix_serdes_timing_path(platform)
|
||||||
|
self.config["RTIO_FREQUENCY"] = str(rtio_clk / 1e6)
|
||||||
|
platform.add_period_constraint(self.ps7.cd_sys.clk, 10)
|
||||||
|
|
||||||
|
self.comb += [
|
||||||
|
self.ps7.enet0.enet.gmii.tx_clk.eq(gmii.tx_clk),
|
||||||
|
self.ps7.enet0.enet.gmii.rx_clk.eq(gmii.rx_clk),
|
||||||
|
]
|
||||||
|
self.clock_domains.cd_eth_rx = ClockDomain(reset_less=False)
|
||||||
|
self.clock_domains.cd_eth_tx = ClockDomain(reset_less=False)
|
||||||
|
self.comb += [
|
||||||
|
ClockSignal("eth_rx").eq(gmii.rx_clk),
|
||||||
|
ClockSignal("eth_tx").eq(gmii.tx_clk),
|
||||||
|
]
|
||||||
|
self.sync.eth_tx += [
|
||||||
|
gmii.txd.eq(self.ps7.enet0.enet.gmii.txd),
|
||||||
|
gmii.tx_en.eq(self.ps7.enet0.enet.gmii.tx_en),
|
||||||
|
]
|
||||||
|
self.sync.eth_rx += [
|
||||||
|
self.ps7.enet0.enet.gmii.rxd.eq(gmii.rxd),
|
||||||
|
self.ps7.enet0.enet.gmii.rx_dv.eq(gmii.rx_dv),
|
||||||
|
]
|
||||||
|
|
||||||
|
# MDIO
|
||||||
|
mdio = platform.request("mdio")
|
||||||
|
self.comb += mdio.mdc.eq(self.ps7.enet0.enet.mdio.mdc)
|
||||||
|
self.specials += Instance(
|
||||||
|
"IOBUF",
|
||||||
|
i_I=self.ps7.enet0.enet.mdio.o,
|
||||||
|
io_IO=mdio.mdio,
|
||||||
|
o_O=self.ps7.enet0.enet.mdio.i,
|
||||||
|
i_T=~self.ps7.enet0.enet.mdio.t_n,
|
||||||
|
)
|
||||||
|
|
||||||
|
# I2C
|
||||||
|
i2c = self.platform.request("i2c")
|
||||||
|
self.specials += [
|
||||||
|
# SCL
|
||||||
|
Instance(
|
||||||
|
"IOBUF",
|
||||||
|
i_I=self.ps7.i2c0.scl.o,
|
||||||
|
io_IO=i2c.scl,
|
||||||
|
o_O=self.ps7.i2c0.scl.i,
|
||||||
|
i_T=~self.ps7.i2c0.scl.t_n,
|
||||||
|
),
|
||||||
|
# SDA
|
||||||
|
Instance(
|
||||||
|
"IOBUF",
|
||||||
|
i_I=self.ps7.i2c0.sda.o,
|
||||||
|
io_IO=i2c.sda,
|
||||||
|
o_O=self.ps7.i2c0.sda.i,
|
||||||
|
i_T=~self.ps7.i2c0.sda.t_n,
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
|
self.rtio_channels = []
|
||||||
|
for i in (0, 1):
|
||||||
|
print("USER LED at RTIO channel 0x{:06x}".format(len(self.rtio_channels)))
|
||||||
|
user_led = self.platform.request("user_led", i)
|
||||||
|
phy = ttl_simple.Output(user_led)
|
||||||
|
self.submodules += phy
|
||||||
|
self.rtio_channels.append(rtio.Channel.from_phy(phy))
|
||||||
|
|
||||||
|
print("SPI at RTIO channel 0x{:06x}".format(len(self.rtio_channels)))
|
||||||
|
spi_phy = spi2.SPIMaster(platform.request("spi"))
|
||||||
|
self.submodules += spi_phy
|
||||||
|
self.rtio_channels.append(rtio.Channel.from_phy(spi_phy, ififo_depth=4))
|
||||||
|
self.config["RTIO_LOG_CHANNEL"] = len(self.rtio_channels)
|
||||||
|
self.rtio_channels.append(rtio.LogChannel())
|
||||||
|
|
||||||
|
self.submodules.rtio_tsc = rtio.TSC(glbl_fine_ts_width=3)
|
||||||
|
self.submodules.rtio_core = rtio.Core(self.rtio_tsc, self.rtio_channels)
|
||||||
|
self.csr_devices.append("rtio_core")
|
||||||
|
if self.acpki:
|
||||||
|
import 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.csr_devices.append("rtio")
|
||||||
|
else:
|
||||||
|
self.config["KI_IMPL"] = "csr"
|
||||||
|
self.submodules.rtio = rtio.KernelInitiator(self.rtio_tsc, now64=True)
|
||||||
|
self.csr_devices.append("rtio")
|
||||||
|
|
||||||
|
self.submodules.rtio_dma = dma.DMA(self.ps7.s_axi_hp0)
|
||||||
|
self.csr_devices.append("rtio_dma")
|
||||||
|
|
||||||
|
self.submodules.cri_con = rtio.CRIInterconnectShared(
|
||||||
|
[self.rtio.cri, self.rtio_dma.cri],
|
||||||
|
[self.rtio_core.cri],
|
||||||
|
enable_routing=True,
|
||||||
|
)
|
||||||
|
self.csr_devices.append("cri_con")
|
||||||
|
|
||||||
|
self.submodules.rtio_moninj = rtio.MonInj(self.rtio_channels)
|
||||||
|
self.csr_devices.append("rtio_moninj")
|
||||||
|
|
||||||
|
self.submodules.rtio_analyzer = analyzer.Analyzer(
|
||||||
|
self.rtio_tsc, self.rtio_core.cri, self.ps7.s_axi_hp1
|
||||||
|
)
|
||||||
|
self.csr_devices.append("rtio_analyzer")
|
||||||
|
|
||||||
|
|
||||||
|
class BASE(EBAZ4205):
|
||||||
|
def __init__(self, rtio_clk, acpki):
|
||||||
|
EBAZ4205.__init__(self, rtio_clk, acpki)
|
||||||
|
|
||||||
|
|
||||||
|
VARIANTS = {cls.__name__.lower(): cls for cls in [BASE]}
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
description="ARTIQ port to the EBAZ4205 control card of Ebit E9+ BTC miner"
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-r", default=None, help="build Rust interface into the specified file"
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-m", default=None, help="build Rust memory interface into the specified file"
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-c",
|
||||||
|
default=None,
|
||||||
|
help="build Rust compiler configuration into the specified file",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-g", default=None, help="build gateware into the specified directory"
|
||||||
|
)
|
||||||
|
parser.add_argument("--rtio-clk", default=125e6, help="RTIO Clock Frequency (Hz)")
|
||||||
|
parser.add_argument(
|
||||||
|
"-V",
|
||||||
|
"--variant",
|
||||||
|
default="base",
|
||||||
|
help="variant: " "[acpki_]base" "(default: %(default)s)",
|
||||||
|
)
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
rtio_clk = int(args.rtio_clk)
|
||||||
|
variant = args.variant.lower()
|
||||||
|
acpki = variant.startswith("acpki_")
|
||||||
|
if acpki:
|
||||||
|
variant = variant[6:]
|
||||||
|
|
||||||
|
try:
|
||||||
|
cls = VARIANTS[variant]
|
||||||
|
except KeyError:
|
||||||
|
raise SystemExit("Invalid variant (-V/--variant)")
|
||||||
|
|
||||||
|
soc = cls(rtio_clk=rtio_clk, acpki=acpki)
|
||||||
|
soc.finalize()
|
||||||
|
|
||||||
|
if args.r is not None:
|
||||||
|
write_csr_file(soc, args.r)
|
||||||
|
if args.m is not None:
|
||||||
|
write_mem_file(soc, args.m)
|
||||||
|
if args.c is not None:
|
||||||
|
write_rustc_cfg_file(soc, args.c)
|
||||||
|
if args.g is not None:
|
||||||
|
soc.build(build_dir=args.g)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
|
@ -10,6 +10,7 @@ name = "libboard_artiq"
|
||||||
[features]
|
[features]
|
||||||
target_zc706 = ["libboard_zynq/target_zc706", "libconfig/target_zc706"]
|
target_zc706 = ["libboard_zynq/target_zc706", "libconfig/target_zc706"]
|
||||||
target_kasli_soc = ["libboard_zynq/target_kasli_soc", "libconfig/target_kasli_soc"]
|
target_kasli_soc = ["libboard_zynq/target_kasli_soc", "libconfig/target_kasli_soc"]
|
||||||
|
target_ebaz4205 = ["libboard_zynq/target_ebaz4205", "libconfig/target_ebaz4205"]
|
||||||
calibrate_wrpll_skew = []
|
calibrate_wrpll_skew = []
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
|
|
|
@ -255,6 +255,7 @@ pub enum Packet {
|
||||||
destination: u8,
|
destination: u8,
|
||||||
id: u32,
|
id: u32,
|
||||||
run: bool,
|
run: bool,
|
||||||
|
timestamp: u64,
|
||||||
},
|
},
|
||||||
SubkernelLoadRunReply {
|
SubkernelLoadRunReply {
|
||||||
destination: u8,
|
destination: u8,
|
||||||
|
@ -514,6 +515,7 @@ impl Packet {
|
||||||
destination: reader.read_u8()?,
|
destination: reader.read_u8()?,
|
||||||
id: reader.read_u32()?,
|
id: reader.read_u32()?,
|
||||||
run: reader.read_bool()?,
|
run: reader.read_bool()?,
|
||||||
|
timestamp: reader.read_u64()?,
|
||||||
},
|
},
|
||||||
0xc5 => Packet::SubkernelLoadRunReply {
|
0xc5 => Packet::SubkernelLoadRunReply {
|
||||||
destination: reader.read_u8()?,
|
destination: reader.read_u8()?,
|
||||||
|
@ -877,12 +879,14 @@ impl Packet {
|
||||||
destination,
|
destination,
|
||||||
id,
|
id,
|
||||||
run,
|
run,
|
||||||
|
timestamp,
|
||||||
} => {
|
} => {
|
||||||
writer.write_u8(0xc4)?;
|
writer.write_u8(0xc4)?;
|
||||||
writer.write_u8(source)?;
|
writer.write_u8(source)?;
|
||||||
writer.write_u8(destination)?;
|
writer.write_u8(destination)?;
|
||||||
writer.write_u32(id)?;
|
writer.write_u32(id)?;
|
||||||
writer.write_bool(run)?;
|
writer.write_bool(run)?;
|
||||||
|
writer.write_u64(timestamp)?;
|
||||||
}
|
}
|
||||||
Packet::SubkernelLoadRunReply { destination, succeeded } => {
|
Packet::SubkernelLoadRunReply { destination, succeeded } => {
|
||||||
writer.write_u8(0xc5)?;
|
writer.write_u8(0xc5)?;
|
||||||
|
|
|
@ -81,6 +81,7 @@ pub enum Message {
|
||||||
id: u32,
|
id: u32,
|
||||||
destination: u8,
|
destination: u8,
|
||||||
run: bool,
|
run: bool,
|
||||||
|
timestamp: u64,
|
||||||
},
|
},
|
||||||
#[cfg(has_drtio)]
|
#[cfg(has_drtio)]
|
||||||
SubkernelLoadRunReply {
|
SubkernelLoadRunReply {
|
||||||
|
|
|
@ -3,7 +3,7 @@ use alloc::vec::Vec;
|
||||||
use cslice::CSlice;
|
use cslice::CSlice;
|
||||||
|
|
||||||
use super::{Message, SubkernelStatus, KERNEL_CHANNEL_0TO1, KERNEL_CHANNEL_1TO0};
|
use super::{Message, SubkernelStatus, KERNEL_CHANNEL_0TO1, KERNEL_CHANNEL_1TO0};
|
||||||
use crate::{artiq_raise, eh_artiq, rpc::send_args};
|
use crate::{artiq_raise, eh_artiq, rpc::send_args, rtio::now_mu};
|
||||||
|
|
||||||
pub extern "C" fn load_run(id: u32, destination: u8, run: bool) {
|
pub extern "C" fn load_run(id: u32, destination: u8, run: bool) {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -14,6 +14,7 @@ pub extern "C" fn load_run(id: u32, destination: u8, run: bool) {
|
||||||
id: id,
|
id: id,
|
||||||
destination: destination,
|
destination: destination,
|
||||||
run: run,
|
run: run,
|
||||||
|
timestamp: now_mu() as u64,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
match unsafe { KERNEL_CHANNEL_0TO1.as_mut().unwrap() }.recv() {
|
match unsafe { KERNEL_CHANNEL_0TO1.as_mut().unwrap() }.recv() {
|
||||||
|
|
|
@ -8,6 +8,7 @@ edition = "2018"
|
||||||
[features]
|
[features]
|
||||||
target_zc706 = ["libboard_zynq/target_zc706", "libsupport_zynq/target_zc706", "libconfig/target_zc706", "libboard_artiq/target_zc706"]
|
target_zc706 = ["libboard_zynq/target_zc706", "libsupport_zynq/target_zc706", "libconfig/target_zc706", "libboard_artiq/target_zc706"]
|
||||||
target_kasli_soc = ["libboard_zynq/target_kasli_soc", "libsupport_zynq/target_kasli_soc", "libconfig/target_kasli_soc", "libboard_artiq/target_kasli_soc"]
|
target_kasli_soc = ["libboard_zynq/target_kasli_soc", "libsupport_zynq/target_kasli_soc", "libconfig/target_kasli_soc", "libboard_artiq/target_kasli_soc"]
|
||||||
|
target_ebaz4205 = ["libboard_zynq/target_ebaz4205", "libsupport_zynq/target_ebaz4205", "libconfig/target_ebaz4205", "libboard_artiq/target_ebaz4205"]
|
||||||
default = ["target_zc706"]
|
default = ["target_zc706"]
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
|
|
|
@ -405,8 +405,9 @@ async fn handle_run_kernel(
|
||||||
id,
|
id,
|
||||||
destination: _,
|
destination: _,
|
||||||
run,
|
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,
|
Ok(()) => true,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error!("Error loading subkernel: {:?}", e);
|
error!("Error loading subkernel: {:?}", e);
|
||||||
|
@ -696,27 +697,6 @@ async fn handle_connection(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn load_and_run_idle_kernel(
|
|
||||||
buffer: &Vec<u8>,
|
|
||||||
control: &Rc<RefCell<kernel::Control>>,
|
|
||||||
up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>,
|
|
||||||
aux_mutex: &Rc<Mutex<bool>>,
|
|
||||||
routing_table: &drtio_routing::RoutingTable,
|
|
||||||
timer: GlobalTimer,
|
|
||||||
) {
|
|
||||||
info!("Loading idle kernel");
|
|
||||||
let res = handle_flash_kernel(buffer, control, up_destinations, aux_mutex, routing_table, timer).await;
|
|
||||||
match res {
|
|
||||||
Err(_) => warn!("error loading idle kernel"),
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
info!("Running idle kernel");
|
|
||||||
let _ = handle_run_kernel(None, control, up_destinations, aux_mutex, routing_table, timer)
|
|
||||||
.await
|
|
||||||
.map_err(|_| warn!("error running idle kernel"));
|
|
||||||
info!("Idle kernel terminated");
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn main(timer: GlobalTimer, cfg: Config) {
|
pub fn main(timer: GlobalTimer, cfg: Config) {
|
||||||
let net_addresses = net_settings::get_addresses(&cfg);
|
let net_addresses = net_settings::get_addresses(&cfg);
|
||||||
info!("network addresses: {}", net_addresses);
|
info!("network addresses: {}", net_addresses);
|
||||||
|
@ -777,7 +757,6 @@ pub fn main(timer: GlobalTimer, cfg: Config) {
|
||||||
moninj::start(timer, &aux_mutex, &drtio_routing_table);
|
moninj::start(timer, &aux_mutex, &drtio_routing_table);
|
||||||
|
|
||||||
let control: Rc<RefCell<kernel::Control>> = Rc::new(RefCell::new(kernel::Control::start()));
|
let control: Rc<RefCell<kernel::Control>> = Rc::new(RefCell::new(kernel::Control::start()));
|
||||||
let idle_kernel = Rc::new(cfg.read("idle_kernel").ok());
|
|
||||||
if let Ok(buffer) = cfg.read("startup_kernel") {
|
if let Ok(buffer) = cfg.read("startup_kernel") {
|
||||||
info!("Loading startup kernel...");
|
info!("Loading startup kernel...");
|
||||||
let routing_table = drtio_routing_table.borrow();
|
let routing_table = drtio_routing_table.borrow();
|
||||||
|
@ -804,35 +783,26 @@ pub fn main(timer: GlobalTimer, cfg: Config) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mgmt::start(cfg);
|
let cfg = Rc::new(cfg);
|
||||||
|
let restart_idle = Rc::new(Semaphore::new(1, 1));
|
||||||
|
mgmt::start(cfg.clone(), restart_idle.clone());
|
||||||
|
|
||||||
task::spawn(async move {
|
task::spawn(async move {
|
||||||
let connection = Rc::new(Semaphore::new(0, 1));
|
let connection = Rc::new(Semaphore::new(1, 1));
|
||||||
let terminate = Rc::new(Semaphore::new(0, 1));
|
let terminate = Rc::new(Semaphore::new(0, 1));
|
||||||
{
|
let can_restart_idle = Rc::new(Semaphore::new(1, 1));
|
||||||
let control = control.clone();
|
let restart_idle = restart_idle.clone();
|
||||||
let idle_kernel = idle_kernel.clone();
|
|
||||||
let connection = connection.clone();
|
|
||||||
let terminate = terminate.clone();
|
|
||||||
let up_destinations = up_destinations.clone();
|
|
||||||
let aux_mutex = aux_mutex.clone();
|
|
||||||
let routing_table = drtio_routing_table.clone();
|
|
||||||
task::spawn(async move {
|
|
||||||
let routing_table = routing_table.borrow();
|
|
||||||
select_biased! {
|
|
||||||
_ = (async {
|
|
||||||
if let Some(buffer) = &*idle_kernel {
|
|
||||||
load_and_run_idle_kernel(&buffer, &control, &up_destinations, &aux_mutex, &routing_table, timer).await;
|
|
||||||
}
|
|
||||||
}).fuse() => (),
|
|
||||||
_ = terminate.async_wait().fuse() => ()
|
|
||||||
}
|
|
||||||
connection.signal();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let mut stream = TcpStream::accept(1381, 0x10_000, 0x10_000).await.unwrap();
|
let control = control.clone();
|
||||||
|
let mut maybe_stream = select_biased! {
|
||||||
|
s = (async {
|
||||||
|
TcpStream::accept(1381, 0x10_000, 0x10_000).await.unwrap()
|
||||||
|
}).fuse() => Some(s),
|
||||||
|
_ = (async {
|
||||||
|
restart_idle.async_wait().await;
|
||||||
|
can_restart_idle.async_wait().await;
|
||||||
|
}).fuse() => None
|
||||||
|
};
|
||||||
|
|
||||||
if connection.try_wait().is_none() {
|
if connection.try_wait().is_none() {
|
||||||
// there is an existing connection
|
// there is an existing connection
|
||||||
|
@ -840,32 +810,58 @@ pub fn main(timer: GlobalTimer, cfg: Config) {
|
||||||
connection.async_wait().await;
|
connection.async_wait().await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let maybe_idle_kernel = cfg.read("idle_kernel").ok();
|
||||||
|
if maybe_idle_kernel.is_none() && maybe_stream.is_none() {
|
||||||
|
control.borrow_mut().restart(); // terminate idle kernel if running
|
||||||
|
}
|
||||||
|
|
||||||
let control = control.clone();
|
let control = control.clone();
|
||||||
let idle_kernel = idle_kernel.clone();
|
|
||||||
let connection = connection.clone();
|
let connection = connection.clone();
|
||||||
let terminate = terminate.clone();
|
let terminate = terminate.clone();
|
||||||
|
let can_restart_idle = can_restart_idle.clone();
|
||||||
let up_destinations = up_destinations.clone();
|
let up_destinations = up_destinations.clone();
|
||||||
let aux_mutex = aux_mutex.clone();
|
let aux_mutex = aux_mutex.clone();
|
||||||
let routing_table = drtio_routing_table.clone();
|
let routing_table = drtio_routing_table.clone();
|
||||||
|
|
||||||
// we make sure the value of terminate is 0 before we start
|
// we make sure the value of terminate is 0 before we start
|
||||||
let _ = terminate.try_wait();
|
let _ = terminate.try_wait();
|
||||||
|
let _ = can_restart_idle.try_wait();
|
||||||
task::spawn(async move {
|
task::spawn(async move {
|
||||||
let routing_table = routing_table.borrow();
|
let routing_table = routing_table.borrow();
|
||||||
select_biased! {
|
select_biased! {
|
||||||
_ = (async {
|
_ = (async {
|
||||||
let _ = handle_connection(&mut stream, control.clone(), &up_destinations, &aux_mutex, &routing_table, timer)
|
if let Some(stream) = &mut maybe_stream {
|
||||||
|
let _ = handle_connection(stream, control.clone(), &up_destinations, &aux_mutex, &routing_table, timer)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| warn!("connection terminated: {}", e));
|
.map_err(|e| warn!("connection terminated: {}", e));
|
||||||
if let Some(buffer) = &*idle_kernel {
|
}
|
||||||
load_and_run_idle_kernel(&buffer, &control, &up_destinations, &aux_mutex, &routing_table, timer).await;
|
can_restart_idle.signal();
|
||||||
|
match maybe_idle_kernel {
|
||||||
|
Some(buffer) => {
|
||||||
|
loop {
|
||||||
|
info!("loading idle kernel");
|
||||||
|
match handle_flash_kernel(&buffer, &control, &up_destinations, &aux_mutex, &routing_table, timer).await {
|
||||||
|
Ok(_) => {
|
||||||
|
info!("running idle kernel");
|
||||||
|
match handle_run_kernel(None, &control, &up_destinations, &aux_mutex, &routing_table, timer).await {
|
||||||
|
Ok(_) => info!("idle kernel finished"),
|
||||||
|
Err(_) => warn!("idle kernel running error")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Err(_) => warn!("idle kernel loading error")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
None => info!("no idle kernel found")
|
||||||
}
|
}
|
||||||
}).fuse() => (),
|
}).fuse() => (),
|
||||||
_ = terminate.async_wait().fuse() => ()
|
_ = terminate.async_wait().fuse() => ()
|
||||||
}
|
}
|
||||||
connection.signal();
|
connection.signal();
|
||||||
|
if let Some(stream) = maybe_stream {
|
||||||
let _ = stream.flush().await;
|
let _ = stream.flush().await;
|
||||||
let _ = stream.abort().await;
|
let _ = stream.abort().await;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -914,7 +910,8 @@ pub fn soft_panic_main(timer: GlobalTimer, cfg: Config) -> ! {
|
||||||
|
|
||||||
Sockets::init(32);
|
Sockets::init(32);
|
||||||
|
|
||||||
mgmt::start(cfg);
|
let dummy = Rc::new(Semaphore::new(0, 1));
|
||||||
|
mgmt::start(Rc::new(cfg), dummy);
|
||||||
|
|
||||||
// getting eth settings disables the LED as it resets GPIO
|
// getting eth settings disables the LED as it resets GPIO
|
||||||
// need to re-enable it here
|
// need to re-enable it here
|
||||||
|
|
|
@ -6,6 +6,7 @@ use libasync::{smoltcp::TcpStream, task};
|
||||||
use libboard_artiq::logger::{BufferLogger, LogBufferRef};
|
use libboard_artiq::logger::{BufferLogger, LogBufferRef};
|
||||||
use libboard_zynq::{slcr, smoltcp};
|
use libboard_zynq::{slcr, smoltcp};
|
||||||
use libconfig::Config;
|
use libconfig::Config;
|
||||||
|
use libcortex_a9::semaphore::Semaphore;
|
||||||
use log::{self, debug, error, info, warn, LevelFilter};
|
use log::{self, debug, error, info, warn, LevelFilter};
|
||||||
use num_derive::FromPrimitive;
|
use num_derive::FromPrimitive;
|
||||||
use num_traits::FromPrimitive;
|
use num_traits::FromPrimitive;
|
||||||
|
@ -111,7 +112,12 @@ async fn read_key(stream: &mut TcpStream) -> Result<String> {
|
||||||
Ok(String::from_utf8(buffer).unwrap())
|
Ok(String::from_utf8(buffer).unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_connection(stream: &mut TcpStream, pull_id: Rc<RefCell<u32>>, cfg: Rc<Config>) -> Result<()> {
|
async fn handle_connection(
|
||||||
|
stream: &mut TcpStream,
|
||||||
|
pull_id: Rc<RefCell<u32>>,
|
||||||
|
cfg: Rc<Config>,
|
||||||
|
restart_idle: Rc<Semaphore>,
|
||||||
|
) -> Result<()> {
|
||||||
if !expect(&stream, b"ARTIQ management\n").await? {
|
if !expect(&stream, b"ARTIQ management\n").await? {
|
||||||
return Err(Error::UnexpectedPattern);
|
return Err(Error::UnexpectedPattern);
|
||||||
}
|
}
|
||||||
|
@ -200,6 +206,9 @@ async fn handle_connection(stream: &mut TcpStream, pull_id: Rc<RefCell<u32>>, cf
|
||||||
let value = cfg.write(&key, buffer);
|
let value = cfg.write(&key, buffer);
|
||||||
if value.is_ok() {
|
if value.is_ok() {
|
||||||
debug!("write success");
|
debug!("write success");
|
||||||
|
if key == "idle_kernel" {
|
||||||
|
restart_idle.signal();
|
||||||
|
}
|
||||||
write_i8(stream, Reply::Success as i8).await?;
|
write_i8(stream, Reply::Success as i8).await?;
|
||||||
} else {
|
} else {
|
||||||
// this is an error because we do not expect write to fail
|
// this is an error because we do not expect write to fail
|
||||||
|
@ -213,6 +222,9 @@ async fn handle_connection(stream: &mut TcpStream, pull_id: Rc<RefCell<u32>>, cf
|
||||||
let value = cfg.remove(&key);
|
let value = cfg.remove(&key);
|
||||||
if value.is_ok() {
|
if value.is_ok() {
|
||||||
debug!("erase success");
|
debug!("erase success");
|
||||||
|
if key == "idle_kernel" {
|
||||||
|
restart_idle.signal();
|
||||||
|
}
|
||||||
write_i8(stream, Reply::Success as i8).await?;
|
write_i8(stream, Reply::Success as i8).await?;
|
||||||
} else {
|
} else {
|
||||||
warn!("erase failed");
|
warn!("erase failed");
|
||||||
|
@ -229,17 +241,17 @@ async fn handle_connection(stream: &mut TcpStream, pull_id: Rc<RefCell<u32>>, cf
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn start(cfg: Config) {
|
pub fn start(cfg: Rc<Config>, restart_idle: Rc<Semaphore>) {
|
||||||
task::spawn(async move {
|
task::spawn(async move {
|
||||||
let pull_id = Rc::new(RefCell::new(0u32));
|
let pull_id = Rc::new(RefCell::new(0u32));
|
||||||
let cfg = Rc::new(cfg);
|
|
||||||
loop {
|
loop {
|
||||||
let mut stream = TcpStream::accept(1380, 2048, 2048).await.unwrap();
|
let mut stream = TcpStream::accept(1380, 2048, 2048).await.unwrap();
|
||||||
let pull_id = pull_id.clone();
|
let pull_id = pull_id.clone();
|
||||||
let cfg = cfg.clone();
|
let cfg = cfg.clone();
|
||||||
|
let restart_idle = restart_idle.clone();
|
||||||
task::spawn(async move {
|
task::spawn(async move {
|
||||||
info!("received connection");
|
info!("received connection");
|
||||||
let _ = handle_connection(&mut stream, pull_id, cfg)
|
let _ = handle_connection(&mut stream, pull_id, cfg, restart_idle)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| warn!("connection terminated: {:?}", e));
|
.map_err(|e| warn!("connection terminated: {:?}", e));
|
||||||
let _ = stream.flush().await;
|
let _ = stream.flush().await;
|
||||||
|
|
|
@ -102,7 +102,7 @@ mod remote_moninj {
|
||||||
overrd: i8,
|
overrd: i8,
|
||||||
value: i8,
|
value: i8,
|
||||||
) {
|
) {
|
||||||
let _lock = aux_mutex.lock();
|
let _lock = aux_mutex.async_lock().await;
|
||||||
drtioaux_async::send(
|
drtioaux_async::send(
|
||||||
linkno,
|
linkno,
|
||||||
&drtioaux_async::Packet::InjectionRequest {
|
&drtioaux_async::Packet::InjectionRequest {
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
|
#[cfg(not(feature = "target_ebaz4205"))]
|
||||||
use embedded_hal::blocking::delay::DelayMs;
|
use embedded_hal::blocking::delay::DelayMs;
|
||||||
#[cfg(has_si5324)]
|
#[cfg(has_si5324)]
|
||||||
use ksupport::i2c;
|
use ksupport::i2c;
|
||||||
|
#[cfg(not(feature = "target_ebaz4205"))]
|
||||||
use libboard_artiq::pl;
|
use libboard_artiq::pl;
|
||||||
#[cfg(has_si5324)]
|
#[cfg(has_si5324)]
|
||||||
use libboard_artiq::si5324;
|
use libboard_artiq::si5324;
|
||||||
|
@ -10,7 +12,9 @@ use libboard_artiq::si549;
|
||||||
use libboard_zynq::i2c::I2c;
|
use libboard_zynq::i2c::I2c;
|
||||||
use libboard_zynq::timer::GlobalTimer;
|
use libboard_zynq::timer::GlobalTimer;
|
||||||
use libconfig::Config;
|
use libconfig::Config;
|
||||||
use log::{info, warn};
|
#[cfg(not(feature = "target_ebaz4205"))]
|
||||||
|
use log::info;
|
||||||
|
use log::warn;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Copy, Clone)]
|
#[derive(Debug, PartialEq, Copy, Clone)]
|
||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
|
@ -69,7 +73,7 @@ fn get_rtio_clock_cfg(cfg: &Config) -> RtioClock {
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(has_drtio))]
|
#[cfg(not(any(has_drtio, feature = "target_ebaz4205")))]
|
||||||
fn init_rtio(timer: &mut GlobalTimer) {
|
fn init_rtio(timer: &mut GlobalTimer) {
|
||||||
info!("Switching SYS clocks...");
|
info!("Switching SYS clocks...");
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -429,7 +433,7 @@ pub fn init(timer: &mut GlobalTimer, cfg: &Config) {
|
||||||
#[cfg(has_drtio)]
|
#[cfg(has_drtio)]
|
||||||
init_drtio(timer);
|
init_drtio(timer);
|
||||||
|
|
||||||
#[cfg(not(has_drtio))]
|
#[cfg(not(any(has_drtio, feature = "target_ebaz4205")))]
|
||||||
init_rtio(timer);
|
init_rtio(timer);
|
||||||
|
|
||||||
#[cfg(all(has_si549, has_wrpll))]
|
#[cfg(all(has_si549, has_wrpll))]
|
||||||
|
|
|
@ -792,6 +792,7 @@ pub mod drtio {
|
||||||
id: u32,
|
id: u32,
|
||||||
destination: u8,
|
destination: u8,
|
||||||
run: bool,
|
run: bool,
|
||||||
|
timestamp: u64,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let linkno = routing_table.0[destination as usize][0] - 1;
|
let linkno = routing_table.0[destination as usize][0] - 1;
|
||||||
let reply = aux_transact(
|
let reply = aux_transact(
|
||||||
|
@ -803,6 +804,7 @@ pub mod drtio {
|
||||||
source: 0,
|
source: 0,
|
||||||
destination: destination,
|
destination: destination,
|
||||||
run: run,
|
run: run,
|
||||||
|
timestamp,
|
||||||
},
|
},
|
||||||
timer,
|
timer,
|
||||||
)
|
)
|
||||||
|
|
|
@ -100,12 +100,22 @@ pub async fn load(
|
||||||
timer: GlobalTimer,
|
timer: GlobalTimer,
|
||||||
id: u32,
|
id: u32,
|
||||||
run: bool,
|
run: bool,
|
||||||
|
timestamp: u64,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
if let Some(subkernel) = SUBKERNELS.async_lock().await.get_mut(&id) {
|
if let Some(subkernel) = SUBKERNELS.async_lock().await.get_mut(&id) {
|
||||||
if subkernel.state != SubkernelState::Uploaded {
|
if subkernel.state != SubkernelState::Uploaded {
|
||||||
return Err(Error::IncorrectState);
|
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 {
|
if run {
|
||||||
subkernel.state = SubkernelState::Running;
|
subkernel.state = SubkernelState::Running;
|
||||||
}
|
}
|
||||||
|
|
|
@ -826,6 +826,7 @@ fn process_aux_packet(
|
||||||
destination: _destination,
|
destination: _destination,
|
||||||
id,
|
id,
|
||||||
run,
|
run,
|
||||||
|
timestamp,
|
||||||
} => {
|
} => {
|
||||||
forward!(
|
forward!(
|
||||||
router,
|
router,
|
||||||
|
@ -844,7 +845,7 @@ fn process_aux_packet(
|
||||||
// cannot run kernel while DDMA is running
|
// cannot run kernel while DDMA is running
|
||||||
succeeded = false;
|
succeeded = false;
|
||||||
} else {
|
} else {
|
||||||
succeeded |= kernel_manager.run(source, id).is_ok();
|
succeeded |= kernel_manager.run(source, id, timestamp).is_ok();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
router.send(
|
router.send(
|
||||||
|
|
|
@ -8,7 +8,7 @@ use core_io::{Error as IoError, Write};
|
||||||
use cslice::AsCSlice;
|
use cslice::AsCSlice;
|
||||||
use dma::{Error as DmaError, Manager as DmaManager};
|
use dma::{Error as DmaError, Manager as DmaManager};
|
||||||
use io::{Cursor, ProtoWrite};
|
use io::{Cursor, ProtoWrite};
|
||||||
use ksupport::{eh_artiq, kernel, rpc};
|
use ksupport::{eh_artiq, kernel, rpc, rtio};
|
||||||
use libboard_artiq::{drtio_routing::RoutingTable,
|
use libboard_artiq::{drtio_routing::RoutingTable,
|
||||||
drtioaux,
|
drtioaux,
|
||||||
drtioaux_proto::{PayloadStatus, MASTER_PAYLOAD_MAX_SIZE},
|
drtioaux_proto::{PayloadStatus, MASTER_PAYLOAD_MAX_SIZE},
|
||||||
|
@ -349,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 {
|
if self.session.kernel_state != KernelState::Loaded || self.session.id != id {
|
||||||
self.load(id)?;
|
self.load(id)?;
|
||||||
}
|
}
|
||||||
|
@ -359,6 +359,7 @@ impl<'a> Manager<'_> {
|
||||||
csr::cri_con::selected_write(2);
|
csr::cri_con::selected_write(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rtio::at_mu(timestamp as i64);
|
||||||
self.control.tx.send(kernel::Message::StartRequest);
|
self.control.tx.send(kernel::Message::StartRequest);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -812,6 +813,7 @@ impl<'a> Manager<'_> {
|
||||||
id,
|
id,
|
||||||
destination: sk_destination,
|
destination: sk_destination,
|
||||||
run,
|
run,
|
||||||
|
timestamp,
|
||||||
} => {
|
} => {
|
||||||
self.session.kernel_state = KernelState::SubkernelAwaitLoad;
|
self.session.kernel_state = KernelState::SubkernelAwaitLoad;
|
||||||
router.route(
|
router.route(
|
||||||
|
@ -820,6 +822,7 @@ impl<'a> Manager<'_> {
|
||||||
destination: sk_destination,
|
destination: sk_destination,
|
||||||
id: id,
|
id: id,
|
||||||
run: run,
|
run: run,
|
||||||
|
timestamp,
|
||||||
},
|
},
|
||||||
routing_table,
|
routing_table,
|
||||||
rank,
|
rank,
|
||||||
|
|
Loading…
Reference in New Issue