forked from M-Labs/artiq-zynq
Compare commits
62 Commits
refactor_n
...
master
Author | SHA1 | Date |
---|---|---|
Sebastien Bourdeauducq | 1f5ea41934 | |
Sebastien Bourdeauducq | 7f83d56ef5 | |
Jonathan Coates | 1d431456f4 | |
Sebastien Bourdeauducq | b03e380c1e | |
occheung | 47fc53c4bf | |
occheung | 42eaecf9e1 | |
occheung | beb7e6f994 | |
occheung | 4502a47aa6 | |
occheung | ac6b7d5cf0 | |
occheung | 3019bc6123 | |
occheung | 95b8562812 | |
occheung | a13f5d02fa | |
occheung | e52aa77068 | |
occheung | 8e28d12ad0 | |
occheung | 47cddae04f | |
occheung | 27a65df40e | |
occheung | 759cca3bfd | |
occheung | aadb6fc22d | |
occheung | ae4d5a4228 | |
occheung | 6f1d727ca2 | |
occheung | 7da5061f7e | |
occheung | 47d418c69e | |
occheung | d2979e8894 | |
occheung | 3884c14a19 | |
occheung | c5b00d8e4e | |
occheung | 2985875f9a | |
occheung | 5cb565a7e0 | |
occheung | 59954829a2 | |
occheung | 960864c847 | |
occheung | bdc29e5709 | |
occheung | 332732dc44 | |
occheung | 244c7396d9 | |
newell | 2c633409b8 | |
Sebastien Bourdeauducq | 9774b39fd8 | |
Sebastien Bourdeauducq | 9054e4a7cb | |
newell | d79bf8d54a | |
Sebastien Bourdeauducq | 75e7fc55a3 | |
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 | |
abdul124 | bd1de933fb | |
abdul124 | e8d77fca3e | |
abdul124 | 85e8a3fc44 | |
Sebastien Bourdeauducq | 04078b3d89 | |
abdul124 | d508c5c6f8 | |
abdul124 | bae41253e4 | |
abdul124 | 20181e9915 | |
abdul124 | a835149619 |
90
README.md
90
README.md
|
@ -4,60 +4,102 @@ 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).
|
||||
|
||||
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
|
||||
-------
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
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},
|
||||
},
|
||||
}
|
||||
|
||||
# TTLs starting at RTIO channel 2, ending at RTIO channel 15
|
||||
for i in range(2, 16):
|
||||
device_db["ttl" + str(i)] = {
|
||||
"type": "local",
|
||||
"module": "artiq.coredevice.ttl",
|
||||
"class": "TTLInOut",
|
||||
"arguments": {"channel": i},
|
||||
}
|
||||
|
||||
device_db.update(
|
||||
spi0={
|
||||
"type": "local",
|
||||
"module": "artiq.coredevice.spi2",
|
||||
"class": "SPIMaster",
|
||||
"arguments": {"channel": 16},
|
||||
},
|
||||
dds0={
|
||||
"type": "local",
|
||||
"module": "artiq.coredevice.ad9834",
|
||||
"class": "AD9834",
|
||||
"arguments": {"spi_device": "spi0"},
|
||||
},
|
||||
)
|
108
flake.lock
108
flake.lock
|
@ -11,11 +11,11 @@
|
|||
"src-pythonparser": "src-pythonparser"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1722417433,
|
||||
"narHash": "sha256-QEbcVdL1sUQEbMCvCUvPM8DKqwOth3gJpdiLTf4hPN8=",
|
||||
"lastModified": 1732066716,
|
||||
"narHash": "sha256-krjvt9+RccnAxSEZcFhRpjA2S3CoqE4MSa1JUg421b4=",
|
||||
"ref": "refs/heads/master",
|
||||
"rev": "0623480c82c28d57e14dc4f363374758a52284d3",
|
||||
"revCount": 8952,
|
||||
"rev": "270a417a28b516d36983779a1adb6d33a3c55a4a",
|
||||
"revCount": 9102,
|
||||
"type": "git",
|
||||
"url": "https://github.com/m-labs/artiq.git"
|
||||
},
|
||||
|
@ -68,45 +68,13 @@
|
|||
"type": "github"
|
||||
}
|
||||
},
|
||||
"mozilla-overlay": {
|
||||
"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_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"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1721924956,
|
||||
"narHash": "sha256-Sb1jlyRO+N8jBXEX9Pg9Z1Qb8Bw9QyOgLDNMEpmjZ2M=",
|
||||
"lastModified": 1731319897,
|
||||
"narHash": "sha256-PbABj4tnbWFMfBp6OcUK5iGy1QY+/Z96ZcLpooIbuEI=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "5ad6a14c6bf098e98800b091668718c336effc95",
|
||||
"rev": "dc460ec76cbff0e66e269457d7b728432263166c",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -119,7 +87,6 @@
|
|||
"root": {
|
||||
"inputs": {
|
||||
"artiq": "artiq",
|
||||
"mozilla-overlay": "mozilla-overlay",
|
||||
"zynq-rs": "zynq-rs"
|
||||
}
|
||||
},
|
||||
|
@ -131,15 +98,38 @@
|
|||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1722046723,
|
||||
"narHash": "sha256-G7/gHz8ORRvHd1/RIURrdcswKRPe9K0FsIYR4v5jSWo=",
|
||||
"lastModified": 1719454714,
|
||||
"narHash": "sha256-MojqG0lyUINkEk0b3kM2drsU5vyaF8DFZe/FAlZVOGs=",
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"rev": "56baac5e6b2743d4730e664ea64f6d8a2aad0fbb",
|
||||
"rev": "d1c527659cf076ecc4b96a91c702d080b213801e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "oxalica",
|
||||
"ref": "snapshot/2024-08-01",
|
||||
"repo": "rust-overlay",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"rust-overlay_2": {
|
||||
"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"
|
||||
}
|
||||
|
@ -152,11 +142,11 @@
|
|||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1717637367,
|
||||
"narHash": "sha256-4mSm9wl5EMgzzrW6w86IDUevkEOT99FESHGcxcyQbD0=",
|
||||
"lastModified": 1728371104,
|
||||
"narHash": "sha256-PPnAyDedUQ7Og/Cby9x5OT9wMkNGTP8GS53V6N/dk4w=",
|
||||
"owner": "m-labs",
|
||||
"repo": "sipyco",
|
||||
"rev": "02b96ec2473a3c3d3c980899de2564ddce949dab",
|
||||
"rev": "094a6cd63ffa980ef63698920170e50dc9ba77fd",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -168,11 +158,11 @@
|
|||
"src-migen": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1721561053,
|
||||
"narHash": "sha256-z3LRhNmKZrjr6rFD0yxtccSa/SWvFIYmb+G/D5d2Jd8=",
|
||||
"lastModified": 1727677091,
|
||||
"narHash": "sha256-Zg3SQnTwMM/VkOGKogbPyuCC2NhLy8HB2SPEUWWNgCU=",
|
||||
"owner": "m-labs",
|
||||
"repo": "migen",
|
||||
"rev": "9279e8623f8433bc4f23ac51e5e2331bfe544417",
|
||||
"rev": "c19ae9f8ae162ffe2d310a92bfce53ac2a821bc8",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -184,11 +174,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"
|
||||
|
@ -232,18 +222,18 @@
|
|||
},
|
||||
"zynq-rs": {
|
||||
"inputs": {
|
||||
"mozilla-overlay": "mozilla-overlay_2",
|
||||
"nixpkgs": [
|
||||
"artiq",
|
||||
"nixpkgs"
|
||||
]
|
||||
],
|
||||
"rust-overlay": "rust-overlay_2"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1720537402,
|
||||
"narHash": "sha256-ybvaQ48SVBqYVqgYmGUdefGZkni7PJ90qYQPHnFOwDs=",
|
||||
"lastModified": 1731749494,
|
||||
"narHash": "sha256-WGigAhvVCGN5YZ1dHPyvoqAh47W1Gtph036O1aKFlLE=",
|
||||
"ref": "refs/heads/master",
|
||||
"rev": "b2b3e5c933cbc4b7cb14adde480d7561a3ae71ee",
|
||||
"revCount": 648,
|
||||
"rev": "12975de2e110d7948bf47b768559f727d0abc8fc",
|
||||
"revCount": 655,
|
||||
"type": "git",
|
||||
"url": "https://git.m-labs.hk/m-labs/zynq-rs"
|
||||
},
|
||||
|
|
11
flake.nix
11
flake.nix
|
@ -2,13 +2,12 @@
|
|||
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.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;
|
||||
|
@ -75,7 +74,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 = ''
|
||||
|
@ -364,7 +363,8 @@
|
|||
(board-package-set { target = "zc706"; variant = "acpki_nist_qc2_satellite_100mhz"; }) //
|
||||
(board-package-set { target = "kasli_soc"; variant = "demo"; json = ./demo.json; }) //
|
||||
(board-package-set { target = "kasli_soc"; variant = "master"; json = ./kasli-soc-master.json; }) //
|
||||
(board-package-set { target = "kasli_soc"; variant = "satellite"; json = ./kasli-soc-satellite.json; });
|
||||
(board-package-set { target = "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; };
|
||||
|
||||
|
@ -384,6 +384,7 @@
|
|||
artiqpkgs.artiq
|
||||
artiqpkgs.vivado
|
||||
binutils-arm
|
||||
pre-commit
|
||||
];
|
||||
XARGO_RUST_SRC = "${rust}/lib/rustlib/src/rust/library";
|
||||
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]
|
|
@ -395,7 +395,7 @@ checksum = "c75de51135344a4f8ed3cfe2720dc27736f7711989703a0b43aadf3753c55577"
|
|||
[[package]]
|
||||
name = "nalgebra"
|
||||
version = "0.32.6"
|
||||
source = "git+https://git.m-labs.hk/M-labs/nalgebra?rev=dd00f9b#dd00f9b46046e0b931d1b470166db02fd29591be"
|
||||
source = "git+https://git.m-labs.hk/M-Labs/nalgebra.git?rev=dd00f9b#dd00f9b46046e0b931d1b470166db02fd29591be"
|
||||
dependencies = [
|
||||
"approx",
|
||||
"num-complex",
|
||||
|
@ -559,7 +559,9 @@ name = "satman"
|
|||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"build_zynq",
|
||||
"byteorder",
|
||||
"core_io",
|
||||
"crc",
|
||||
"cslice",
|
||||
"embedded-hal",
|
||||
"io",
|
||||
|
|
|
@ -0,0 +1,307 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import argparse
|
||||
|
||||
import analyzer
|
||||
import dma
|
||||
from artiq.gateware import rtio
|
||||
from artiq.gateware.rtio.phy import 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"),
|
||||
)
|
||||
]
|
||||
|
||||
|
||||
# Connector DATA1
|
||||
def _create_ttl():
|
||||
_ttl = []
|
||||
|
||||
for idx, elem in enumerate([x for x in range(5, 21) if x not in (10, 12)]):
|
||||
_ttl.append(
|
||||
("ttl", idx, Pins("DATA1:DATA1-{}".format(elem)), IOStandard("LVCMOS33")),
|
||||
)
|
||||
return _ttl
|
||||
|
||||
|
||||
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)
|
||||
platform.add_extension(_create_ttl())
|
||||
|
||||
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))
|
||||
|
||||
for i in range(14):
|
||||
print("TTL at RTIO channel 0x{:06x}".format(len(self.rtio_channels)))
|
||||
ttl = self.platform.request("ttl", i)
|
||||
phy = ttl_simple.InOut(ttl)
|
||||
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]
|
||||
target_zc706 = ["libboard_zynq/target_zc706", "libconfig/target_zc706"]
|
||||
target_kasli_soc = ["libboard_zynq/target_kasli_soc", "libconfig/target_kasli_soc"]
|
||||
target_ebaz4205 = ["libboard_zynq/target_ebaz4205", "libconfig/target_ebaz4205"]
|
||||
calibrate_wrpll_skew = []
|
||||
|
||||
[build-dependencies]
|
||||
|
|
|
@ -185,6 +185,24 @@ unsafe fn align_comma(timer: &mut GlobalTimer) {
|
|||
}
|
||||
}
|
||||
|
||||
pub unsafe fn align_wordslip(timer: &mut GlobalTimer, trx_no: u8) -> bool {
|
||||
pl::csr::eem_transceiver::transceiver_sel_write(trx_no);
|
||||
|
||||
for slip in 0..=1 {
|
||||
pl::csr::eem_transceiver::wordslip_write(slip as u8);
|
||||
timer.delay_us(1);
|
||||
pl::csr::eem_transceiver::comma_align_reset_write(1);
|
||||
timer.delay_us(100);
|
||||
|
||||
if pl::csr::eem_transceiver::comma_read() == 1 {
|
||||
debug!("comma alignment completed with {} wordslip", slip);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
pub fn init(timer: &mut GlobalTimer, cfg: &Config) {
|
||||
for trx_no in 0..pl::csr::CONFIG_EEM_DRTIO_COUNT {
|
||||
unsafe {
|
||||
|
@ -222,7 +240,6 @@ pub fn init(timer: &mut GlobalTimer, cfg: &Config) {
|
|||
|
||||
unsafe {
|
||||
align_comma(timer);
|
||||
pl::csr::eem_transceiver::rx_ready_write(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -255,6 +255,7 @@ pub enum Packet {
|
|||
destination: u8,
|
||||
id: u32,
|
||||
run: bool,
|
||||
timestamp: u64,
|
||||
},
|
||||
SubkernelLoadRunReply {
|
||||
destination: u8,
|
||||
|
@ -287,6 +288,77 @@ pub enum Packet {
|
|||
SubkernelMessageAck {
|
||||
destination: u8,
|
||||
},
|
||||
|
||||
CoreMgmtGetLogRequest {
|
||||
destination: u8,
|
||||
clear: bool,
|
||||
},
|
||||
CoreMgmtClearLogRequest {
|
||||
destination: u8,
|
||||
},
|
||||
CoreMgmtSetLogLevelRequest {
|
||||
destination: u8,
|
||||
log_level: u8,
|
||||
},
|
||||
CoreMgmtSetUartLogLevelRequest {
|
||||
destination: u8,
|
||||
log_level: u8,
|
||||
},
|
||||
CoreMgmtConfigReadRequest {
|
||||
destination: u8,
|
||||
length: u16,
|
||||
key: [u8; MASTER_PAYLOAD_MAX_SIZE],
|
||||
},
|
||||
CoreMgmtConfigReadContinue {
|
||||
destination: u8,
|
||||
},
|
||||
CoreMgmtConfigWriteRequest {
|
||||
destination: u8,
|
||||
last: bool,
|
||||
length: u16,
|
||||
data: [u8; MASTER_PAYLOAD_MAX_SIZE],
|
||||
},
|
||||
CoreMgmtConfigRemoveRequest {
|
||||
destination: u8,
|
||||
length: u16,
|
||||
key: [u8; MASTER_PAYLOAD_MAX_SIZE],
|
||||
},
|
||||
CoreMgmtConfigEraseRequest {
|
||||
destination: u8,
|
||||
},
|
||||
CoreMgmtRebootRequest {
|
||||
destination: u8,
|
||||
},
|
||||
CoreMgmtAllocatorDebugRequest {
|
||||
destination: u8,
|
||||
},
|
||||
CoreMgmtFlashRequest {
|
||||
destination: u8,
|
||||
payload_length: u32,
|
||||
},
|
||||
CoreMgmtFlashAddDataRequest {
|
||||
destination: u8,
|
||||
last: bool,
|
||||
length: u16,
|
||||
data: [u8; MASTER_PAYLOAD_MAX_SIZE],
|
||||
},
|
||||
CoreMgmtDropLinkAck {
|
||||
destination: u8,
|
||||
},
|
||||
CoreMgmtDropLink,
|
||||
CoreMgmtGetLogReply {
|
||||
last: bool,
|
||||
length: u16,
|
||||
data: [u8; SAT_PAYLOAD_MAX_SIZE],
|
||||
},
|
||||
CoreMgmtConfigReadReply {
|
||||
last: bool,
|
||||
length: u16,
|
||||
value: [u8; SAT_PAYLOAD_MAX_SIZE],
|
||||
},
|
||||
CoreMgmtReply {
|
||||
succeeded: bool,
|
||||
},
|
||||
}
|
||||
|
||||
impl Packet {
|
||||
|
@ -514,6 +586,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()?,
|
||||
|
@ -563,6 +636,115 @@ impl Packet {
|
|||
destination: reader.read_u8()?,
|
||||
},
|
||||
|
||||
0xd0 => Packet::CoreMgmtGetLogRequest {
|
||||
destination: reader.read_u8()?,
|
||||
clear: reader.read_bool()?,
|
||||
},
|
||||
0xd1 => Packet::CoreMgmtClearLogRequest {
|
||||
destination: reader.read_u8()?,
|
||||
},
|
||||
0xd2 => Packet::CoreMgmtSetLogLevelRequest {
|
||||
destination: reader.read_u8()?,
|
||||
log_level: reader.read_u8()?,
|
||||
},
|
||||
0xd3 => Packet::CoreMgmtSetUartLogLevelRequest {
|
||||
destination: reader.read_u8()?,
|
||||
log_level: reader.read_u8()?,
|
||||
},
|
||||
0xd4 => {
|
||||
let destination = reader.read_u8()?;
|
||||
let length = reader.read_u16()?;
|
||||
let mut key: [u8; MASTER_PAYLOAD_MAX_SIZE] = [0; MASTER_PAYLOAD_MAX_SIZE];
|
||||
reader.read_exact(&mut key[0..length as usize])?;
|
||||
Packet::CoreMgmtConfigReadRequest {
|
||||
destination: destination,
|
||||
length: length,
|
||||
key: key,
|
||||
}
|
||||
}
|
||||
0xd5 => Packet::CoreMgmtConfigReadContinue {
|
||||
destination: reader.read_u8()?,
|
||||
},
|
||||
0xd6 => {
|
||||
let destination = reader.read_u8()?;
|
||||
let last = reader.read_bool()?;
|
||||
let length = reader.read_u16()?;
|
||||
let mut data: [u8; MASTER_PAYLOAD_MAX_SIZE] = [0; MASTER_PAYLOAD_MAX_SIZE];
|
||||
reader.read_exact(&mut data[0..length as usize])?;
|
||||
Packet::CoreMgmtConfigWriteRequest {
|
||||
destination: destination,
|
||||
last: last,
|
||||
length: length,
|
||||
data: data,
|
||||
}
|
||||
}
|
||||
0xd7 => {
|
||||
let destination = reader.read_u8()?;
|
||||
let length = reader.read_u16()?;
|
||||
let mut key: [u8; MASTER_PAYLOAD_MAX_SIZE] = [0; MASTER_PAYLOAD_MAX_SIZE];
|
||||
reader.read_exact(&mut key[0..length as usize])?;
|
||||
Packet::CoreMgmtConfigRemoveRequest {
|
||||
destination: destination,
|
||||
length: length,
|
||||
key: key,
|
||||
}
|
||||
}
|
||||
0xd8 => Packet::CoreMgmtConfigEraseRequest {
|
||||
destination: reader.read_u8()?,
|
||||
},
|
||||
0xd9 => Packet::CoreMgmtRebootRequest {
|
||||
destination: reader.read_u8()?,
|
||||
},
|
||||
0xda => Packet::CoreMgmtAllocatorDebugRequest {
|
||||
destination: reader.read_u8()?,
|
||||
},
|
||||
0xdb => Packet::CoreMgmtFlashRequest {
|
||||
destination: reader.read_u8()?,
|
||||
payload_length: reader.read_u32()?,
|
||||
},
|
||||
0xdc => {
|
||||
let destination = reader.read_u8()?;
|
||||
let last = reader.read_bool()?;
|
||||
let length = reader.read_u16()?;
|
||||
let mut data: [u8; MASTER_PAYLOAD_MAX_SIZE] = [0; MASTER_PAYLOAD_MAX_SIZE];
|
||||
reader.read_exact(&mut data[0..length as usize])?;
|
||||
Packet::CoreMgmtFlashAddDataRequest {
|
||||
destination: destination,
|
||||
last: last,
|
||||
length: length,
|
||||
data: data,
|
||||
}
|
||||
}
|
||||
0xdd => Packet::CoreMgmtDropLinkAck {
|
||||
destination: reader.read_u8()?,
|
||||
},
|
||||
0xde => Packet::CoreMgmtDropLink,
|
||||
0xdf => {
|
||||
let last = reader.read_bool()?;
|
||||
let length = reader.read_u16()?;
|
||||
let mut data: [u8; SAT_PAYLOAD_MAX_SIZE] = [0; SAT_PAYLOAD_MAX_SIZE];
|
||||
reader.read_exact(&mut data[0..length as usize])?;
|
||||
Packet::CoreMgmtGetLogReply {
|
||||
last: last,
|
||||
length: length,
|
||||
data: data,
|
||||
}
|
||||
}
|
||||
0xe0 => {
|
||||
let last = reader.read_bool()?;
|
||||
let length = reader.read_u16()?;
|
||||
let mut value: [u8; SAT_PAYLOAD_MAX_SIZE] = [0; SAT_PAYLOAD_MAX_SIZE];
|
||||
reader.read_exact(&mut value[0..length as usize])?;
|
||||
Packet::CoreMgmtConfigReadReply {
|
||||
last: last,
|
||||
length: length,
|
||||
value: value,
|
||||
}
|
||||
}
|
||||
0xe1 => Packet::CoreMgmtReply {
|
||||
succeeded: reader.read_bool()?,
|
||||
},
|
||||
|
||||
ty => return Err(Error::UnknownPacket(ty)),
|
||||
})
|
||||
}
|
||||
|
@ -877,12 +1059,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)?;
|
||||
|
@ -938,6 +1122,115 @@ impl Packet {
|
|||
writer.write_u8(0xcc)?;
|
||||
writer.write_u8(destination)?;
|
||||
}
|
||||
|
||||
Packet::CoreMgmtGetLogRequest { destination, clear } => {
|
||||
writer.write_u8(0xd0)?;
|
||||
writer.write_u8(destination)?;
|
||||
writer.write_bool(clear)?;
|
||||
}
|
||||
Packet::CoreMgmtClearLogRequest { destination } => {
|
||||
writer.write_u8(0xd1)?;
|
||||
writer.write_u8(destination)?;
|
||||
}
|
||||
Packet::CoreMgmtSetLogLevelRequest { destination, log_level } => {
|
||||
writer.write_u8(0xd2)?;
|
||||
writer.write_u8(destination)?;
|
||||
writer.write_u8(log_level)?;
|
||||
}
|
||||
Packet::CoreMgmtSetUartLogLevelRequest { destination, log_level } => {
|
||||
writer.write_u8(0xd3)?;
|
||||
writer.write_u8(destination)?;
|
||||
writer.write_u8(log_level)?;
|
||||
}
|
||||
Packet::CoreMgmtConfigReadRequest {
|
||||
destination,
|
||||
length,
|
||||
key,
|
||||
} => {
|
||||
writer.write_u8(0xd4)?;
|
||||
writer.write_u8(destination)?;
|
||||
writer.write_u16(length)?;
|
||||
writer.write_all(&key[0..length as usize])?;
|
||||
}
|
||||
Packet::CoreMgmtConfigReadContinue { destination } => {
|
||||
writer.write_u8(0xd5)?;
|
||||
writer.write_u8(destination)?;
|
||||
}
|
||||
Packet::CoreMgmtConfigWriteRequest {
|
||||
destination,
|
||||
last,
|
||||
length,
|
||||
data,
|
||||
} => {
|
||||
writer.write_u8(0xd6)?;
|
||||
writer.write_u8(destination)?;
|
||||
writer.write_bool(last)?;
|
||||
writer.write_u16(length)?;
|
||||
writer.write_all(&data[0..length as usize])?;
|
||||
}
|
||||
Packet::CoreMgmtConfigRemoveRequest {
|
||||
destination,
|
||||
length,
|
||||
key,
|
||||
} => {
|
||||
writer.write_u8(0xd7)?;
|
||||
writer.write_u8(destination)?;
|
||||
writer.write_u16(length)?;
|
||||
writer.write_all(&key[0..length as usize])?;
|
||||
}
|
||||
Packet::CoreMgmtConfigEraseRequest { destination } => {
|
||||
writer.write_u8(0xd8)?;
|
||||
writer.write_u8(destination)?;
|
||||
}
|
||||
Packet::CoreMgmtRebootRequest { destination } => {
|
||||
writer.write_u8(0xd9)?;
|
||||
writer.write_u8(destination)?;
|
||||
}
|
||||
Packet::CoreMgmtAllocatorDebugRequest { destination } => {
|
||||
writer.write_u8(0xda)?;
|
||||
writer.write_u8(destination)?;
|
||||
}
|
||||
Packet::CoreMgmtFlashRequest {
|
||||
destination,
|
||||
payload_length,
|
||||
} => {
|
||||
writer.write_u8(0xdb)?;
|
||||
writer.write_u8(destination)?;
|
||||
writer.write_u32(payload_length)?;
|
||||
}
|
||||
Packet::CoreMgmtFlashAddDataRequest {
|
||||
destination,
|
||||
last,
|
||||
length,
|
||||
data,
|
||||
} => {
|
||||
writer.write_u8(0xdc)?;
|
||||
writer.write_u8(destination)?;
|
||||
writer.write_bool(last)?;
|
||||
writer.write_u16(length)?;
|
||||
writer.write_all(&data[..length as usize])?;
|
||||
}
|
||||
Packet::CoreMgmtDropLinkAck { destination } => {
|
||||
writer.write_u8(0xdd)?;
|
||||
writer.write_u8(destination)?;
|
||||
}
|
||||
Packet::CoreMgmtDropLink => writer.write_u8(0xde)?,
|
||||
Packet::CoreMgmtGetLogReply { last, length, data } => {
|
||||
writer.write_u8(0xdf)?;
|
||||
writer.write_bool(last)?;
|
||||
writer.write_u16(length)?;
|
||||
writer.write_all(&data[0..length as usize])?;
|
||||
}
|
||||
Packet::CoreMgmtConfigReadReply { last, length, value } => {
|
||||
writer.write_u8(0xe0)?;
|
||||
writer.write_bool(last)?;
|
||||
writer.write_u16(length)?;
|
||||
writer.write_all(&value[0..length as usize])?;
|
||||
}
|
||||
Packet::CoreMgmtReply { succeeded } => {
|
||||
writer.write_u8(0xe1)?;
|
||||
writer.write_bool(succeeded)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -974,7 +1267,8 @@ impl Packet {
|
|||
| Packet::SubkernelLoadRunReply { .. }
|
||||
| Packet::SubkernelMessageAck { .. }
|
||||
| Packet::DmaPlaybackStatus { .. }
|
||||
| Packet::SubkernelFinished { .. } => false,
|
||||
| Packet::SubkernelFinished { .. }
|
||||
| Packet::CoreMgmtDropLinkAck { .. } => false,
|
||||
_ => true,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -34,7 +34,7 @@ io = { path = "../libio" }
|
|||
libboard_artiq = { path = "../libboard_artiq" }
|
||||
|
||||
[dependencies.nalgebra]
|
||||
git = "https://git.m-labs.hk/M-labs/nalgebra.git"
|
||||
git = "https://git.m-labs.hk/M-Labs/nalgebra.git"
|
||||
rev = "dd00f9b"
|
||||
default-features = false
|
||||
features = ["libm", "alloc"]
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
use core::mem;
|
||||
|
||||
use core_io::Error as ReadError;
|
||||
use cslice::CSlice;
|
||||
use cslice::{AsCSlice, CSlice};
|
||||
use dwarf::eh::{self, EHAction, EHContext};
|
||||
use io::{Cursor, ProtoRead};
|
||||
use libc::{c_int, c_void, uintptr_t};
|
||||
|
@ -222,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;
|
||||
|
@ -477,20 +475,30 @@ extern "C" fn stop_fn(
|
|||
}
|
||||
}
|
||||
|
||||
// Must be kept in sync with preallocate_runtime_exception_names() in artiq/language/embedding_map.py
|
||||
static EXCEPTION_ID_LOOKUP: [(&str, u32); 12] = [
|
||||
("RuntimeError", 0),
|
||||
("RTIOUnderflow", 1),
|
||||
("RTIOOverflow", 2),
|
||||
("RTIODestinationUnreachable", 3),
|
||||
("DMAError", 4),
|
||||
("I2CError", 5),
|
||||
("CacheError", 6),
|
||||
("SPIError", 7),
|
||||
("ZeroDivisionError", 8),
|
||||
("IndexError", 9),
|
||||
("UnwrapNoneError", 10),
|
||||
("SubkernelError", 11),
|
||||
// Must be kept in sync with preallocate_runtime_exception_names() in `artiq.compiler.embedding`
|
||||
static EXCEPTION_ID_LOOKUP: [(&str, u32); 22] = [
|
||||
("RTIOUnderflow", 0),
|
||||
("RTIOOverflow", 1),
|
||||
("RTIODestinationUnreachable", 2),
|
||||
("DMAError", 3),
|
||||
("I2CError", 4),
|
||||
("CacheError", 5),
|
||||
("SPIError", 6),
|
||||
("SubkernelError", 7),
|
||||
("AssertionError", 8),
|
||||
("AttributeError", 9),
|
||||
("IndexError", 10),
|
||||
("IOError", 11),
|
||||
("KeyError", 12),
|
||||
("NotImplementedError", 13),
|
||||
("OverflowError", 14),
|
||||
("RuntimeError", 15),
|
||||
("TimeoutError", 16),
|
||||
("TypeError", 17),
|
||||
("ValueError", 18),
|
||||
("ZeroDivisionError", 19),
|
||||
("LinAlgError", 20),
|
||||
("UnwrapNoneError", 21),
|
||||
];
|
||||
|
||||
pub fn get_exception_id(name: &str) -> u32 {
|
||||
|
@ -525,3 +533,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) };
|
||||
}
|
||||
|
|
|
@ -332,6 +332,13 @@ pub fn resolve(required: &[u8]) -> Option<u32> {
|
|||
api!(sp_linalg_schur = linalg::sp_linalg_schur),
|
||||
api!(sp_linalg_hessenberg = linalg::sp_linalg_hessenberg),
|
||||
|
||||
/*
|
||||
* 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)
|
||||
|
|
|
@ -55,8 +55,8 @@ pub unsafe extern "C" fn np_linalg_cholesky(mat1: *mut InputMatrix, out: *mut In
|
|||
}
|
||||
|
||||
let outdim = out.get_dims();
|
||||
let out_slice = unsafe { slice::from_raw_parts_mut(out.data, outdim[0] * outdim[1]) };
|
||||
let data_slice1 = unsafe { slice::from_raw_parts_mut(mat1.data, dim1[0] * dim1[1]) };
|
||||
let out_slice = slice::from_raw_parts_mut(out.data, outdim[0] * outdim[1]);
|
||||
let data_slice1 = slice::from_raw_parts_mut(mat1.data, dim1[0] * dim1[1]);
|
||||
|
||||
let matrix1 = DMatrix::from_row_slice(dim1[0], dim1[1], data_slice1);
|
||||
let result = matrix1.cholesky();
|
||||
|
@ -93,9 +93,9 @@ pub unsafe extern "C" fn np_linalg_qr(mat1: *mut InputMatrix, out_q: *mut InputM
|
|||
let outq_dim = (*out_q).get_dims();
|
||||
let outr_dim = (*out_r).get_dims();
|
||||
|
||||
let data_slice1 = unsafe { slice::from_raw_parts_mut(mat1.data, dim1[0] * dim1[1]) };
|
||||
let out_q_slice = unsafe { slice::from_raw_parts_mut(out_q.data, outq_dim[0] * outq_dim[1]) };
|
||||
let out_r_slice = unsafe { slice::from_raw_parts_mut(out_r.data, outr_dim[0] * outr_dim[1]) };
|
||||
let data_slice1 = slice::from_raw_parts_mut(mat1.data, dim1[0] * dim1[1]);
|
||||
let out_q_slice = slice::from_raw_parts_mut(out_q.data, outq_dim[0] * outq_dim[1]);
|
||||
let out_r_slice = slice::from_raw_parts_mut(out_r.data, outr_dim[0] * outr_dim[1]);
|
||||
|
||||
// Refer to https://github.com/dimforge/nalgebra/issues/735
|
||||
let matrix1 = DMatrix::from_row_slice(dim1[0], dim1[1], data_slice1);
|
||||
|
@ -138,10 +138,10 @@ pub unsafe extern "C" fn np_linalg_svd(
|
|||
let outs_dim = (*outs).get_dims();
|
||||
let outvh_dim = (*outvh).get_dims();
|
||||
|
||||
let data_slice1 = unsafe { slice::from_raw_parts_mut(mat1.data, dim1[0] * dim1[1]) };
|
||||
let out_u_slice = unsafe { slice::from_raw_parts_mut(outu.data, outu_dim[0] * outu_dim[1]) };
|
||||
let out_s_slice = unsafe { slice::from_raw_parts_mut(outs.data, outs_dim[0]) };
|
||||
let out_vh_slice = unsafe { slice::from_raw_parts_mut(outvh.data, outvh_dim[0] * outvh_dim[1]) };
|
||||
let data_slice1 = slice::from_raw_parts_mut(mat1.data, dim1[0] * dim1[1]);
|
||||
let out_u_slice = slice::from_raw_parts_mut(outu.data, outu_dim[0] * outu_dim[1]);
|
||||
let out_s_slice = slice::from_raw_parts_mut(outs.data, outs_dim[0]);
|
||||
let out_vh_slice = slice::from_raw_parts_mut(outvh.data, outvh_dim[0] * outvh_dim[1]);
|
||||
|
||||
let matrix = DMatrix::from_row_slice(dim1[0], dim1[1], data_slice1);
|
||||
let result = matrix.svd(true, true);
|
||||
|
@ -180,8 +180,8 @@ pub unsafe extern "C" fn np_linalg_inv(mat1: *mut InputMatrix, out: *mut InputMa
|
|||
}
|
||||
|
||||
let outdim = out.get_dims();
|
||||
let out_slice = unsafe { slice::from_raw_parts_mut(out.data, outdim[0] * outdim[1]) };
|
||||
let data_slice1 = unsafe { slice::from_raw_parts_mut(mat1.data, dim1[0] * dim1[1]) };
|
||||
let out_slice = slice::from_raw_parts_mut(out.data, outdim[0] * outdim[1]);
|
||||
let data_slice1 = slice::from_raw_parts_mut(mat1.data, dim1[0] * dim1[1]);
|
||||
|
||||
let matrix = DMatrix::from_row_slice(dim1[0], dim1[1], data_slice1);
|
||||
if !matrix.is_invertible() {
|
||||
|
@ -210,8 +210,8 @@ pub unsafe extern "C" fn np_linalg_pinv(mat1: *mut InputMatrix, out: *mut InputM
|
|||
}
|
||||
let dim1 = (*mat1).get_dims();
|
||||
let outdim = out.get_dims();
|
||||
let out_slice = unsafe { slice::from_raw_parts_mut(out.data, outdim[0] * outdim[1]) };
|
||||
let data_slice1 = unsafe { slice::from_raw_parts_mut(mat1.data, dim1[0] * dim1[1]) };
|
||||
let out_slice = slice::from_raw_parts_mut(out.data, outdim[0] * outdim[1]);
|
||||
let data_slice1 = slice::from_raw_parts_mut(mat1.data, dim1[0] * dim1[1]);
|
||||
|
||||
let matrix = DMatrix::from_row_slice(dim1[0], dim1[1], data_slice1);
|
||||
let svd = matrix.svd(true, true);
|
||||
|
@ -247,11 +247,11 @@ pub unsafe extern "C" fn np_linalg_matrix_power(mat1: *mut InputMatrix, mat2: *m
|
|||
}
|
||||
|
||||
let dim1 = (*mat1).get_dims();
|
||||
let power = unsafe { slice::from_raw_parts_mut(mat2.data, 1) };
|
||||
let power = slice::from_raw_parts_mut(mat2.data, 1);
|
||||
let power = power[0];
|
||||
let outdim = out.get_dims();
|
||||
let out_slice = unsafe { slice::from_raw_parts_mut(out.data, outdim[0] * outdim[1]) };
|
||||
let data_slice1 = unsafe { slice::from_raw_parts_mut(mat1.data, dim1[0] * dim1[1]) };
|
||||
let out_slice = slice::from_raw_parts_mut(out.data, outdim[0] * outdim[1]);
|
||||
let data_slice1 = slice::from_raw_parts_mut(mat1.data, dim1[0] * dim1[1]);
|
||||
let mut abs_power = power;
|
||||
if abs_power < 0.0 {
|
||||
abs_power = abs_power * -1.0;
|
||||
|
@ -295,8 +295,8 @@ pub unsafe extern "C" fn np_linalg_det(mat1: *mut InputMatrix, out: *mut InputMa
|
|||
);
|
||||
}
|
||||
let dim1 = (*mat1).get_dims();
|
||||
let out_slice = unsafe { slice::from_raw_parts_mut(out.data, 1) };
|
||||
let data_slice1 = unsafe { slice::from_raw_parts_mut(mat1.data, dim1[0] * dim1[1]) };
|
||||
let out_slice = slice::from_raw_parts_mut(out.data, 1);
|
||||
let data_slice1 = slice::from_raw_parts_mut(mat1.data, dim1[0] * dim1[1]);
|
||||
|
||||
let matrix = DMatrix::from_row_slice(dim1[0], dim1[1], data_slice1);
|
||||
if !matrix.is_square() {
|
||||
|
@ -334,9 +334,9 @@ pub unsafe extern "C" fn sp_linalg_lu(mat1: *mut InputMatrix, out_l: *mut InputM
|
|||
let outl_dim = (*out_l).get_dims();
|
||||
let outu_dim = (*out_u).get_dims();
|
||||
|
||||
let data_slice1 = unsafe { slice::from_raw_parts_mut(mat1.data, dim1[0] * dim1[1]) };
|
||||
let out_l_slice = unsafe { slice::from_raw_parts_mut(out_l.data, outl_dim[0] * outl_dim[1]) };
|
||||
let out_u_slice = unsafe { slice::from_raw_parts_mut(out_u.data, outu_dim[0] * outu_dim[1]) };
|
||||
let data_slice1 = slice::from_raw_parts_mut(mat1.data, dim1[0] * dim1[1]);
|
||||
let out_l_slice = slice::from_raw_parts_mut(out_l.data, outl_dim[0] * outl_dim[1]);
|
||||
let out_u_slice = slice::from_raw_parts_mut(out_u.data, outu_dim[0] * outu_dim[1]);
|
||||
|
||||
let matrix = DMatrix::from_row_slice(dim1[0], dim1[1], data_slice1);
|
||||
let (_, l, u) = matrix.lu().unpack();
|
||||
|
@ -379,9 +379,9 @@ pub unsafe extern "C" fn sp_linalg_schur(mat1: *mut InputMatrix, out_t: *mut Inp
|
|||
let out_t_dim = (*out_t).get_dims();
|
||||
let out_z_dim = (*out_z).get_dims();
|
||||
|
||||
let data_slice1 = unsafe { slice::from_raw_parts_mut(mat1.data, dim1[0] * dim1[1]) };
|
||||
let out_t_slice = unsafe { slice::from_raw_parts_mut(out_t.data, out_t_dim[0] * out_t_dim[1]) };
|
||||
let out_z_slice = unsafe { slice::from_raw_parts_mut(out_z.data, out_z_dim[0] * out_z_dim[1]) };
|
||||
let data_slice1 = slice::from_raw_parts_mut(mat1.data, dim1[0] * dim1[1]);
|
||||
let out_t_slice = slice::from_raw_parts_mut(out_t.data, out_t_dim[0] * out_t_dim[1]);
|
||||
let out_z_slice = slice::from_raw_parts_mut(out_z.data, out_z_dim[0] * out_z_dim[1]);
|
||||
|
||||
let matrix = DMatrix::from_row_slice(dim1[0], dim1[1], data_slice1);
|
||||
let (z, t) = matrix.schur().unpack();
|
||||
|
@ -428,9 +428,9 @@ pub unsafe extern "C" fn sp_linalg_hessenberg(
|
|||
let out_h_dim = (*out_h).get_dims();
|
||||
let out_q_dim = (*out_q).get_dims();
|
||||
|
||||
let data_slice1 = unsafe { slice::from_raw_parts_mut(mat1.data, dim1[0] * dim1[1]) };
|
||||
let out_h_slice = unsafe { slice::from_raw_parts_mut(out_h.data, out_h_dim[0] * out_h_dim[1]) };
|
||||
let out_q_slice = unsafe { slice::from_raw_parts_mut(out_q.data, out_q_dim[0] * out_q_dim[1]) };
|
||||
let data_slice1 = slice::from_raw_parts_mut(mat1.data, dim1[0] * dim1[1]);
|
||||
let out_h_slice = slice::from_raw_parts_mut(out_h.data, out_h_dim[0] * out_h_dim[1]);
|
||||
let out_q_slice = slice::from_raw_parts_mut(out_q.data, out_q_dim[0] * out_q_dim[1]);
|
||||
|
||||
let matrix = DMatrix::from_row_slice(dim1[0], dim1[1], data_slice1);
|
||||
let (q, h) = matrix.hessenberg().unpack();
|
||||
|
|
|
@ -81,6 +81,7 @@ pub enum Message {
|
|||
id: u32,
|
||||
destination: u8,
|
||||
run: bool,
|
||||
timestamp: u64,
|
||||
},
|
||||
#[cfg(has_drtio)]
|
||||
SubkernelLoadRunReply {
|
||||
|
|
|
@ -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, 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) {
|
||||
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() {
|
||||
|
|
|
@ -8,6 +8,7 @@ edition = "2018"
|
|||
[features]
|
||||
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_ebaz4205 = ["libboard_zynq/target_ebaz4205", "libsupport_zynq/target_ebaz4205", "libconfig/target_ebaz4205", "libboard_artiq/target_ebaz4205"]
|
||||
default = ["target_zc706"]
|
||||
|
||||
[build-dependencies]
|
||||
|
@ -20,6 +21,7 @@ cslice = "0.3"
|
|||
log = "0.4"
|
||||
embedded-hal = "0.2"
|
||||
core_io = { version = "0.1", features = ["collections"] }
|
||||
crc = { version = "1.7", default-features = false }
|
||||
byteorder = { version = "1.3", default-features = false }
|
||||
void = { version = "1", default-features = false }
|
||||
futures = { version = "0.3", default-features = false, features = ["async-await"] }
|
||||
|
|
|
@ -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);
|
||||
|
@ -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) {
|
||||
let net_addresses = net_settings::get_addresses(&cfg);
|
||||
info!("network addresses: {}", net_addresses);
|
||||
|
@ -777,7 +757,6 @@ pub fn main(timer: GlobalTimer, cfg: Config) {
|
|||
moninj::start(timer, &aux_mutex, &drtio_routing_table);
|
||||
|
||||
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") {
|
||||
info!("Loading startup kernel...");
|
||||
let routing_table = drtio_routing_table.borrow();
|
||||
|
@ -804,35 +783,34 @@ 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(),
|
||||
Some(mgmt::DrtioContext(
|
||||
aux_mutex.clone(),
|
||||
drtio_routing_table.clone(),
|
||||
timer,
|
||||
)),
|
||||
);
|
||||
|
||||
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 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();
|
||||
});
|
||||
}
|
||||
|
||||
let can_restart_idle = Rc::new(Semaphore::new(1, 1));
|
||||
let restart_idle = restart_idle.clone();
|
||||
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() {
|
||||
// there is an existing connection
|
||||
|
@ -840,32 +818,58 @@ pub fn main(timer: GlobalTimer, cfg: Config) {
|
|||
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 idle_kernel = idle_kernel.clone();
|
||||
let connection = connection.clone();
|
||||
let terminate = terminate.clone();
|
||||
let can_restart_idle = can_restart_idle.clone();
|
||||
let up_destinations = up_destinations.clone();
|
||||
let aux_mutex = aux_mutex.clone();
|
||||
let routing_table = drtio_routing_table.clone();
|
||||
|
||||
// we make sure the value of terminate is 0 before we start
|
||||
let _ = terminate.try_wait();
|
||||
let _ = can_restart_idle.try_wait();
|
||||
task::spawn(async move {
|
||||
let routing_table = routing_table.borrow();
|
||||
select_biased! {
|
||||
_ = (async {
|
||||
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
|
||||
.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() => (),
|
||||
_ = terminate.async_wait().fuse() => ()
|
||||
}
|
||||
connection.signal();
|
||||
if let Some(stream) = maybe_stream {
|
||||
let _ = stream.flush().await;
|
||||
let _ = stream.abort().await;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
@ -914,7 +918,8 @@ pub fn soft_panic_main(timer: GlobalTimer, cfg: Config) -> ! {
|
|||
|
||||
Sockets::init(32);
|
||||
|
||||
mgmt::start(cfg);
|
||||
let dummy = Rc::new(Semaphore::new(0, 1));
|
||||
mgmt::start(Rc::new(cfg), dummy, None);
|
||||
|
||||
// getting eth settings disables the LED as it resets GPIO
|
||||
// need to re-enable it here
|
||||
|
|
|
@ -1,16 +1,22 @@
|
|||
use alloc::{rc::Rc, string::String, vec::Vec};
|
||||
use core::cell::RefCell;
|
||||
|
||||
use byteorder::{ByteOrder, NativeEndian};
|
||||
use crc::crc32;
|
||||
use futures::{future::poll_fn, task::Poll};
|
||||
use libasync::{smoltcp::TcpStream, task};
|
||||
use libboard_artiq::logger::{BufferLogger, LogBufferRef};
|
||||
use libboard_zynq::{slcr, smoltcp};
|
||||
use libboard_artiq::{drtio_routing::RoutingTable,
|
||||
logger::{BufferLogger, LogBufferRef}};
|
||||
use libboard_zynq::{smoltcp, timer::GlobalTimer};
|
||||
use libconfig::Config;
|
||||
use log::{self, debug, error, info, warn, LevelFilter};
|
||||
use libcortex_a9::{mutex::Mutex, semaphore::Semaphore};
|
||||
use log::{self, debug, error, info, warn};
|
||||
use num_derive::FromPrimitive;
|
||||
use num_traits::FromPrimitive;
|
||||
|
||||
use crate::proto_async::*;
|
||||
#[cfg(has_drtio)]
|
||||
use crate::rtio_mgt::drtio;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum Error {
|
||||
|
@ -18,6 +24,8 @@ pub enum Error {
|
|||
UnknownLogLevel(u8),
|
||||
UnexpectedPattern,
|
||||
UnrecognizedPacket,
|
||||
#[cfg(has_drtio)]
|
||||
DrtioError(drtio::Error),
|
||||
}
|
||||
|
||||
type Result<T> = core::result::Result<T, Error>;
|
||||
|
@ -29,6 +37,8 @@ impl core::fmt::Display for Error {
|
|||
&Error::UnknownLogLevel(lvl) => write!(f, "unknown log level {}", lvl),
|
||||
&Error::UnexpectedPattern => write!(f, "unexpected pattern"),
|
||||
&Error::UnrecognizedPacket => write!(f, "unrecognized packet"),
|
||||
#[cfg(has_drtio)]
|
||||
&Error::DrtioError(error) => write!(f, "drtio error: {}", error),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -39,6 +49,13 @@ impl From<smoltcp::Error> for Error {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(has_drtio)]
|
||||
impl From<drtio::Error> for Error {
|
||||
fn from(error: drtio::Error) -> Self {
|
||||
Error::DrtioError(error)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, FromPrimitive)]
|
||||
pub enum Request {
|
||||
GetLog = 1,
|
||||
|
@ -51,6 +68,11 @@ pub enum Request {
|
|||
ConfigRead = 12,
|
||||
ConfigWrite = 13,
|
||||
ConfigRemove = 14,
|
||||
ConfigErase = 15,
|
||||
|
||||
DebugAllocator = 8,
|
||||
|
||||
Flash = 9,
|
||||
}
|
||||
|
||||
#[repr(i8)]
|
||||
|
@ -111,30 +133,605 @@ async fn read_key(stream: &mut TcpStream) -> Result<String> {
|
|||
Ok(String::from_utf8(buffer).unwrap())
|
||||
}
|
||||
|
||||
async fn handle_connection(stream: &mut TcpStream, pull_id: Rc<RefCell<u32>>, cfg: Rc<Config>) -> Result<()> {
|
||||
if !expect(&stream, b"ARTIQ management\n").await? {
|
||||
return Err(Error::UnexpectedPattern);
|
||||
}
|
||||
stream.send_slice("e".as_bytes()).await?;
|
||||
#[cfg(has_drtio)]
|
||||
mod remote_coremgmt {
|
||||
use core_io::Read;
|
||||
use io::ProtoWrite;
|
||||
use libboard_artiq::{drtioaux_async,
|
||||
drtioaux_proto::{Packet, MASTER_PAYLOAD_MAX_SIZE}};
|
||||
|
||||
use super::*;
|
||||
|
||||
pub async fn get_log(
|
||||
stream: &mut TcpStream,
|
||||
aux_mutex: &Rc<Mutex<bool>>,
|
||||
routing_table: &RoutingTable,
|
||||
timer: GlobalTimer,
|
||||
linkno: u8,
|
||||
destination: u8,
|
||||
) -> Result<()> {
|
||||
let mut buffer = Vec::new();
|
||||
loop {
|
||||
let msg = read_i8(stream).await;
|
||||
if let Err(smoltcp::Error::Finished) = msg {
|
||||
let reply = drtio::aux_transact(
|
||||
aux_mutex,
|
||||
linkno,
|
||||
routing_table,
|
||||
&Packet::CoreMgmtGetLogRequest {
|
||||
destination,
|
||||
clear: false,
|
||||
},
|
||||
timer,
|
||||
)
|
||||
.await;
|
||||
|
||||
match reply {
|
||||
Ok(Packet::CoreMgmtGetLogReply { last, length, data }) => {
|
||||
buffer.extend(&data[..length as usize]);
|
||||
if last {
|
||||
write_i8(stream, Reply::LogContent as i8).await?;
|
||||
write_chunk(stream, &buffer).await?;
|
||||
return Ok(());
|
||||
}
|
||||
let msg: Request = FromPrimitive::from_i8(msg?).ok_or(Error::UnrecognizedPacket)?;
|
||||
match msg {
|
||||
Request::GetLog => {
|
||||
}
|
||||
Ok(packet) => {
|
||||
error!("received unexpected aux packet: {:?}", packet);
|
||||
write_i8(stream, Reply::Error as i8).await?;
|
||||
return Err(drtio::Error::UnexpectedReply.into());
|
||||
}
|
||||
Err(e) => {
|
||||
error!("aux packet error ({})", e);
|
||||
write_i8(stream, Reply::Error as i8).await?;
|
||||
return Err(e.into());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn clear_log(
|
||||
stream: &mut TcpStream,
|
||||
aux_mutex: &Rc<Mutex<bool>>,
|
||||
routing_table: &RoutingTable,
|
||||
timer: GlobalTimer,
|
||||
linkno: u8,
|
||||
destination: u8,
|
||||
) -> Result<()> {
|
||||
let reply = drtio::aux_transact(
|
||||
aux_mutex,
|
||||
linkno,
|
||||
routing_table,
|
||||
&Packet::CoreMgmtClearLogRequest { destination },
|
||||
timer,
|
||||
)
|
||||
.await;
|
||||
|
||||
match reply {
|
||||
Ok(Packet::CoreMgmtReply { succeeded: true }) => {
|
||||
write_i8(stream, Reply::Success as i8).await?;
|
||||
Ok(())
|
||||
}
|
||||
Ok(packet) => {
|
||||
error!("received unexpected aux packet: {:?}", packet);
|
||||
write_i8(stream, Reply::Error as i8).await?;
|
||||
Err(drtio::Error::UnexpectedReply.into())
|
||||
}
|
||||
Err(e) => {
|
||||
error!("aux packet error ({})", e);
|
||||
write_i8(stream, Reply::Error as i8).await?;
|
||||
Err(e.into())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn pull_log(
|
||||
stream: &mut TcpStream,
|
||||
aux_mutex: &Rc<Mutex<bool>>,
|
||||
routing_table: &RoutingTable,
|
||||
timer: GlobalTimer,
|
||||
linkno: u8,
|
||||
destination: u8,
|
||||
pull_id: &Rc<RefCell<u32>>,
|
||||
) -> Result<()> {
|
||||
let id = {
|
||||
let mut guard = pull_id.borrow_mut();
|
||||
*guard += 1;
|
||||
*guard
|
||||
};
|
||||
let mut buffer = Vec::new();
|
||||
|
||||
loop {
|
||||
if id != *pull_id.borrow() {
|
||||
// another connection attempts to pull the log...
|
||||
// abort this connection...
|
||||
break;
|
||||
}
|
||||
|
||||
let reply = drtio::aux_transact(
|
||||
aux_mutex,
|
||||
linkno,
|
||||
routing_table,
|
||||
&Packet::CoreMgmtGetLogRequest {
|
||||
destination,
|
||||
clear: true,
|
||||
},
|
||||
timer,
|
||||
)
|
||||
.await;
|
||||
|
||||
match reply {
|
||||
Ok(Packet::CoreMgmtGetLogReply { last, length, data }) => {
|
||||
buffer.extend(&data[..length as usize]);
|
||||
if last {
|
||||
write_chunk(stream, &buffer).await?;
|
||||
buffer.clear();
|
||||
task::r#yield().await;
|
||||
}
|
||||
}
|
||||
Ok(packet) => {
|
||||
error!("received unexpected aux packet: {:?}", packet);
|
||||
return Err(drtio::Error::UnexpectedReply.into());
|
||||
}
|
||||
Err(e) => {
|
||||
error!("aux packet error ({})", e);
|
||||
return Err(e.into());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn set_log_filter(
|
||||
stream: &mut TcpStream,
|
||||
aux_mutex: &Rc<Mutex<bool>>,
|
||||
routing_table: &RoutingTable,
|
||||
timer: GlobalTimer,
|
||||
linkno: u8,
|
||||
destination: u8,
|
||||
level: log::LevelFilter,
|
||||
) -> Result<()> {
|
||||
let reply = drtio::aux_transact(
|
||||
aux_mutex,
|
||||
linkno,
|
||||
routing_table,
|
||||
&Packet::CoreMgmtSetLogLevelRequest {
|
||||
destination,
|
||||
log_level: level as u8,
|
||||
},
|
||||
timer,
|
||||
)
|
||||
.await;
|
||||
|
||||
match reply {
|
||||
Ok(Packet::CoreMgmtReply { succeeded: true }) => {
|
||||
write_i8(stream, Reply::Success as i8).await?;
|
||||
Ok(())
|
||||
}
|
||||
Ok(packet) => {
|
||||
error!("received unexpected aux packet: {:?}", packet);
|
||||
write_i8(stream, Reply::Error as i8).await?;
|
||||
Err(drtio::Error::UnexpectedReply.into())
|
||||
}
|
||||
Err(e) => {
|
||||
error!("aux packet error ({})", e);
|
||||
write_i8(stream, Reply::Error as i8).await?;
|
||||
Err(e.into())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn set_uart_log_filter(
|
||||
stream: &mut TcpStream,
|
||||
aux_mutex: &Rc<Mutex<bool>>,
|
||||
routing_table: &RoutingTable,
|
||||
timer: GlobalTimer,
|
||||
linkno: u8,
|
||||
destination: u8,
|
||||
level: log::LevelFilter,
|
||||
) -> Result<()> {
|
||||
let reply = drtio::aux_transact(
|
||||
aux_mutex,
|
||||
linkno,
|
||||
routing_table,
|
||||
&Packet::CoreMgmtSetUartLogLevelRequest {
|
||||
destination,
|
||||
log_level: level as u8,
|
||||
},
|
||||
timer,
|
||||
)
|
||||
.await;
|
||||
|
||||
match reply {
|
||||
Ok(Packet::CoreMgmtReply { succeeded: true }) => {
|
||||
write_i8(stream, Reply::Success as i8).await?;
|
||||
Ok(())
|
||||
}
|
||||
Ok(packet) => {
|
||||
error!("received unexpected aux packet: {:?}", packet);
|
||||
write_i8(stream, Reply::Error as i8).await?;
|
||||
Err(drtio::Error::UnexpectedReply.into())
|
||||
}
|
||||
Err(e) => {
|
||||
error!("aux packet error ({})", e);
|
||||
write_i8(stream, Reply::Error as i8).await?;
|
||||
Err(e.into())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn config_read(
|
||||
stream: &mut TcpStream,
|
||||
aux_mutex: &Rc<Mutex<bool>>,
|
||||
routing_table: &RoutingTable,
|
||||
timer: GlobalTimer,
|
||||
linkno: u8,
|
||||
destination: u8,
|
||||
_cfg: &Rc<Config>,
|
||||
key: &String,
|
||||
) -> Result<()> {
|
||||
let mut config_key: [u8; MASTER_PAYLOAD_MAX_SIZE] = [0; MASTER_PAYLOAD_MAX_SIZE];
|
||||
let len = key.len();
|
||||
config_key[..len].clone_from_slice(key.as_bytes());
|
||||
|
||||
let mut reply = drtio::aux_transact(
|
||||
aux_mutex,
|
||||
linkno,
|
||||
routing_table,
|
||||
&Packet::CoreMgmtConfigReadRequest {
|
||||
destination: destination,
|
||||
length: len as u16,
|
||||
key: config_key,
|
||||
},
|
||||
timer,
|
||||
)
|
||||
.await;
|
||||
|
||||
let mut buffer = Vec::<u8>::new();
|
||||
loop {
|
||||
match reply {
|
||||
Ok(Packet::CoreMgmtConfigReadReply { last, length, value }) => {
|
||||
buffer.extend(&value[..length as usize]);
|
||||
|
||||
if last {
|
||||
write_i8(stream, Reply::ConfigData as i8).await?;
|
||||
write_chunk(stream, &buffer).await?;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
reply = drtio::aux_transact(
|
||||
aux_mutex,
|
||||
linkno,
|
||||
routing_table,
|
||||
&Packet::CoreMgmtConfigReadContinue {
|
||||
destination: destination,
|
||||
},
|
||||
timer,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
Ok(packet) => {
|
||||
error!("received unexpected aux packet: {:?}", packet);
|
||||
write_i8(stream, Reply::Error as i8).await?;
|
||||
return Err(drtio::Error::UnexpectedReply.into());
|
||||
}
|
||||
Err(e) => {
|
||||
error!("aux packet error ({})", e);
|
||||
write_i8(stream, Reply::Error as i8).await?;
|
||||
return Err(e.into());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn config_write(
|
||||
stream: &mut TcpStream,
|
||||
aux_mutex: &Rc<Mutex<bool>>,
|
||||
routing_table: &RoutingTable,
|
||||
timer: GlobalTimer,
|
||||
linkno: u8,
|
||||
destination: u8,
|
||||
_cfg: &Rc<Config>,
|
||||
key: &String,
|
||||
value: Vec<u8>,
|
||||
_restart_idle: &Rc<Semaphore>,
|
||||
) -> Result<()> {
|
||||
let mut message = Vec::with_capacity(key.len() + value.len() + 4 * 2);
|
||||
message.write_string(key).unwrap();
|
||||
message.write_bytes(&value).unwrap();
|
||||
|
||||
match drtio::partition_data(
|
||||
linkno,
|
||||
aux_mutex,
|
||||
routing_table,
|
||||
timer,
|
||||
&message,
|
||||
|slice, status, len: usize| Packet::CoreMgmtConfigWriteRequest {
|
||||
destination: destination,
|
||||
last: status.is_last(),
|
||||
length: len as u16,
|
||||
data: *slice,
|
||||
},
|
||||
|reply| match reply {
|
||||
Packet::CoreMgmtReply { succeeded: true } => Ok(()),
|
||||
packet => {
|
||||
error!("received unexpected aux packet: {:?}", packet);
|
||||
Err(drtio::Error::UnexpectedReply)
|
||||
}
|
||||
},
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(()) => {
|
||||
write_i8(stream, Reply::Success as i8).await?;
|
||||
Ok(())
|
||||
}
|
||||
Err(e) => {
|
||||
error!("aux packet error ({})", e);
|
||||
write_i8(stream, Reply::Error as i8).await?;
|
||||
Err(e.into())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn config_remove(
|
||||
stream: &mut TcpStream,
|
||||
aux_mutex: &Rc<Mutex<bool>>,
|
||||
routing_table: &RoutingTable,
|
||||
timer: GlobalTimer,
|
||||
linkno: u8,
|
||||
destination: u8,
|
||||
_cfg: &Rc<Config>,
|
||||
key: &String,
|
||||
_restart_idle: &Rc<Semaphore>,
|
||||
) -> Result<()> {
|
||||
let mut config_key: [u8; MASTER_PAYLOAD_MAX_SIZE] = [0; MASTER_PAYLOAD_MAX_SIZE];
|
||||
let len = key.len();
|
||||
config_key[..len].clone_from_slice(key.as_bytes());
|
||||
|
||||
let reply = drtio::aux_transact(
|
||||
aux_mutex,
|
||||
linkno,
|
||||
routing_table,
|
||||
&Packet::CoreMgmtConfigRemoveRequest {
|
||||
destination: destination,
|
||||
length: len as u16,
|
||||
key: config_key,
|
||||
},
|
||||
timer,
|
||||
)
|
||||
.await;
|
||||
|
||||
match reply {
|
||||
Ok(Packet::CoreMgmtReply { succeeded: true }) => {
|
||||
write_i8(stream, Reply::Success as i8).await?;
|
||||
Ok(())
|
||||
}
|
||||
Ok(packet) => {
|
||||
error!("received unexpected aux packet: {:?}", packet);
|
||||
write_i8(stream, Reply::Error as i8).await?;
|
||||
Err(drtio::Error::UnexpectedReply.into())
|
||||
}
|
||||
Err(e) => {
|
||||
error!("aux packet error ({})", e);
|
||||
write_i8(stream, Reply::Error as i8).await?;
|
||||
Err(e.into())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn config_erase(
|
||||
stream: &mut TcpStream,
|
||||
aux_mutex: &Rc<Mutex<bool>>,
|
||||
routing_table: &RoutingTable,
|
||||
timer: GlobalTimer,
|
||||
linkno: u8,
|
||||
destination: u8,
|
||||
) -> Result<()> {
|
||||
let reply = drtio::aux_transact(
|
||||
aux_mutex,
|
||||
linkno,
|
||||
routing_table,
|
||||
&Packet::CoreMgmtConfigEraseRequest {
|
||||
destination: destination,
|
||||
},
|
||||
timer,
|
||||
)
|
||||
.await;
|
||||
|
||||
match reply {
|
||||
Ok(Packet::CoreMgmtReply { succeeded: true }) => {
|
||||
write_i8(stream, Reply::Success as i8).await?;
|
||||
Ok(())
|
||||
}
|
||||
Ok(packet) => {
|
||||
error!("received unexpected aux packet: {:?}", packet);
|
||||
write_i8(stream, Reply::Error as i8).await?;
|
||||
Err(drtio::Error::UnexpectedReply.into())
|
||||
}
|
||||
Err(e) => {
|
||||
error!("aux packet error ({})", e);
|
||||
write_i8(stream, Reply::Error as i8).await?;
|
||||
Err(e.into())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn reboot(
|
||||
stream: &mut TcpStream,
|
||||
aux_mutex: &Rc<Mutex<bool>>,
|
||||
routing_table: &RoutingTable,
|
||||
timer: GlobalTimer,
|
||||
linkno: u8,
|
||||
destination: u8,
|
||||
) -> Result<()> {
|
||||
let reply = drtio::aux_transact(
|
||||
aux_mutex,
|
||||
linkno,
|
||||
routing_table,
|
||||
&Packet::CoreMgmtRebootRequest {
|
||||
destination: destination,
|
||||
},
|
||||
timer,
|
||||
)
|
||||
.await;
|
||||
|
||||
match reply {
|
||||
Ok(Packet::CoreMgmtReply { succeeded: true }) => {
|
||||
write_i8(stream, Reply::RebootImminent as i8).await?;
|
||||
Ok(())
|
||||
}
|
||||
Ok(packet) => {
|
||||
error!("received unexpected aux packet: {:?}", packet);
|
||||
write_i8(stream, Reply::Error as i8).await?;
|
||||
Err(drtio::Error::UnexpectedReply.into())
|
||||
}
|
||||
Err(e) => {
|
||||
error!("aux packet error ({})", e);
|
||||
write_i8(stream, Reply::Error as i8).await?;
|
||||
Err(e.into())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn debug_allocator(
|
||||
stream: &mut TcpStream,
|
||||
aux_mutex: &Rc<Mutex<bool>>,
|
||||
routing_table: &RoutingTable,
|
||||
timer: GlobalTimer,
|
||||
linkno: u8,
|
||||
destination: u8,
|
||||
) -> Result<()> {
|
||||
let reply = drtio::aux_transact(
|
||||
aux_mutex,
|
||||
linkno,
|
||||
routing_table,
|
||||
&Packet::CoreMgmtAllocatorDebugRequest {
|
||||
destination: destination,
|
||||
},
|
||||
timer,
|
||||
)
|
||||
.await;
|
||||
|
||||
match reply {
|
||||
Ok(Packet::CoreMgmtReply { succeeded: true }) => {
|
||||
write_i8(stream, Reply::Success as i8).await?;
|
||||
Ok(())
|
||||
}
|
||||
Ok(packet) => {
|
||||
error!("received unexpected aux packet: {:?}", packet);
|
||||
Err(drtio::Error::UnexpectedReply.into())
|
||||
}
|
||||
Err(e) => {
|
||||
error!("aux packet error ({})", e);
|
||||
Err(e.into())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn image_write(
|
||||
stream: &mut TcpStream,
|
||||
aux_mutex: &Rc<Mutex<bool>>,
|
||||
routing_table: &RoutingTable,
|
||||
timer: GlobalTimer,
|
||||
linkno: u8,
|
||||
destination: u8,
|
||||
_cfg: &Rc<Config>,
|
||||
image: Vec<u8>,
|
||||
) -> Result<()> {
|
||||
let mut image = &image[..];
|
||||
|
||||
let alloc_reply = drtio::aux_transact(
|
||||
aux_mutex,
|
||||
linkno,
|
||||
routing_table,
|
||||
&Packet::CoreMgmtFlashRequest {
|
||||
destination: destination,
|
||||
payload_length: image.len() as u32,
|
||||
},
|
||||
timer,
|
||||
)
|
||||
.await;
|
||||
|
||||
match alloc_reply {
|
||||
Ok(Packet::CoreMgmtReply { succeeded: true }) => Ok(()),
|
||||
Ok(packet) => {
|
||||
error!("received unexpected aux packet: {:?}", packet);
|
||||
write_i8(stream, Reply::Error as i8).await?;
|
||||
Err(drtio::Error::UnexpectedReply)
|
||||
}
|
||||
Err(e) => {
|
||||
error!("aux packet error ({})", e);
|
||||
write_i8(stream, Reply::Error as i8).await?;
|
||||
Err(drtio::Error::AuxError)
|
||||
}
|
||||
}?;
|
||||
|
||||
while !image.is_empty() {
|
||||
let mut data = [0; MASTER_PAYLOAD_MAX_SIZE];
|
||||
let len = image.read(&mut data).unwrap();
|
||||
let last = image.is_empty();
|
||||
|
||||
let reply = drtio::aux_transact(
|
||||
aux_mutex,
|
||||
linkno,
|
||||
routing_table,
|
||||
&Packet::CoreMgmtFlashAddDataRequest {
|
||||
destination: destination,
|
||||
last: last,
|
||||
length: len as u16,
|
||||
data: data,
|
||||
},
|
||||
timer,
|
||||
)
|
||||
.await;
|
||||
|
||||
match reply {
|
||||
Ok(Packet::CoreMgmtReply { succeeded: true }) if !last => Ok(()),
|
||||
Ok(Packet::CoreMgmtDropLink) if last => drtioaux_async::send(
|
||||
linkno,
|
||||
&Packet::CoreMgmtDropLinkAck {
|
||||
destination: destination,
|
||||
},
|
||||
)
|
||||
.await
|
||||
.map_err(|_| drtio::Error::AuxError),
|
||||
Ok(packet) => {
|
||||
error!("received unexpected aux packet: {:?}", packet);
|
||||
write_i8(stream, Reply::Error as i8).await?;
|
||||
Err(drtio::Error::UnexpectedReply)
|
||||
}
|
||||
Err(e) => {
|
||||
error!("aux packet error ({})", e);
|
||||
write_i8(stream, Reply::Error as i8).await?;
|
||||
Err(drtio::Error::AuxError)
|
||||
}
|
||||
}?;
|
||||
}
|
||||
|
||||
write_i8(stream, Reply::RebootImminent as i8).await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
mod local_coremgmt {
|
||||
use libboard_zynq::slcr;
|
||||
|
||||
use super::*;
|
||||
|
||||
pub async fn get_log(stream: &mut TcpStream) -> Result<()> {
|
||||
let buffer = get_logger_buffer().await.extract().as_bytes().to_vec();
|
||||
write_i8(stream, Reply::LogContent as i8).await?;
|
||||
write_chunk(stream, &buffer).await?;
|
||||
Ok(())
|
||||
}
|
||||
Request::ClearLog => {
|
||||
|
||||
pub async fn clear_log(stream: &mut TcpStream) -> Result<()> {
|
||||
let mut buffer = get_logger_buffer().await;
|
||||
buffer.clear();
|
||||
write_i8(stream, Reply::Success as i8).await?;
|
||||
Ok(())
|
||||
}
|
||||
Request::PullLog => {
|
||||
|
||||
pub async fn pull_log(stream: &mut TcpStream, pull_id: &Rc<RefCell<u32>>) -> Result<()> {
|
||||
let id = {
|
||||
let mut guard = pull_id.borrow_mut();
|
||||
*guard += 1;
|
||||
|
@ -151,32 +748,34 @@ async fn handle_connection(stream: &mut TcpStream, pull_id: Rc<RefCell<u32>>, cf
|
|||
buffer.clear();
|
||||
core::mem::drop(buffer);
|
||||
write_chunk(stream, &bytes).await?;
|
||||
if log::max_level() == LevelFilter::Trace {
|
||||
if log::max_level() == log::LevelFilter::Trace {
|
||||
// temporarily discard all trace level log
|
||||
let logger = unsafe { BufferLogger::get_logger().as_mut().unwrap() };
|
||||
logger.set_buffer_log_level(LevelFilter::Debug);
|
||||
logger.set_buffer_log_level(log::LevelFilter::Debug);
|
||||
stream.flush().await?;
|
||||
logger.set_buffer_log_level(LevelFilter::Trace);
|
||||
logger.set_buffer_log_level(log::LevelFilter::Trace);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
Request::SetLogFilter => {
|
||||
let lvl = read_log_level_filter(stream).await?;
|
||||
|
||||
pub async fn set_log_filter(stream: &mut TcpStream, lvl: log::LevelFilter) -> Result<()> {
|
||||
info!("Changing log level to {}", lvl);
|
||||
log::set_max_level(lvl);
|
||||
write_i8(stream, Reply::Success as i8).await?;
|
||||
Ok(())
|
||||
}
|
||||
Request::SetUartLogFilter => {
|
||||
let lvl = read_log_level_filter(stream).await?;
|
||||
|
||||
pub async fn set_uart_log_filter(stream: &mut TcpStream, lvl: log::LevelFilter) -> Result<()> {
|
||||
info!("Changing UART log level to {}", lvl);
|
||||
unsafe {
|
||||
BufferLogger::get_logger().as_ref().unwrap().set_uart_log_level(lvl);
|
||||
}
|
||||
write_i8(stream, Reply::Success as i8).await?;
|
||||
Ok(())
|
||||
}
|
||||
Request::ConfigRead => {
|
||||
let key = read_key(stream).await?;
|
||||
debug!("read key: {}", key);
|
||||
|
||||
pub async fn config_read(stream: &mut TcpStream, cfg: &Rc<Config>, key: &String) -> Result<()> {
|
||||
let value = cfg.read(&key);
|
||||
if let Ok(value) = value {
|
||||
debug!("got value");
|
||||
|
@ -186,10 +785,165 @@ async fn handle_connection(stream: &mut TcpStream, pull_id: Rc<RefCell<u32>>, cf
|
|||
warn!("read error: no such key");
|
||||
write_i8(stream, Reply::Error as i8).await?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn config_write(
|
||||
stream: &mut TcpStream,
|
||||
cfg: &Rc<Config>,
|
||||
key: &String,
|
||||
value: Vec<u8>,
|
||||
restart_idle: &Rc<Semaphore>,
|
||||
) -> Result<()> {
|
||||
let value = cfg.write(&key, value);
|
||||
if value.is_ok() {
|
||||
debug!("write success");
|
||||
if key == "idle_kernel" {
|
||||
restart_idle.signal();
|
||||
}
|
||||
write_i8(stream, Reply::Success as i8).await?;
|
||||
} else {
|
||||
// this is an error because we do not expect write to fail
|
||||
error!("failed to write: {:?}", value);
|
||||
write_i8(stream, Reply::Error as i8).await?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn config_remove(
|
||||
stream: &mut TcpStream,
|
||||
cfg: &Rc<Config>,
|
||||
key: &String,
|
||||
restart_idle: &Rc<Semaphore>,
|
||||
) -> Result<()> {
|
||||
debug!("erase key: {}", key);
|
||||
let value = cfg.remove(&key);
|
||||
if value.is_ok() {
|
||||
debug!("erase success");
|
||||
if key == "idle_kernel" {
|
||||
restart_idle.signal();
|
||||
}
|
||||
write_i8(stream, Reply::Success as i8).await?;
|
||||
} else {
|
||||
warn!("erase failed");
|
||||
write_i8(stream, Reply::Error as i8).await?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn config_erase(stream: &mut TcpStream) -> Result<()> {
|
||||
error!("zynq device does not support config erase");
|
||||
write_i8(stream, Reply::Error as i8).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn reboot(stream: &mut TcpStream) -> Result<()> {
|
||||
info!("rebooting");
|
||||
write_i8(stream, Reply::RebootImminent as i8).await?;
|
||||
stream.flush().await?;
|
||||
slcr::reboot();
|
||||
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
pub async fn debug_allocator(_stream: &mut TcpStream) -> Result<()> {
|
||||
error!("zynq device does not support allocator debug print");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn image_write(stream: &mut TcpStream, cfg: &Rc<Config>, image: Vec<u8>) -> Result<()> {
|
||||
let mut image = image.clone();
|
||||
let image_ref = &image[..];
|
||||
let bin_len = image.len() - 4;
|
||||
|
||||
let (image_ref, expected_crc) = {
|
||||
let (image_ref, crc_slice) = image_ref.split_at(bin_len);
|
||||
(image_ref, NativeEndian::read_u32(crc_slice))
|
||||
};
|
||||
|
||||
let actual_crc = crc32::checksum_ieee(image_ref);
|
||||
|
||||
if actual_crc == expected_crc {
|
||||
info!("CRC passed. Writing boot image to SD card...");
|
||||
image.truncate(bin_len);
|
||||
cfg.write("boot", image).expect("failed to write boot image");
|
||||
reboot(stream).await?;
|
||||
} else {
|
||||
error!(
|
||||
"CRC failed, images have not been written to flash.\n(actual {:08x}, expected {:08x})",
|
||||
actual_crc, expected_crc
|
||||
);
|
||||
write_i8(stream, Reply::Error as i8).await?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(has_drtio)]
|
||||
macro_rules! process {
|
||||
($stream: ident, $drtio_context:ident, $destination:expr, $func:ident $(, $param:expr)*) => {{
|
||||
if $destination == 0 {
|
||||
local_coremgmt::$func($stream, $($param, )*).await
|
||||
} else if let Some(DrtioContext(ref aux_mutex, ref routing_table, timer)) = $drtio_context {
|
||||
let routing_table = routing_table.borrow();
|
||||
let linkno = routing_table.0[$destination as usize][0] - 1 as u8;
|
||||
remote_coremgmt::$func($stream, &aux_mutex, &routing_table, timer, linkno, $destination, $($param, )*).await
|
||||
} else {
|
||||
error!("coremgmt-over-drtio not supported for panicked device, please reboot");
|
||||
write_i8($stream, Reply::Error as i8).await?;
|
||||
Err(drtio::Error::LinkDown.into())
|
||||
}
|
||||
}}
|
||||
}
|
||||
|
||||
#[cfg(not(has_drtio))]
|
||||
macro_rules! process {
|
||||
($stream: ident, $drtio_context:ident, $destination:expr, $func:ident $(, $param:expr)*) => {{
|
||||
local_coremgmt::$func($stream, $($param, )*).await
|
||||
}}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct DrtioContext(pub Rc<Mutex<bool>>, pub Rc<RefCell<RoutingTable>>, pub GlobalTimer);
|
||||
|
||||
async fn handle_connection(
|
||||
stream: &mut TcpStream,
|
||||
pull_id: Rc<RefCell<u32>>,
|
||||
cfg: Rc<Config>,
|
||||
restart_idle: Rc<Semaphore>,
|
||||
_drtio_context: Option<DrtioContext>,
|
||||
) -> Result<()> {
|
||||
if !expect(&stream, b"ARTIQ management\n").await? {
|
||||
return Err(Error::UnexpectedPattern);
|
||||
}
|
||||
|
||||
let _destination: u8 = read_i8(stream).await? as u8;
|
||||
stream.send_slice("e".as_bytes()).await?;
|
||||
|
||||
loop {
|
||||
let msg = read_i8(stream).await;
|
||||
if let Err(smoltcp::Error::Finished) = msg {
|
||||
return Ok(());
|
||||
}
|
||||
let msg: Request = FromPrimitive::from_i8(msg?).ok_or(Error::UnrecognizedPacket)?;
|
||||
match msg {
|
||||
Request::GetLog => process!(stream, _drtio_context, _destination, get_log),
|
||||
Request::ClearLog => process!(stream, _drtio_context, _destination, clear_log),
|
||||
Request::PullLog => process!(stream, _drtio_context, _destination, pull_log, &pull_id),
|
||||
Request::SetLogFilter => {
|
||||
let lvl = read_log_level_filter(stream).await?;
|
||||
process!(stream, _drtio_context, _destination, set_log_filter, lvl)
|
||||
}
|
||||
Request::SetUartLogFilter => {
|
||||
let lvl = read_log_level_filter(stream).await?;
|
||||
process!(stream, _drtio_context, _destination, set_uart_log_filter, lvl)
|
||||
}
|
||||
Request::ConfigRead => {
|
||||
let key = read_key(stream).await?;
|
||||
process!(stream, _drtio_context, _destination, config_read, &cfg, &key)
|
||||
}
|
||||
Request::ConfigWrite => {
|
||||
let key = read_key(stream).await?;
|
||||
debug!("write key: {}", key);
|
||||
let len = read_i32(stream).await?;
|
||||
let len = if len <= 0 { 0 } else { len as usize };
|
||||
let mut buffer = Vec::with_capacity(len);
|
||||
|
@ -197,49 +951,67 @@ async fn handle_connection(stream: &mut TcpStream, pull_id: Rc<RefCell<u32>>, cf
|
|||
buffer.set_len(len);
|
||||
}
|
||||
read_chunk(stream, &mut buffer).await?;
|
||||
let value = cfg.write(&key, buffer);
|
||||
if value.is_ok() {
|
||||
debug!("write success");
|
||||
write_i8(stream, Reply::Success as i8).await?;
|
||||
} else {
|
||||
// this is an error because we do not expect write to fail
|
||||
error!("failed to write: {:?}", value);
|
||||
write_i8(stream, Reply::Error as i8).await?;
|
||||
}
|
||||
process!(
|
||||
stream,
|
||||
_drtio_context,
|
||||
_destination,
|
||||
config_write,
|
||||
&cfg,
|
||||
&key,
|
||||
buffer,
|
||||
&restart_idle
|
||||
)
|
||||
}
|
||||
Request::ConfigRemove => {
|
||||
let key = read_key(stream).await?;
|
||||
debug!("erase key: {}", key);
|
||||
let value = cfg.remove(&key);
|
||||
if value.is_ok() {
|
||||
debug!("erase success");
|
||||
write_i8(stream, Reply::Success as i8).await?;
|
||||
} else {
|
||||
warn!("erase failed");
|
||||
write_i8(stream, Reply::Error as i8).await?;
|
||||
}
|
||||
process!(
|
||||
stream,
|
||||
_drtio_context,
|
||||
_destination,
|
||||
config_remove,
|
||||
&cfg,
|
||||
&key,
|
||||
&restart_idle
|
||||
)
|
||||
}
|
||||
Request::Reboot => {
|
||||
info!("rebooting");
|
||||
write_i8(stream, Reply::RebootImminent as i8).await?;
|
||||
stream.flush().await?;
|
||||
slcr::reboot();
|
||||
process!(stream, _drtio_context, _destination, reboot)
|
||||
}
|
||||
Request::ConfigErase => {
|
||||
process!(stream, _drtio_context, _destination, config_erase)
|
||||
}
|
||||
Request::DebugAllocator => {
|
||||
process!(stream, _drtio_context, _destination, debug_allocator)
|
||||
}
|
||||
Request::Flash => {
|
||||
let len = read_i32(stream).await?;
|
||||
if len <= 0 {
|
||||
write_i8(stream, Reply::Error as i8).await?;
|
||||
return Err(Error::UnexpectedPattern);
|
||||
}
|
||||
let mut buffer = Vec::with_capacity(len as usize);
|
||||
unsafe {
|
||||
buffer.set_len(len as usize);
|
||||
}
|
||||
read_chunk(stream, &mut buffer).await?;
|
||||
process!(stream, _drtio_context, _destination, image_write, &cfg, buffer)
|
||||
}
|
||||
}?;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn start(cfg: Config) {
|
||||
pub fn start(cfg: Rc<Config>, restart_idle: Rc<Semaphore>, drtio_context: Option<DrtioContext>) {
|
||||
task::spawn(async move {
|
||||
let pull_id = Rc::new(RefCell::new(0u32));
|
||||
let cfg = Rc::new(cfg);
|
||||
loop {
|
||||
let mut stream = TcpStream::accept(1380, 2048, 2048).await.unwrap();
|
||||
let pull_id = pull_id.clone();
|
||||
let cfg = cfg.clone();
|
||||
let restart_idle = restart_idle.clone();
|
||||
let drtio_context = drtio_context.clone();
|
||||
task::spawn(async move {
|
||||
info!("received connection");
|
||||
let _ = handle_connection(&mut stream, pull_id, cfg)
|
||||
let _ = handle_connection(&mut stream, pull_id, cfg, restart_idle, drtio_context)
|
||||
.await
|
||||
.map_err(|e| warn!("connection terminated: {:?}", e));
|
||||
let _ = stream.flush().await;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
#[cfg(not(feature = "target_ebaz4205"))]
|
||||
use embedded_hal::blocking::delay::DelayMs;
|
||||
#[cfg(has_si5324)]
|
||||
use ksupport::i2c;
|
||||
#[cfg(not(feature = "target_ebaz4205"))]
|
||||
use libboard_artiq::pl;
|
||||
#[cfg(has_si5324)]
|
||||
use libboard_artiq::si5324;
|
||||
|
@ -11,6 +13,8 @@ use libboard_zynq::i2c::I2c;
|
|||
use libboard_zynq::timer::GlobalTimer;
|
||||
use libconfig::Config;
|
||||
use log::{info, warn};
|
||||
#[cfg(feature = "target_ebaz4205")]
|
||||
use {libboard_zynq::slcr, libregister::RegisterRW};
|
||||
|
||||
#[derive(Debug, PartialEq, Copy, Clone)]
|
||||
#[allow(non_camel_case_types)]
|
||||
|
@ -69,7 +73,7 @@ fn get_rtio_clock_cfg(cfg: &Config) -> RtioClock {
|
|||
res
|
||||
}
|
||||
|
||||
#[cfg(not(has_drtio))]
|
||||
#[cfg(not(any(has_drtio, feature = "target_ebaz4205")))]
|
||||
fn init_rtio(timer: &mut GlobalTimer) {
|
||||
info!("Switching SYS clocks...");
|
||||
unsafe {
|
||||
|
@ -406,6 +410,38 @@ fn get_si549_setting(clk: RtioClock) -> si549::FrequencySetting {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "target_ebaz4205")]
|
||||
fn set_fclk0_freq(clk: RtioClock, cfg: &Config) {
|
||||
let io_pll_freq: u32 = 1_000_000_000; // Hardcoded in zynq-rs
|
||||
let mut target_freq = 0;
|
||||
let mut divisor0 = 1u8;
|
||||
|
||||
match clk {
|
||||
RtioClock::Int_100 => {
|
||||
target_freq = 100_000_000;
|
||||
divisor0 = 10;
|
||||
}
|
||||
RtioClock::Int_125 => {
|
||||
target_freq = 125_000_000;
|
||||
divisor0 = 8;
|
||||
}
|
||||
_ => {
|
||||
warn!("Unsupported RTIO Clock: '{:?}'", clk);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
slcr::RegisterBlock::unlocked(|slcr| {
|
||||
slcr.fpga0_clk_ctrl.modify(|_, w| w.divisor0(divisor0));
|
||||
});
|
||||
|
||||
info!(
|
||||
"Set FCLK0 to {:.2} MHz (target: {} MHz).",
|
||||
io_pll_freq as f64 / divisor0 as f64,
|
||||
target_freq / 1_000_000
|
||||
);
|
||||
}
|
||||
|
||||
pub fn init(timer: &mut GlobalTimer, cfg: &Config) {
|
||||
let clk = get_rtio_clock_cfg(cfg);
|
||||
#[cfg(has_si5324)]
|
||||
|
@ -429,9 +465,19 @@ pub fn init(timer: &mut GlobalTimer, cfg: &Config) {
|
|||
#[cfg(has_drtio)]
|
||||
init_drtio(timer);
|
||||
|
||||
#[cfg(not(has_drtio))]
|
||||
#[cfg(not(any(has_drtio, feature = "target_ebaz4205")))]
|
||||
init_rtio(timer);
|
||||
|
||||
#[cfg(feature = "target_ebaz4205")]
|
||||
{
|
||||
match clk {
|
||||
RtioClock::Int_100 | RtioClock::Int_125 => {
|
||||
set_fclk0_freq(clk, cfg);
|
||||
}
|
||||
_ => {} // Not set for external clocks
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(has_si549, has_wrpll))]
|
||||
{
|
||||
// SYS CLK switch will reset CSRs that are used by WRPLL
|
||||
|
|
|
@ -13,9 +13,13 @@ pub mod drtio {
|
|||
use core::fmt;
|
||||
|
||||
use embedded_hal::blocking::delay::DelayMs;
|
||||
#[cfg(has_drtio_eem)]
|
||||
use embedded_hal::blocking::delay::DelayUs;
|
||||
use ksupport::{resolve_channel_name, ASYNC_ERROR_BUSY, ASYNC_ERROR_COLLISION, ASYNC_ERROR_SEQUENCE_ERROR,
|
||||
SEEN_ASYNC_ERRORS};
|
||||
use libasync::{delay, task};
|
||||
#[cfg(has_drtio_eem)]
|
||||
use libboard_artiq::drtio_eem;
|
||||
use libboard_artiq::{drtioaux::Error as DrtioError,
|
||||
drtioaux_async,
|
||||
drtioaux_async::Packet,
|
||||
|
@ -26,6 +30,10 @@ pub mod drtio {
|
|||
use super::*;
|
||||
use crate::{analyzer::remote_analyzer::RemoteBuffer, rtio_dma::remote_dma, subkernel};
|
||||
|
||||
#[cfg(has_drtio_eem)]
|
||||
const DRTIO_EEM_LINKNOS: core::ops::Range<usize> =
|
||||
(csr::DRTIO.len() - csr::CONFIG_EEM_DRTIO_COUNT as usize)..csr::DRTIO.len();
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||
pub enum Error {
|
||||
Timeout,
|
||||
|
@ -76,8 +84,18 @@ pub mod drtio {
|
|||
});
|
||||
}
|
||||
|
||||
async fn link_rx_up(linkno: u8) -> bool {
|
||||
async fn link_rx_up(linkno: u8, _timer: &mut GlobalTimer) -> bool {
|
||||
let linkno = linkno as usize;
|
||||
#[cfg(has_drtio_eem)]
|
||||
if DRTIO_EEM_LINKNOS.contains(&linkno) {
|
||||
let eem_trx_no = linkno - DRTIO_EEM_LINKNOS.start;
|
||||
unsafe {
|
||||
csr::eem_transceiver::transceiver_sel_write(eem_trx_no as u8);
|
||||
csr::eem_transceiver::comma_align_reset_write(1);
|
||||
}
|
||||
_timer.delay_us(100);
|
||||
return unsafe { csr::eem_transceiver::comma_read() == 1 };
|
||||
}
|
||||
unsafe { (csr::DRTIO[linkno].rx_up_read)() == 1 }
|
||||
}
|
||||
|
||||
|
@ -152,8 +170,8 @@ pub mod drtio {
|
|||
}
|
||||
}
|
||||
|
||||
async fn recv_aux_timeout(linkno: u8, timeout: u64, timer: GlobalTimer) -> Result<Packet, Error> {
|
||||
if !link_rx_up(linkno).await {
|
||||
async fn recv_aux_timeout(linkno: u8, timeout: u64, mut timer: GlobalTimer) -> Result<Packet, Error> {
|
||||
if !link_rx_up(linkno, &mut timer).await {
|
||||
return Err(Error::LinkDown);
|
||||
}
|
||||
match drtioaux_async::recv_timeout(linkno, Some(timeout), timer).await {
|
||||
|
@ -168,9 +186,9 @@ pub mod drtio {
|
|||
linkno: u8,
|
||||
routing_table: &RoutingTable,
|
||||
request: &Packet,
|
||||
timer: GlobalTimer,
|
||||
mut timer: GlobalTimer,
|
||||
) -> Result<Packet, Error> {
|
||||
if !link_rx_up(linkno).await {
|
||||
if !link_rx_up(linkno, &mut timer).await {
|
||||
return Err(Error::LinkDown);
|
||||
}
|
||||
let _lock = aux_mutex.async_lock().await;
|
||||
|
@ -194,11 +212,11 @@ pub mod drtio {
|
|||
aux_mutex: &Rc<Mutex<bool>>,
|
||||
linkno: u8,
|
||||
routing_table: &RoutingTable,
|
||||
timer: GlobalTimer,
|
||||
mut timer: GlobalTimer,
|
||||
) -> u32 {
|
||||
let mut count = 0;
|
||||
loop {
|
||||
if !link_rx_up(linkno).await {
|
||||
if !link_rx_up(linkno, &mut timer).await {
|
||||
return 0;
|
||||
}
|
||||
count += 1;
|
||||
|
@ -462,7 +480,7 @@ pub mod drtio {
|
|||
aux_mutex: &Rc<Mutex<bool>>,
|
||||
routing_table: &RoutingTable,
|
||||
up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>,
|
||||
timer: GlobalTimer,
|
||||
mut timer: GlobalTimer,
|
||||
) {
|
||||
let mut up_links = [false; csr::DRTIO.len()];
|
||||
loop {
|
||||
|
@ -470,16 +488,35 @@ pub mod drtio {
|
|||
let linkno = linkno as u8;
|
||||
if up_links[linkno as usize] {
|
||||
/* link was previously up */
|
||||
if link_rx_up(linkno).await {
|
||||
if link_rx_up(linkno, &mut timer).await {
|
||||
process_unsolicited_aux(aux_mutex, linkno, routing_table).await;
|
||||
process_local_errors(linkno).await;
|
||||
} else {
|
||||
info!("[LINK#{}] link is down", linkno);
|
||||
up_links[linkno as usize] = false;
|
||||
|
||||
#[cfg(has_drtio_eem)]
|
||||
if DRTIO_EEM_LINKNOS.contains(&(linkno as usize)) {
|
||||
unsafe {
|
||||
csr::eem_transceiver::rx_ready_write(0);
|
||||
}
|
||||
while !matches!(drtioaux_async::recv(linkno).await, Ok(None)) {}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* link was previously down */
|
||||
if link_rx_up(linkno).await {
|
||||
#[cfg(has_drtio_eem)]
|
||||
if DRTIO_EEM_LINKNOS.contains(&(linkno as usize)) {
|
||||
let eem_trx_no = linkno - DRTIO_EEM_LINKNOS.start as u8;
|
||||
if !unsafe { drtio_eem::align_wordslip(&mut timer, eem_trx_no) } {
|
||||
continue;
|
||||
}
|
||||
unsafe {
|
||||
csr::eem_transceiver::rx_ready_write(1);
|
||||
}
|
||||
}
|
||||
|
||||
if link_rx_up(linkno, &mut timer).await {
|
||||
info!("[LINK#{}] link RX became up, pinging", linkno);
|
||||
let ping_count = ping_remote(aux_mutex, linkno, routing_table, timer).await;
|
||||
if ping_count > 0 {
|
||||
|
@ -523,7 +560,7 @@ pub mod drtio {
|
|||
|
||||
for linkno in 0..csr::DRTIO.len() {
|
||||
let linkno = linkno as u8;
|
||||
if task::block_on(link_rx_up(linkno)) {
|
||||
if task::block_on(link_rx_up(linkno, &mut timer)) {
|
||||
let reply = task::block_on(aux_transact(
|
||||
&aux_mutex,
|
||||
linkno,
|
||||
|
@ -540,7 +577,7 @@ pub mod drtio {
|
|||
}
|
||||
}
|
||||
|
||||
async fn partition_data<PacketF, HandlerF>(
|
||||
pub async fn partition_data<PacketF, HandlerF>(
|
||||
linkno: u8,
|
||||
aux_mutex: &Rc<Mutex<bool>>,
|
||||
routing_table: &RoutingTable,
|
||||
|
@ -792,6 +829,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(
|
||||
|
@ -803,6 +841,7 @@ pub mod drtio {
|
|||
source: 0,
|
||||
destination: destination,
|
||||
run: run,
|
||||
timestamp,
|
||||
},
|
||||
timer,
|
||||
)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -15,7 +15,9 @@ build_zynq = { path = "../libbuild_zynq" }
|
|||
|
||||
[dependencies]
|
||||
log = { version = "0.4", default-features = false }
|
||||
byteorder = { version = "1.3", default-features = false }
|
||||
core_io = { version = "0.1", features = ["collections"] }
|
||||
crc = { version = "1.7", default-features = false }
|
||||
cslice = "0.3"
|
||||
embedded-hal = "0.2"
|
||||
|
||||
|
|
|
@ -4,7 +4,9 @@
|
|||
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
extern crate byteorder;
|
||||
extern crate core_io;
|
||||
extern crate crc;
|
||||
extern crate cslice;
|
||||
extern crate embedded_hal;
|
||||
|
||||
|
@ -38,16 +40,18 @@ use libboard_artiq::{drtio_routing, drtioaux,
|
|||
pl::csr};
|
||||
#[cfg(feature = "target_kasli_soc")]
|
||||
use libboard_zynq::error_led::ErrorLED;
|
||||
use libboard_zynq::{i2c::I2c, print, println, time::Milliseconds, timer::GlobalTimer};
|
||||
use libboard_zynq::{i2c::I2c, print, println, slcr, 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};
|
||||
use mgmt::Manager as CoreManager;
|
||||
use routing::Router;
|
||||
use subkernel::Manager as KernelManager;
|
||||
|
||||
mod analyzer;
|
||||
mod dma;
|
||||
mod mgmt;
|
||||
mod repeater;
|
||||
mod routing;
|
||||
mod subkernel;
|
||||
|
@ -149,6 +153,7 @@ fn process_aux_packet(
|
|||
dma_manager: &mut DmaManager,
|
||||
analyzer: &mut Analyzer,
|
||||
kernel_manager: &mut KernelManager,
|
||||
core_manager: &mut CoreManager,
|
||||
router: &mut Router,
|
||||
) -> Result<(), drtioaux::Error> {
|
||||
// In the code below, *_chan_sel_write takes an u8 if there are fewer than 256 channels,
|
||||
|
@ -826,6 +831,7 @@ fn process_aux_packet(
|
|||
destination: _destination,
|
||||
id,
|
||||
run,
|
||||
timestamp,
|
||||
} => {
|
||||
forward!(
|
||||
router,
|
||||
|
@ -844,7 +850,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(
|
||||
|
@ -1010,6 +1016,335 @@ fn process_aux_packet(
|
|||
}
|
||||
Ok(())
|
||||
}
|
||||
drtioaux::Packet::CoreMgmtGetLogRequest {
|
||||
destination: _destination,
|
||||
clear,
|
||||
} => {
|
||||
forward!(
|
||||
router,
|
||||
_routing_table,
|
||||
_destination,
|
||||
*rank,
|
||||
*self_destination,
|
||||
_repeaters,
|
||||
&packet,
|
||||
timer
|
||||
);
|
||||
let mut data_slice = [0; SAT_PAYLOAD_MAX_SIZE];
|
||||
let meta = core_manager.log_get_slice(&mut data_slice, clear);
|
||||
drtioaux::send(
|
||||
0,
|
||||
&drtioaux::Packet::CoreMgmtGetLogReply {
|
||||
last: meta.status.is_last(),
|
||||
length: meta.len as u16,
|
||||
data: data_slice,
|
||||
},
|
||||
)
|
||||
}
|
||||
drtioaux::Packet::CoreMgmtClearLogRequest {
|
||||
destination: _destination,
|
||||
} => {
|
||||
forward!(
|
||||
router,
|
||||
_routing_table,
|
||||
_destination,
|
||||
*rank,
|
||||
*self_destination,
|
||||
_repeaters,
|
||||
&packet,
|
||||
timer
|
||||
);
|
||||
mgmt::clear_log();
|
||||
drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded: true })
|
||||
}
|
||||
drtioaux::Packet::CoreMgmtSetLogLevelRequest {
|
||||
destination: _destination,
|
||||
log_level,
|
||||
} => {
|
||||
forward!(
|
||||
router,
|
||||
_routing_table,
|
||||
_destination,
|
||||
*rank,
|
||||
*self_destination,
|
||||
_repeaters,
|
||||
&packet,
|
||||
timer
|
||||
);
|
||||
|
||||
if let Ok(level_filter) = mgmt::byte_to_level_filter(log_level) {
|
||||
info!("Changing log level to {}", level_filter);
|
||||
log::set_max_level(level_filter);
|
||||
drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded: true })
|
||||
} else {
|
||||
drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded: false })
|
||||
}
|
||||
}
|
||||
drtioaux::Packet::CoreMgmtSetUartLogLevelRequest {
|
||||
destination: _destination,
|
||||
log_level,
|
||||
} => {
|
||||
forward!(
|
||||
router,
|
||||
_routing_table,
|
||||
_destination,
|
||||
*rank,
|
||||
*self_destination,
|
||||
_repeaters,
|
||||
&packet,
|
||||
timer
|
||||
);
|
||||
|
||||
if let Ok(level_filter) = mgmt::byte_to_level_filter(log_level) {
|
||||
info!("Changing UART log level to {}", level_filter);
|
||||
unsafe {
|
||||
logger::BufferLogger::get_logger()
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.set_uart_log_level(level_filter);
|
||||
}
|
||||
drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded: true })
|
||||
} else {
|
||||
drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded: false })
|
||||
}
|
||||
}
|
||||
drtioaux::Packet::CoreMgmtConfigReadRequest {
|
||||
destination: _destination,
|
||||
length,
|
||||
key,
|
||||
} => {
|
||||
forward!(
|
||||
router,
|
||||
_routing_table,
|
||||
_destination,
|
||||
*rank,
|
||||
*self_destination,
|
||||
_repeaters,
|
||||
&packet,
|
||||
timer
|
||||
);
|
||||
|
||||
let mut value_slice = [0; SAT_PAYLOAD_MAX_SIZE];
|
||||
|
||||
let key_slice = &key[..length as usize];
|
||||
if !key_slice.is_ascii() {
|
||||
error!("invalid key");
|
||||
drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded: false })
|
||||
} else {
|
||||
let key = core::str::from_utf8(key_slice).unwrap();
|
||||
if core_manager.fetch_config_value(key).is_ok() {
|
||||
let meta = core_manager.get_config_value_slice(&mut value_slice);
|
||||
drtioaux::send(
|
||||
0,
|
||||
&drtioaux::Packet::CoreMgmtConfigReadReply {
|
||||
last: meta.status.is_last(),
|
||||
length: meta.len as u16,
|
||||
value: value_slice,
|
||||
},
|
||||
)
|
||||
} else {
|
||||
drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded: false })
|
||||
}
|
||||
}
|
||||
}
|
||||
drtioaux::Packet::CoreMgmtConfigReadContinue {
|
||||
destination: _destination,
|
||||
} => {
|
||||
forward!(
|
||||
router,
|
||||
_routing_table,
|
||||
_destination,
|
||||
*rank,
|
||||
*self_destination,
|
||||
_repeaters,
|
||||
&packet,
|
||||
timer
|
||||
);
|
||||
|
||||
let mut value_slice = [0; SAT_PAYLOAD_MAX_SIZE];
|
||||
let meta = core_manager.get_config_value_slice(&mut value_slice);
|
||||
drtioaux::send(
|
||||
0,
|
||||
&drtioaux::Packet::CoreMgmtConfigReadReply {
|
||||
last: meta.status.is_last(),
|
||||
length: meta.len as u16,
|
||||
value: value_slice,
|
||||
},
|
||||
)
|
||||
}
|
||||
drtioaux::Packet::CoreMgmtConfigWriteRequest {
|
||||
destination: _destination,
|
||||
last,
|
||||
length,
|
||||
data,
|
||||
} => {
|
||||
forward!(
|
||||
router,
|
||||
_routing_table,
|
||||
_destination,
|
||||
*rank,
|
||||
*self_destination,
|
||||
_repeaters,
|
||||
&packet,
|
||||
timer
|
||||
);
|
||||
|
||||
core_manager.add_config_data(&data, length as usize);
|
||||
|
||||
let mut succeeded = true;
|
||||
if last {
|
||||
succeeded = core_manager.write_config().is_ok();
|
||||
core_manager.clear_config_data();
|
||||
}
|
||||
|
||||
drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded })
|
||||
}
|
||||
drtioaux::Packet::CoreMgmtConfigRemoveRequest {
|
||||
destination: _destination,
|
||||
length,
|
||||
key,
|
||||
} => {
|
||||
forward!(
|
||||
router,
|
||||
_routing_table,
|
||||
_destination,
|
||||
*rank,
|
||||
*self_destination,
|
||||
_repeaters,
|
||||
&packet,
|
||||
timer
|
||||
);
|
||||
|
||||
let key_slice = &key[..length as usize];
|
||||
if !key_slice.is_ascii() {
|
||||
error!("invalid key");
|
||||
drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded: false })
|
||||
} else {
|
||||
let key = core::str::from_utf8(key_slice).unwrap();
|
||||
let succeeded = core_manager.remove_config(key).is_ok();
|
||||
drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded })
|
||||
}
|
||||
}
|
||||
drtioaux::Packet::CoreMgmtConfigEraseRequest {
|
||||
destination: _destination,
|
||||
} => {
|
||||
forward!(
|
||||
router,
|
||||
_routing_table,
|
||||
_destination,
|
||||
*rank,
|
||||
*self_destination,
|
||||
_repeaters,
|
||||
&packet,
|
||||
timer
|
||||
);
|
||||
|
||||
error!("config erase not supported on zynq device");
|
||||
drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded: false })
|
||||
}
|
||||
drtioaux::Packet::CoreMgmtRebootRequest {
|
||||
destination: _destination,
|
||||
} => {
|
||||
info!("received reboot request");
|
||||
forward!(
|
||||
router,
|
||||
_routing_table,
|
||||
_destination,
|
||||
*rank,
|
||||
*self_destination,
|
||||
_repeaters,
|
||||
&packet,
|
||||
timer
|
||||
);
|
||||
|
||||
drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded: true })?;
|
||||
info!("reboot imminent");
|
||||
slcr::reboot();
|
||||
|
||||
unreachable!();
|
||||
}
|
||||
drtioaux::Packet::CoreMgmtAllocatorDebugRequest {
|
||||
destination: _destination,
|
||||
} => {
|
||||
forward!(
|
||||
router,
|
||||
_routing_table,
|
||||
_destination,
|
||||
*rank,
|
||||
*self_destination,
|
||||
_repeaters,
|
||||
&packet,
|
||||
timer
|
||||
);
|
||||
|
||||
error!("debug allocator not supported on zynq device");
|
||||
drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded: false })
|
||||
}
|
||||
drtioaux::Packet::CoreMgmtFlashRequest {
|
||||
destination: _destination,
|
||||
payload_length,
|
||||
} => {
|
||||
forward!(
|
||||
router,
|
||||
_routing_table,
|
||||
_destination,
|
||||
*rank,
|
||||
*self_destination,
|
||||
_repeaters,
|
||||
&packet,
|
||||
timer
|
||||
);
|
||||
|
||||
core_manager.allocate_image_buffer(payload_length as usize);
|
||||
drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded: true })
|
||||
}
|
||||
drtioaux::Packet::CoreMgmtFlashAddDataRequest {
|
||||
destination: _destination,
|
||||
last,
|
||||
length,
|
||||
data,
|
||||
} => {
|
||||
forward!(
|
||||
router,
|
||||
_routing_table,
|
||||
_destination,
|
||||
*rank,
|
||||
*self_destination,
|
||||
_repeaters,
|
||||
&packet,
|
||||
timer
|
||||
);
|
||||
|
||||
core_manager.add_image_data(&data, length as usize);
|
||||
|
||||
if last {
|
||||
drtioaux::send(0, &drtioaux::Packet::CoreMgmtDropLink)
|
||||
} else {
|
||||
drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded: true })
|
||||
}
|
||||
}
|
||||
drtioaux::Packet::CoreMgmtDropLinkAck {
|
||||
destination: _destination,
|
||||
} => {
|
||||
forward!(
|
||||
router,
|
||||
_routing_table,
|
||||
_destination,
|
||||
*rank,
|
||||
*self_destination,
|
||||
_repeaters,
|
||||
&packet,
|
||||
timer
|
||||
);
|
||||
|
||||
unsafe {
|
||||
csr::gt_drtio::txenable_write(0);
|
||||
}
|
||||
core_manager.write_image();
|
||||
info!("reboot imminent");
|
||||
slcr::reboot();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
p => {
|
||||
warn!("received unexpected aux packet: {:?}", p);
|
||||
|
@ -1028,6 +1363,7 @@ fn process_aux_packets(
|
|||
dma_manager: &mut DmaManager,
|
||||
analyzer: &mut Analyzer,
|
||||
kernel_manager: &mut KernelManager,
|
||||
core_manager: &mut CoreManager,
|
||||
router: &mut Router,
|
||||
) {
|
||||
let result = drtioaux::recv(0).and_then(|packet| {
|
||||
|
@ -1043,6 +1379,7 @@ fn process_aux_packets(
|
|||
dma_manager,
|
||||
analyzer,
|
||||
kernel_manager,
|
||||
core_manager,
|
||||
router,
|
||||
)
|
||||
} else {
|
||||
|
@ -1239,7 +1576,7 @@ 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() {
|
||||
let mut cfg = match Config::new() {
|
||||
Ok(cfg) => cfg,
|
||||
Err(err) => {
|
||||
warn!("config initialization failed: {}", err);
|
||||
|
@ -1314,6 +1651,7 @@ pub extern "C" fn main_core0() -> i32 {
|
|||
let mut dma_manager = DmaManager::new();
|
||||
let mut analyzer = Analyzer::new();
|
||||
let mut kernel_manager = KernelManager::new(&mut control);
|
||||
let mut core_manager = CoreManager::new(&mut cfg);
|
||||
|
||||
drtioaux::reset(0);
|
||||
drtiosat_reset(false);
|
||||
|
@ -1331,6 +1669,7 @@ pub extern "C" fn main_core0() -> i32 {
|
|||
&mut dma_manager,
|
||||
&mut analyzer,
|
||||
&mut kernel_manager,
|
||||
&mut core_manager,
|
||||
&mut router,
|
||||
);
|
||||
#[allow(unused_mut)]
|
||||
|
|
|
@ -0,0 +1,149 @@
|
|||
use alloc::vec::Vec;
|
||||
|
||||
use byteorder::{ByteOrder, NativeEndian};
|
||||
use crc::crc32;
|
||||
use io::{ProtoRead, ProtoWrite};
|
||||
use libboard_artiq::{drtioaux_proto::SAT_PAYLOAD_MAX_SIZE,
|
||||
logger::{BufferLogger, LogBufferRef}};
|
||||
use libconfig::Config;
|
||||
use log::{debug, error, info, warn, LevelFilter};
|
||||
|
||||
use crate::routing::{SliceMeta, Sliceable};
|
||||
|
||||
type Result<T> = core::result::Result<T, ()>;
|
||||
|
||||
pub fn byte_to_level_filter(level_byte: u8) -> Result<LevelFilter> {
|
||||
Ok(match level_byte {
|
||||
0 => LevelFilter::Off,
|
||||
1 => LevelFilter::Error,
|
||||
2 => LevelFilter::Warn,
|
||||
3 => LevelFilter::Info,
|
||||
4 => LevelFilter::Debug,
|
||||
5 => LevelFilter::Trace,
|
||||
lv => {
|
||||
error!("unknown log level: {}", lv);
|
||||
return Err(());
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn get_logger_buffer() -> LogBufferRef<'static> {
|
||||
let logger = unsafe { BufferLogger::get_logger().as_mut().unwrap() };
|
||||
loop {
|
||||
if let Some(buffer_ref) = logger.buffer() {
|
||||
return buffer_ref;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn clear_log() {
|
||||
let mut buffer = get_logger_buffer();
|
||||
buffer.clear();
|
||||
}
|
||||
|
||||
pub struct Manager<'a> {
|
||||
cfg: &'a mut Config,
|
||||
last_log: Sliceable,
|
||||
config_payload: Vec<u8>,
|
||||
last_value: Sliceable,
|
||||
image_payload: Vec<u8>,
|
||||
}
|
||||
|
||||
impl<'a> Manager<'_> {
|
||||
pub fn new(cfg: &mut Config) -> Manager {
|
||||
Manager {
|
||||
cfg: cfg,
|
||||
last_log: Sliceable::new(0, Vec::new()),
|
||||
config_payload: Vec::new(),
|
||||
last_value: Sliceable::new(0, Vec::new()),
|
||||
image_payload: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn log_get_slice(&mut self, data_slice: &mut [u8; SAT_PAYLOAD_MAX_SIZE], consume: bool) -> SliceMeta {
|
||||
// Populate buffer if depleted
|
||||
if self.last_log.at_end() {
|
||||
let mut buffer = get_logger_buffer();
|
||||
self.last_log.extend(buffer.extract().as_bytes());
|
||||
if consume {
|
||||
buffer.clear();
|
||||
}
|
||||
}
|
||||
|
||||
self.last_log.get_slice_satellite(data_slice)
|
||||
}
|
||||
|
||||
pub fn fetch_config_value(&mut self, key: &str) -> Result<()> {
|
||||
self.cfg
|
||||
.read(&key)
|
||||
.map(|value| {
|
||||
debug!("got value");
|
||||
self.last_value = Sliceable::new(0, value)
|
||||
})
|
||||
.map_err(|_| warn!("read error: no such key"))
|
||||
}
|
||||
|
||||
pub fn get_config_value_slice(&mut self, data_slice: &mut [u8; SAT_PAYLOAD_MAX_SIZE]) -> SliceMeta {
|
||||
self.last_value.get_slice_satellite(data_slice)
|
||||
}
|
||||
|
||||
pub fn add_config_data(&mut self, data: &[u8], data_len: usize) {
|
||||
self.config_payload.write_all(&data[..data_len]).unwrap();
|
||||
}
|
||||
|
||||
pub fn clear_config_data(&mut self) {
|
||||
self.config_payload.clear();
|
||||
}
|
||||
|
||||
pub fn write_config(&mut self) -> Result<()> {
|
||||
let mut payload = &self.config_payload[..];
|
||||
let key = payload.read_string().map_err(|_err| error!("error on reading key"))?;
|
||||
debug!("write key: {}", key);
|
||||
let value = payload.read_bytes().unwrap();
|
||||
|
||||
self.cfg
|
||||
.write(&key, value)
|
||||
.map(|()| debug!("write success"))
|
||||
.map_err(|err| error!("failed to write: {:?}", err))
|
||||
}
|
||||
|
||||
pub fn remove_config(&mut self, key: &str) -> Result<()> {
|
||||
debug!("erase key: {}", key);
|
||||
self.cfg
|
||||
.remove(&key)
|
||||
.map(|()| debug!("erase success"))
|
||||
.map_err(|err| warn!("failed to erase: {:?}", err))
|
||||
}
|
||||
|
||||
pub fn allocate_image_buffer(&mut self, image_size: usize) {
|
||||
self.image_payload = Vec::with_capacity(image_size);
|
||||
}
|
||||
|
||||
pub fn add_image_data(&mut self, data: &[u8], data_len: usize) {
|
||||
self.image_payload.extend(&data[..data_len]);
|
||||
}
|
||||
|
||||
pub fn write_image(&self) {
|
||||
let mut image = self.image_payload.clone();
|
||||
let image_ref = &image[..];
|
||||
let bin_len = image.len() - 4;
|
||||
|
||||
let (image_ref, expected_crc) = {
|
||||
let (image_ref, crc_slice) = image_ref.split_at(bin_len);
|
||||
(image_ref, NativeEndian::read_u32(crc_slice))
|
||||
};
|
||||
|
||||
let actual_crc = crc32::checksum_ieee(image_ref);
|
||||
|
||||
if actual_crc == expected_crc {
|
||||
info!("CRC passed. Writing boot image to SD card...");
|
||||
image.truncate(bin_len);
|
||||
self.cfg.write("boot", image).expect("failed to write boot image");
|
||||
} else {
|
||||
panic!(
|
||||
"CRC failed, images have not been written to flash.\n(actual {:08x}, expected {:08x})",
|
||||
actual_crc, expected_crc
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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}};
|
||||
drtioaux_proto::{PayloadStatus, MASTER_PAYLOAD_MAX_SIZE, SAT_PAYLOAD_MAX_SIZE}};
|
||||
|
||||
pub struct SliceMeta {
|
||||
pub destination: u8,
|
||||
|
@ -58,6 +58,7 @@ impl Sliceable {
|
|||
}
|
||||
|
||||
get_slice_fn!(get_slice_master, MASTER_PAYLOAD_MAX_SIZE);
|
||||
get_slice_fn!(get_slice_satellite, SAT_PAYLOAD_MAX_SIZE);
|
||||
}
|
||||
|
||||
// Packets from downstream (further satellites) are received and routed appropriately.
|
||||
|
|
|
@ -8,7 +8,7 @@ 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},
|
||||
|
@ -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 {
|
||||
self.load(id)?;
|
||||
}
|
||||
|
@ -359,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(())
|
||||
}
|
||||
|
@ -812,6 +813,7 @@ impl<'a> Manager<'_> {
|
|||
id,
|
||||
destination: sk_destination,
|
||||
run,
|
||||
timestamp,
|
||||
} => {
|
||||
self.session.kernel_state = KernelState::SubkernelAwaitLoad;
|
||||
router.route(
|
||||
|
@ -820,6 +822,7 @@ impl<'a> Manager<'_> {
|
|||
destination: sk_destination,
|
||||
id: id,
|
||||
run: run,
|
||||
timestamp,
|
||||
},
|
||||
routing_table,
|
||||
rank,
|
||||
|
|
Loading…
Reference in New Issue