Compare commits
333 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8d40210d87 | |||
| 15eaa4eb65 | |||
| 3c70203709 | |||
| 9614c48e9d | |||
| 1c4534637d | |||
| 5bd6fe0ad5 | |||
| a8cf7644a2 | |||
| febc623c4b | |||
| ebdfff202a | |||
| c4334a1d8c | |||
| 35be9d5501 | |||
| 1309fe1c97 | |||
| 29bb0aba28 | |||
| d877013a2a | |||
| 30fc3ef2e8 | |||
| 2fb3c7274d | |||
| 8d01fe7a20 | |||
| b8c4184f8e | |||
| e2ce90f051 | |||
| 5c8ea9b885 | |||
| 963d4194b1 | |||
| be38a5d2ee | |||
| ad340334fb | |||
| 9a5e68af41 | |||
| f9255d0611 | |||
| 7350e6dff5 | |||
| 5270fce5f5 | |||
| 3a410e5414 | |||
| 01609cce59 | |||
| ce48d430af | |||
| b83772baf5 | |||
| 099c344cc4 | |||
| c65b130275 | |||
| efd45316e7 | |||
| 1f8c9c3ee3 | |||
| 4a1dc628d9 | |||
| 72407a19a3 | |||
| d9871ed0a7 | |||
| 90db06a9e1 | |||
| 446384d787 | |||
|
|
f3d4793fcb | ||
|
|
00c4d48211 | ||
| fd1b2453d7 | |||
| 6ff895c0bf | |||
|
|
b55f629486 | ||
| 61dbb6a0f1 | |||
| 159987a64b | |||
| 3be9250978 | |||
| b88bb90139 | |||
| 3b0b52ef2c | |||
| 982828bde1 | |||
| db0231956e | |||
| d9bf878d03 | |||
| beb98b52fd | |||
| d57f308765 | |||
| d9f2f84480 | |||
| c317b3a0ac | |||
| 54ce700fde | |||
| 7f28167279 | |||
| 307ced4585 | |||
| 3f497e08a4 | |||
|
|
9a816e1d5b | ||
| 7cceda9353 | |||
| a325d5ce78 | |||
| 40f1c94ecf | |||
| 92c586d266 | |||
| 96928b7d0d | |||
| 59266fd141 | |||
| 78080eae2b | |||
| f1e79310ec | |||
| 3a65d6c2a5 | |||
| 734fd11ad6 | |||
| 5843138a8e | |||
| 1ab755838a | |||
| e21873d227 | |||
| 767b725db7 | |||
| e02b56b709 | |||
| 8223d263f6 | |||
| 1c64f4488a | |||
| 67d79c81a5 | |||
| 9e6b06250a | |||
| 58e54ec7af | |||
| 089f3cb664 | |||
| b0f508f675 | |||
| 89f22883e5 | |||
| 160132a858 | |||
| eeda17bbb5 | |||
| b7588ed629 | |||
| 7fc7e971f7 | |||
| aacf22211b | |||
| 8769439d60 | |||
| 7fb596e803 | |||
| 137fb5375e | |||
| 23af88157e | |||
| 37cdc02b66 | |||
| 74a1ff2bc7 | |||
| 54d494e6ec | |||
| 871de86e18 | |||
| fcb668dd23 | |||
| 7478ff4967 | |||
| d9b5bb83c2 | |||
| 2defdc13bd | |||
| bb8bc269a2 | |||
| c03d3c500b | |||
| 23512254d4 | |||
| e8b73e45fb | |||
| a5b46ca948 | |||
| eace3e9fb7 | |||
| f2462b28e6 | |||
| ba3eec7154 | |||
| 0c216c86ae | |||
| ea3b6141c4 | |||
| 955283eea4 | |||
| e4800e1343 | |||
| 6124937da0 | |||
| 32b91027fd | |||
| 5afc1d4296 | |||
| 1b012fd708 | |||
| 81baed1231 | |||
| bc80454c8d | |||
| 23d92f1cc2 | |||
| 9093ee9350 | |||
| c34779c20c | |||
| 192f8b24fd | |||
| 724ba885b0 | |||
| 2340b44dae | |||
| 0c642c48c0 | |||
| 3338dcd56b | |||
| a9a85b440e | |||
| 67dfbe6860 | |||
| 2c1979d380 | |||
| f3c0fc24cd | |||
| 5dff8636f6 | |||
| 0933a0f013 | |||
| 80309e8cdc | |||
| 39cf613818 | |||
| 1ace72f2f0 | |||
| bb700bc955 | |||
| 8c5c8b8169 | |||
| ae0abe364f | |||
| f5a6a674f5 | |||
| 15e9f09a54 | |||
| 5ceff93a7a | |||
| d77e092523 | |||
| dcc022d8c8 | |||
| d9388adc05 | |||
| 3f1186d363 | |||
| 7cad72fc39 | |||
| 56b5240039 | |||
| e05df9791b | |||
| a37124b318 | |||
| e7bcbf43d6 | |||
| add27693c5 | |||
| 8be4ac6265 | |||
| c0eb70247a | |||
| 7df7335cce | |||
| 13654d9f5a | |||
| 1445ab16d6 | |||
| 257e6c4772 | |||
| 2157539140 | |||
| c60b6bcd41 | |||
| 228050c54d | |||
| da4748bea7 | |||
| 0717003c42 | |||
| 04856e66d0 | |||
| 1dd864f9e5 | |||
| 168529e26d | |||
| f917457fbd | |||
| 29ed10dfb3 | |||
| afd0389bf3 | |||
| f5139ee140 | |||
| 761b7c99cd | |||
| 5982937ee6 | |||
| 32889c11f1 | |||
| bc7925989b | |||
| b2256800fe | |||
| 637163bbca | |||
| 50ead76c09 | |||
| 267a1222ed | |||
| fe09e8615e | |||
| cb8fa20beb | |||
| 0efa450537 | |||
| 4c59ab933b | |||
| 504d7a8d5b | |||
| a577238bae | |||
| 1c90228f84 | |||
| 8129b8163c | |||
| 95175b7168 | |||
| 3172625ba6 | |||
| 9e51599195 | |||
| 5445a1268c | |||
| 48ed2f188e | |||
| 64d79de6c5 | |||
| be8f618d95 | |||
| dca808b2e4 | |||
| e4b85bf51a | |||
| c2c5367572 | |||
| 290134e07e | |||
| e07dad71d5 | |||
| d0c34671d7 | |||
| 82a1b38a19 | |||
| db76dfc209 | |||
| b0ceac0f3a | |||
| a0673f13a1 | |||
| 6086b867c8 | |||
| 17f59e2353 | |||
| f080bee029 | |||
| 599442dc0d | |||
| 622bca24d1 | |||
| bcab64f1ff | |||
| dfc731a4c1 | |||
| 58ecf62921 | |||
| 11134cdfd6 | |||
| 2e99b9cf0d | |||
| 4f79ee962c | |||
| d4105b79e7 | |||
| 1beb6fd944 | |||
| ce1c430fdc | |||
| cf99700299 | |||
| 9f1f349b29 | |||
| 98255ec25a | |||
| 421033ef98 | |||
| c603a4ba12 | |||
| 529d7819a9 | |||
| 1a1a7112ca | |||
| e524317eb9 | |||
| d545feddbd | |||
| 0e6da19406 | |||
| d0e2404311 | |||
| cd9f8e6d7c | |||
| 4a2b28dcc3 | |||
| 21a4a0b5dd | |||
| a82d356f52 | |||
| 8b9bb38331 | |||
| 63157588bb | |||
| 11f8675ad6 | |||
| a0281e4989 | |||
| 850e783139 | |||
| 8fd8cae9d5 | |||
| 7acf8af7f7 | |||
| 13264d9992 | |||
| 8d07f006f2 | |||
| 97e15d51f2 | |||
| 0021a01bdf | |||
| 16801a35f4 | |||
| 81eba30a29 | |||
| 7d6d40a785 | |||
| ffe3020788 | |||
| 8f510b5ca6 | |||
| 5582ca74d2 | |||
| 7c741d9c18 | |||
| 922a03b807 | |||
| 716a5924d1 | |||
| 4856cddb65 | |||
| e1f493f3ca | |||
| 1f5ea41934 | |||
| 7f83d56ef5 | |||
| 1d431456f4 | |||
| b03e380c1e | |||
| 47fc53c4bf | |||
| 42eaecf9e1 | |||
| beb7e6f994 | |||
| 4502a47aa6 | |||
| ac6b7d5cf0 | |||
| 3019bc6123 | |||
| 95b8562812 | |||
| a13f5d02fa | |||
| e52aa77068 | |||
| 8e28d12ad0 | |||
| 47cddae04f | |||
| 27a65df40e | |||
| 759cca3bfd | |||
| aadb6fc22d | |||
| ae4d5a4228 | |||
| 6f1d727ca2 | |||
| 7da5061f7e | |||
| 47d418c69e | |||
| d2979e8894 | |||
| 3884c14a19 | |||
| c5b00d8e4e | |||
| 2985875f9a | |||
| 5cb565a7e0 | |||
| 59954829a2 | |||
| 960864c847 | |||
| bdc29e5709 | |||
| 332732dc44 | |||
| 244c7396d9 | |||
| 2c633409b8 | |||
| 9774b39fd8 | |||
| 9054e4a7cb | |||
| d79bf8d54a | |||
| 75e7fc55a3 | |||
| 24a4d79f0f | |||
| 9ce3aadb15 | |||
| 3390abd5a1 | |||
| a410c40b50 | |||
| 030247be18 | |||
| 61df939c87 | |||
| aba97175c6 | |||
| 81790257a5 | |||
| 1f81d038e0 | |||
| 1e42228aac | |||
| c84653b500 | |||
| 6585b9b441 | |||
| 873dd86b4d | |||
| e7614d2e8e | |||
| 491e426222 | |||
| ccd3bf3003 | |||
| 3fdb7e80a8 | |||
| bd1de933fb | |||
| e8d77fca3e | |||
| 85e8a3fc44 | |||
| 04078b3d89 | |||
| d508c5c6f8 | |||
| bae41253e4 | |||
| 20181e9915 | |||
| a835149619 | |||
| 78d6b7ddcf | |||
| fad1db9796 | |||
| fee30033ec | |||
| fe6f259d48 | |||
| e4d7ce114f | |||
| 63f4783687 | |||
| 69a0b1bfb7 | |||
| f6bff80105 | |||
| 57fd327ecb | |||
| 69d5b11ebf | |||
| bab938c563 | |||
| d51e5e60c3 | |||
| 23857eef63 | |||
| d0615bf965 | |||
| 3a789889cf | |||
| 72b814f7fd |
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
|
||||
[elf_use_ph]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
|
||||
-------
|
||||
|
||||
@@ -2,8 +2,11 @@
|
||||
"target": "kasli_soc",
|
||||
"variant": "demo",
|
||||
"hw_rev": "v1.0",
|
||||
"base": "standalone",
|
||||
"drtio_role": "standalone",
|
||||
"peripherals": [
|
||||
{
|
||||
"type": "coaxpress_sfp"
|
||||
},
|
||||
{
|
||||
"type": "grabber",
|
||||
"ports": [0]
|
||||
|
||||
@@ -1,76 +0,0 @@
|
||||
# For NIST_QC2
|
||||
|
||||
device_db = {
|
||||
"core": {
|
||||
"type": "local",
|
||||
"module": "artiq.coredevice.core",
|
||||
"class": "Core",
|
||||
"arguments": {
|
||||
"host": "192.168.1.52",
|
||||
"ref_period": 1e-9,
|
||||
"ref_multiplier": 8,
|
||||
"target": "cortexa9"
|
||||
}
|
||||
},
|
||||
"core_cache": {
|
||||
"type": "local",
|
||||
"module": "artiq.coredevice.cache",
|
||||
"class": "CoreCache"
|
||||
},
|
||||
"core_dma": {
|
||||
"type": "local",
|
||||
"module": "artiq.coredevice.dma",
|
||||
"class": "CoreDMA"
|
||||
},
|
||||
|
||||
"i2c_switch": {
|
||||
"type": "local",
|
||||
"module": "artiq.coredevice.i2c",
|
||||
"class": "PCA9548"
|
||||
},
|
||||
|
||||
"led0": {
|
||||
"type": "local",
|
||||
"module": "artiq.coredevice.ttl",
|
||||
"class": "TTLOut",
|
||||
"arguments": {"channel": 41},
|
||||
},
|
||||
}
|
||||
|
||||
# TTLs on QC2 backplane
|
||||
for i in range(40):
|
||||
device_db["ttl" + str(i)] = {
|
||||
"type": "local",
|
||||
"module": "artiq.coredevice.ttl",
|
||||
"class": "TTLInOut",
|
||||
"arguments": {"channel": i}
|
||||
}
|
||||
|
||||
device_db["ad9914dds0"] = {
|
||||
"type": "local",
|
||||
"module": "artiq.coredevice.ad9914",
|
||||
"class": "AD9914",
|
||||
"arguments": {"sysclk": 3e9, "bus_channel": 50, "channel": 0},
|
||||
}
|
||||
device_db["ad9914dds1"] = {
|
||||
"type": "local",
|
||||
"module": "artiq.coredevice.ad9914",
|
||||
"class": "AD9914",
|
||||
"arguments": {"sysclk": 3e9, "bus_channel": 50, "channel": 1},
|
||||
}
|
||||
|
||||
for i in range(4):
|
||||
device_db["ttl"+str(i)+"_counter"] = {
|
||||
"type": "local",
|
||||
"module": "artiq.coredevice.edge_counter",
|
||||
"class": "EdgeCounter",
|
||||
"arguments": {"channel": 52+i}
|
||||
}
|
||||
|
||||
# for ARTIQ test suite
|
||||
device_db.update(
|
||||
loop_out="ttl0",
|
||||
loop_in="ttl1",
|
||||
ttl_out="ttl2",
|
||||
ttl_out_serdes="ttl2",
|
||||
)
|
||||
1
examples/device_db.py
Symbolic link
1
examples/device_db.py
Symbolic link
@@ -0,0 +1 @@
|
||||
device_db_zc706.py
|
||||
78
examples/device_db_ebaz4205.py
Normal file
78
examples/device_db_ebaz4205.py
Normal file
@@ -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"},
|
||||
},
|
||||
)
|
||||
86
examples/device_db_zc706.py
Normal file
86
examples/device_db_zc706.py
Normal file
@@ -0,0 +1,86 @@
|
||||
# For NIST_QC2
|
||||
|
||||
import os
|
||||
|
||||
device_db = {
|
||||
"core": {
|
||||
"type": "local",
|
||||
"module": "artiq.coredevice.core",
|
||||
"class": "Core",
|
||||
"arguments": {
|
||||
"host": "192.168.1.52",
|
||||
"ref_period": 1e-9,
|
||||
"ref_multiplier": 8,
|
||||
"target": "cortexa9"
|
||||
}
|
||||
},
|
||||
"core_cache": {
|
||||
"type": "local",
|
||||
"module": "artiq.coredevice.cache",
|
||||
"class": "CoreCache"
|
||||
},
|
||||
"core_dma": {
|
||||
"type": "local",
|
||||
"module": "artiq.coredevice.dma",
|
||||
"class": "CoreDMA"
|
||||
},
|
||||
|
||||
"i2c_switch": {
|
||||
"type": "local",
|
||||
"module": "artiq.coredevice.i2c",
|
||||
"class": "PCA9548"
|
||||
},
|
||||
|
||||
"led0": {
|
||||
"type": "local",
|
||||
"module": "artiq.coredevice.ttl",
|
||||
"class": "TTLOut",
|
||||
"arguments": {"channel": 41},
|
||||
},
|
||||
}
|
||||
|
||||
# TTLs on QC2 backplane
|
||||
for i in range(40):
|
||||
device_db["ttl" + str(i)] = {
|
||||
"type": "local",
|
||||
"module": "artiq.coredevice.ttl",
|
||||
"class": "TTLInOut",
|
||||
"arguments": {"channel": i}
|
||||
}
|
||||
|
||||
device_db["ad9914dds0"] = {
|
||||
"type": "local",
|
||||
"module": "artiq.coredevice.ad9914",
|
||||
"class": "AD9914",
|
||||
"arguments": {"sysclk": 3e9, "bus_channel": 50, "channel": 0},
|
||||
}
|
||||
device_db["ad9914dds1"] = {
|
||||
"type": "local",
|
||||
"module": "artiq.coredevice.ad9914",
|
||||
"class": "AD9914",
|
||||
"arguments": {"sysclk": 3e9, "bus_channel": 50, "channel": 1},
|
||||
}
|
||||
|
||||
for i in range(4):
|
||||
device_db["ttl"+str(i)+"_counter"] = {
|
||||
"type": "local",
|
||||
"module": "artiq.coredevice.edge_counter",
|
||||
"class": "EdgeCounter",
|
||||
"arguments": {"channel": 52+i}
|
||||
}
|
||||
|
||||
# for ARTIQ test suite
|
||||
device_db.update(
|
||||
loop_out="ttl0",
|
||||
loop_in="ttl1",
|
||||
ttl_out="ttl2",
|
||||
ttl_out_serdes="ttl2",
|
||||
)
|
||||
|
||||
if os.environ.get("ENABLE_ACPKI"):
|
||||
device_db["core_batch"] = {
|
||||
"type": "local",
|
||||
"module": "artiq.coredevice.rtio",
|
||||
"class": "RTIOBatch"
|
||||
}
|
||||
|
||||
310
flake.lock
generated
310
flake.lock
generated
@@ -3,25 +3,26 @@
|
||||
"artiq": {
|
||||
"inputs": {
|
||||
"artiq-comtools": "artiq-comtools",
|
||||
"mozilla-overlay": "mozilla-overlay",
|
||||
"naersk": "naersk",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"rust-overlay": "rust-overlay",
|
||||
"sipyco": "sipyco",
|
||||
"src-migen": "src-migen",
|
||||
"src-misoc": "src-misoc",
|
||||
"src-pythonparser": "src-pythonparser"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1717638354,
|
||||
"narHash": "sha256-eyI8OsOrn/j8ChbCpyFpS5VXBW8xSNGGIboFGQj/d4I=",
|
||||
"lastModified": 1770708569,
|
||||
"narHash": "sha256-Q/qir1PtGhinxNzkm/SzySwtLK0nsc06xn6BBPMuKlw=",
|
||||
"ref": "refs/heads/master",
|
||||
"rev": "ebc1e3fb767d6c0eac6eac20c3afeaba2ab70d1a",
|
||||
"revCount": 8833,
|
||||
"rev": "80d453eb23c5db45e02b7a84cf9b07ae8bf9bcfd",
|
||||
"revCount": 9621,
|
||||
"type": "git",
|
||||
"url": "https://github.com/m-labs/artiq.git"
|
||||
"url": "https://git.m-labs.hk/m-labs/artiq"
|
||||
},
|
||||
"original": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/m-labs/artiq.git"
|
||||
"url": "https://git.m-labs.hk/m-labs/artiq"
|
||||
}
|
||||
},
|
||||
"artiq-comtools": {
|
||||
@@ -37,16 +38,62 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1717637438,
|
||||
"narHash": "sha256-BXFidNm3Em8iChPGu1L0s2bY+f2yQ0VVid4MuOoTehw=",
|
||||
"owner": "m-labs",
|
||||
"repo": "artiq-comtools",
|
||||
"rev": "78d27026efe76a13f7b4698a554f55811369ec4d",
|
||||
"lastModified": 1767353405,
|
||||
"narHash": "sha256-KGQqMMN+xavRYEPsBHnNptLvMGxaPzVqHJnYiOEo57c=",
|
||||
"ref": "refs/heads/master",
|
||||
"rev": "3da1f80d702b3a01c4b4fba9e5bc832b79097338",
|
||||
"revCount": 44,
|
||||
"type": "git",
|
||||
"url": "https://git.m-labs.hk/M-Labs/artiq-comtools.git"
|
||||
},
|
||||
"original": {
|
||||
"type": "git",
|
||||
"url": "https://git.m-labs.hk/M-Labs/artiq-comtools.git"
|
||||
}
|
||||
},
|
||||
"fenix": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"artiq",
|
||||
"naersk",
|
||||
"nixpkgs"
|
||||
],
|
||||
"rust-analyzer-src": "rust-analyzer-src"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1752475459,
|
||||
"narHash": "sha256-z6QEu4ZFuHiqdOPbYss4/Q8B0BFhacR8ts6jO/F/aOU=",
|
||||
"owner": "nix-community",
|
||||
"repo": "fenix",
|
||||
"rev": "bf0d6f70f4c9a9cf8845f992105652173f4b617f",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "m-labs",
|
||||
"repo": "artiq-comtools",
|
||||
"owner": "nix-community",
|
||||
"repo": "fenix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"fenix_2": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"zynq-rs",
|
||||
"naersk",
|
||||
"nixpkgs"
|
||||
],
|
||||
"rust-analyzer-src": "rust-analyzer-src_2"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1752475459,
|
||||
"narHash": "sha256-z6QEu4ZFuHiqdOPbYss4/Q8B0BFhacR8ts6jO/F/aOU=",
|
||||
"owner": "nix-community",
|
||||
"repo": "fenix",
|
||||
"rev": "bf0d6f70f4c9a9cf8845f992105652173f4b617f",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"repo": "fenix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
@@ -55,11 +102,11 @@
|
||||
"systems": "systems"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1710146030,
|
||||
"narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
|
||||
"lastModified": 1731533236,
|
||||
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
|
||||
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -68,66 +115,62 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"mozilla-overlay": {
|
||||
"flake": false,
|
||||
"naersk": {
|
||||
"inputs": {
|
||||
"fenix": "fenix",
|
||||
"nixpkgs": [
|
||||
"artiq",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1704373101,
|
||||
"narHash": "sha256-+gi59LRWRQmwROrmE1E2b3mtocwueCQqZ60CwLG+gbg=",
|
||||
"owner": "mozilla",
|
||||
"repo": "nixpkgs-mozilla",
|
||||
"rev": "9b11a87c0cc54e308fa83aac5b4ee1816d5418a2",
|
||||
"lastModified": 1768908532,
|
||||
"narHash": "sha256-HIdLXEFaUVE8FiaCPJbCfBMsnF+mVtDub8Jwj2BD+mk=",
|
||||
"owner": "nix-community",
|
||||
"repo": "naersk",
|
||||
"rev": "8d97452673640eb7fabe428e8b6a425bc355008b",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "mozilla",
|
||||
"repo": "nixpkgs-mozilla",
|
||||
"owner": "nix-community",
|
||||
"repo": "naersk",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"mozilla-overlay_2": {
|
||||
"flake": false,
|
||||
"naersk_2": {
|
||||
"inputs": {
|
||||
"fenix": "fenix_2",
|
||||
"nixpkgs": [
|
||||
"zynq-rs",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1704373101,
|
||||
"narHash": "sha256-+gi59LRWRQmwROrmE1E2b3mtocwueCQqZ60CwLG+gbg=",
|
||||
"owner": "mozilla",
|
||||
"repo": "nixpkgs-mozilla",
|
||||
"rev": "9b11a87c0cc54e308fa83aac5b4ee1816d5418a2",
|
||||
"lastModified": 1769799857,
|
||||
"narHash": "sha256-88IFXZ7Sa1vxbz5pty0Io5qEaMQMMUPMonLa3Ls/ss4=",
|
||||
"owner": "nix-community",
|
||||
"repo": "naersk",
|
||||
"rev": "9d4ed44d8b8cecdceb1d6fd76e74123d90ae6339",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "mozilla",
|
||||
"repo": "nixpkgs-mozilla",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"mozilla-overlay_3": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1704373101,
|
||||
"narHash": "sha256-+gi59LRWRQmwROrmE1E2b3mtocwueCQqZ60CwLG+gbg=",
|
||||
"owner": "mozilla",
|
||||
"repo": "nixpkgs-mozilla",
|
||||
"rev": "9b11a87c0cc54e308fa83aac5b4ee1816d5418a2",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "mozilla",
|
||||
"repo": "nixpkgs-mozilla",
|
||||
"owner": "nix-community",
|
||||
"repo": "naersk",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1717281328,
|
||||
"narHash": "sha256-evZPzpf59oNcDUXxh2GHcxHkTEG4fjae2ytWP85jXRo=",
|
||||
"lastModified": 1768940263,
|
||||
"narHash": "sha256-sJERJIYTKPFXkoz/gBaBtRKke82h4DkX3BBSsKbfbvI=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "b3b2b28c1daa04fe2ae47c21bb76fd226eac4ca1",
|
||||
"rev": "3ceaaa8bc963ced4d830e06ea2d0863b6490ff03",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-24.05",
|
||||
"ref": "nixos-25.11",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
@@ -135,10 +178,86 @@
|
||||
"root": {
|
||||
"inputs": {
|
||||
"artiq": "artiq",
|
||||
"mozilla-overlay": "mozilla-overlay_2",
|
||||
"zynq-rs": "zynq-rs"
|
||||
}
|
||||
},
|
||||
"rust-analyzer-src": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1752428706,
|
||||
"narHash": "sha256-EJcdxw3aXfP8Ex1Nm3s0awyH9egQvB2Gu+QEnJn2Sfg=",
|
||||
"owner": "rust-lang",
|
||||
"repo": "rust-analyzer",
|
||||
"rev": "591e3b7624be97e4443ea7b5542c191311aa141d",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "rust-lang",
|
||||
"ref": "nightly",
|
||||
"repo": "rust-analyzer",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"rust-analyzer-src_2": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1752428706,
|
||||
"narHash": "sha256-EJcdxw3aXfP8Ex1Nm3s0awyH9egQvB2Gu+QEnJn2Sfg=",
|
||||
"owner": "rust-lang",
|
||||
"repo": "rust-analyzer",
|
||||
"rev": "591e3b7624be97e4443ea7b5542c191311aa141d",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "rust-lang",
|
||||
"ref": "nightly",
|
||||
"repo": "rust-analyzer",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"rust-overlay": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"artiq",
|
||||
"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"
|
||||
}
|
||||
},
|
||||
"rust-overlay_2": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"zynq-rs",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1771038269,
|
||||
"narHash": "sha256-TygYZ7JhnJbRoWOk7d5HaA/GhEVCvtRruN7TqaN9s/c=",
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"rev": "d7a86c8a4df49002446737603a3e0d7ef91a9637",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"sipyco": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
@@ -147,67 +266,67 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1717637367,
|
||||
"narHash": "sha256-4mSm9wl5EMgzzrW6w86IDUevkEOT99FESHGcxcyQbD0=",
|
||||
"owner": "m-labs",
|
||||
"repo": "sipyco",
|
||||
"rev": "02b96ec2473a3c3d3c980899de2564ddce949dab",
|
||||
"type": "github"
|
||||
"lastModified": 1767320872,
|
||||
"narHash": "sha256-0lUkzOxOnjk3vQdsL9Yt3KLctYBTZgIRd8RvcITbqO0=",
|
||||
"ref": "refs/heads/master",
|
||||
"rev": "ce454bb64257b1bcef3703f258aaf7fa4ee0c275",
|
||||
"revCount": 154,
|
||||
"type": "git",
|
||||
"url": "https://git.m-labs.hk/M-Labs/sipyco.git"
|
||||
},
|
||||
"original": {
|
||||
"owner": "m-labs",
|
||||
"repo": "sipyco",
|
||||
"type": "github"
|
||||
"type": "git",
|
||||
"url": "https://git.m-labs.hk/M-Labs/sipyco.git"
|
||||
}
|
||||
},
|
||||
"src-migen": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1715484909,
|
||||
"narHash": "sha256-4DCHBUBfc/VA+7NW2Hr0+JP4NnKPru2uVJyZjCCk0Ws=",
|
||||
"owner": "m-labs",
|
||||
"repo": "migen",
|
||||
"rev": "4790bb577681a8c3a8d226bc196a4e5deb39e4df",
|
||||
"type": "github"
|
||||
"lastModified": 1768997857,
|
||||
"narHash": "sha256-bdKQUQ3XLc4fV5sYBfKMuHuOS7nlF0ZU7rjWIKDzFzA=",
|
||||
"ref": "refs/heads/master",
|
||||
"rev": "44e5627d367c528b3ce5e686b6f305a9dfc56f2a",
|
||||
"revCount": 2076,
|
||||
"type": "git",
|
||||
"url": "https://git.m-labs.hk/M-Labs/migen.git"
|
||||
},
|
||||
"original": {
|
||||
"owner": "m-labs",
|
||||
"repo": "migen",
|
||||
"type": "github"
|
||||
"type": "git",
|
||||
"url": "https://git.m-labs.hk/M-Labs/migen.git"
|
||||
}
|
||||
},
|
||||
"src-misoc": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1715647536,
|
||||
"narHash": "sha256-q+USDcaKHABwW56Jzq8u94iGPWlyLXMyVt0j/Gyg+IE=",
|
||||
"lastModified": 1765867404,
|
||||
"narHash": "sha256-YPYUHVIryXDp4W2hUtHUtBbRKIrbhInWImT0NKaacSY=",
|
||||
"ref": "refs/heads/master",
|
||||
"rev": "fea9de558c730bc394a5936094ae95bb9d6fa726",
|
||||
"revCount": 2455,
|
||||
"rev": "7ab412de11f6533cd68cd818924da5c28a484ccd",
|
||||
"revCount": 2509,
|
||||
"submodules": true,
|
||||
"type": "git",
|
||||
"url": "https://github.com/m-labs/misoc.git"
|
||||
"url": "https://git.m-labs.hk/M-Labs/misoc.git"
|
||||
},
|
||||
"original": {
|
||||
"submodules": true,
|
||||
"type": "git",
|
||||
"url": "https://github.com/m-labs/misoc.git"
|
||||
"url": "https://git.m-labs.hk/M-Labs/misoc.git"
|
||||
}
|
||||
},
|
||||
"src-pythonparser": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1628745371,
|
||||
"narHash": "sha256-p6TgeeaK4NEmbhimEXp31W8hVRo4DgWmcCoqZ+UdN60=",
|
||||
"owner": "m-labs",
|
||||
"repo": "pythonparser",
|
||||
"rev": "5413ee5c9f8760e95c6acd5d6e88dabb831ad201",
|
||||
"type": "github"
|
||||
"lastModified": 1767427016,
|
||||
"narHash": "sha256-E57okn+3gwvtXnF/qF/jypNYqijCLUYOEYLF9ZCzHpE=",
|
||||
"ref": "refs/heads/master",
|
||||
"rev": "a2ace427c84ee5b1e9bd9dbc9b9337e50fc54077",
|
||||
"revCount": 152,
|
||||
"type": "git",
|
||||
"url": "https://git.m-labs.hk/M-Labs/pythonparser.git"
|
||||
},
|
||||
"original": {
|
||||
"owner": "m-labs",
|
||||
"repo": "pythonparser",
|
||||
"type": "github"
|
||||
"type": "git",
|
||||
"url": "https://git.m-labs.hk/M-Labs/pythonparser.git"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
@@ -227,18 +346,19 @@
|
||||
},
|
||||
"zynq-rs": {
|
||||
"inputs": {
|
||||
"mozilla-overlay": "mozilla-overlay_3",
|
||||
"naersk": "naersk_2",
|
||||
"nixpkgs": [
|
||||
"artiq",
|
||||
"nixpkgs"
|
||||
]
|
||||
],
|
||||
"rust-overlay": "rust-overlay_2"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1716889070,
|
||||
"narHash": "sha256-w+M5NfukmcMTt73+u6Cmltjn4qpQH8bcoTGskB2IzBE=",
|
||||
"lastModified": 1771064140,
|
||||
"narHash": "sha256-udr/yfbyupzRr2HAYlqE/XMZ5lbPX3arYESrJ3hqKrc=",
|
||||
"ref": "refs/heads/master",
|
||||
"rev": "51b8111e799ebe90ca231ae4d02f84ede32632d5",
|
||||
"revCount": 646,
|
||||
"rev": "6e4e0548a2b98a6acdec8bb306caa08af8f41c2e",
|
||||
"revCount": 742,
|
||||
"type": "git",
|
||||
"url": "https://git.m-labs.hk/m-labs/zynq-rs"
|
||||
},
|
||||
|
||||
434
flake.nix
434
flake.nix
@@ -1,29 +1,36 @@
|
||||
{
|
||||
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.artiq.url = git+https://git.m-labs.hk/m-labs/artiq;
|
||||
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 }:
|
||||
let
|
||||
pkgs = import artiq.inputs.nixpkgs { system = "x86_64-linux"; overlays = [ (import mozilla-overlay) ]; };
|
||||
outputs = {
|
||||
self,
|
||||
zynq-rs,
|
||||
artiq,
|
||||
}: let
|
||||
pkgs = import artiq.inputs.nixpkgs {
|
||||
system = "x86_64-linux";
|
||||
overlays = [(import zynq-rs.inputs.rust-overlay)];
|
||||
};
|
||||
zynqpkgs = zynq-rs.packages.x86_64-linux;
|
||||
artiqpkgs = artiq.packages.x86_64-linux;
|
||||
llvmPackages_11 = zynq-rs.llvmPackages_11;
|
||||
zynqRev = self.sourceInfo.rev or "unknown";
|
||||
|
||||
rust = zynq-rs.rust;
|
||||
rustPlatform = zynq-rs.rustPlatform;
|
||||
naerskLib = zynq-rs.naerskLib;
|
||||
|
||||
fastnumbers = pkgs.python3Packages.buildPythonPackage rec {
|
||||
pname = "fastnumbers";
|
||||
version = "2.2.1";
|
||||
version = "5.1.0";
|
||||
|
||||
src = pkgs.python3Packages.fetchPypi {
|
||||
inherit pname version;
|
||||
sha256 = "0j15i54p7nri6hkzn1wal9pxri4pgql01wgjccig6ar0v5jjbvsy";
|
||||
sha256 = "sha256-4JLTP4uVwxcaL7NOV57+DFSwKQ3X+W/6onYkN2AdkKc=";
|
||||
};
|
||||
pyproject = true;
|
||||
build-system = [pkgs.python3Packages.setuptools];
|
||||
};
|
||||
|
||||
artiq-netboot = pkgs.python3Packages.buildPythonPackage rec {
|
||||
@@ -35,6 +42,8 @@
|
||||
rev = "04f69eb07df73abe4b89fde2c24084f7664f2104";
|
||||
sha256 = "0ql4fr8m8gpb2yql8aqsdqsssxb8zqd6l65kl1f6s9845zy7shs9";
|
||||
};
|
||||
pyproject = true;
|
||||
build-system = [pkgs.python3Packages.setuptools];
|
||||
};
|
||||
|
||||
ramda = pkgs.python3Packages.buildPythonPackage {
|
||||
@@ -47,11 +56,13 @@
|
||||
rev = "d315a9717ebd639366bf3fe26bad9e3d08ec3c49";
|
||||
sha256 = "sha256-bmSt/IHDnULsZjsC6edELnNH7LoJSVF4L4XhwBAXRkY=";
|
||||
};
|
||||
pyproject = true;
|
||||
build-system = [pkgs.python3Packages.setuptools];
|
||||
|
||||
nativeBuildInputs = with pkgs.python3Packages; [ pbr ];
|
||||
propagatedBuildInputs = with pkgs.python3Packages; [ future fastnumbers ];
|
||||
nativeBuildInputs = with pkgs.python3Packages; [pbr];
|
||||
propagatedBuildInputs = with pkgs.python3Packages; [fastnumbers];
|
||||
|
||||
checkInputs = with pkgs.python3Packages; [ pytest ];
|
||||
checkInputs = with pkgs.python3Packages; [pytest];
|
||||
checkPhase = "pytest";
|
||||
doCheck = false;
|
||||
|
||||
@@ -67,15 +78,15 @@
|
||||
src = pkgs.fetchFromGitHub {
|
||||
owner = "peteut";
|
||||
repo = "migen-axi";
|
||||
rev = "27eaa84a70a3abfe1930c86c36c4de2cd652da35";
|
||||
sha256 = "sha256-3Y9W5ns+1wbVd14iePzgSBzE+LxnGMUDtUw3BccFt80=";
|
||||
rev = "98649a92ed7d4e43f75231e6ef9753e1212fab41";
|
||||
sha256 = "sha256-0kEHK+l6gZW750tq89fHRxIh3Gnj5EP2GZX/neWaWzU=";
|
||||
};
|
||||
pyproject = true;
|
||||
build-system = [pkgs.python3Packages.setuptools];
|
||||
|
||||
format = "pyproject";
|
||||
propagatedBuildInputs = with pkgs.python3Packages; [setuptools click numpy toolz jinja2 ramda artiqpkgs.migen artiqpkgs.misoc];
|
||||
|
||||
propagatedBuildInputs = with pkgs.python3Packages; [ setuptools click numpy toolz jinja2 ramda artiqpkgs.migen artiqpkgs.misoc ];
|
||||
|
||||
checkInputs = with pkgs.python3Packages; [ pytest-runner pytestCheckHook pytest-timeout ];
|
||||
checkInputs = with pkgs.python3Packages; [pytestCheckHook pytest-timeout];
|
||||
|
||||
# migen/misoc version checks are broken with pyproject for some reason
|
||||
postPatch = ''
|
||||
@@ -88,22 +99,29 @@
|
||||
substituteInPlace setup.cfg --replace '--flake8' ""
|
||||
'';
|
||||
};
|
||||
binutils = { platform, target, zlib }: pkgs.stdenv.mkDerivation rec {
|
||||
basename = "binutils";
|
||||
version = "2.30";
|
||||
name = "${basename}-${platform}-${version}";
|
||||
src = pkgs.fetchurl {
|
||||
url = "https://ftp.gnu.org/gnu/binutils/binutils-${version}.tar.bz2";
|
||||
sha256 = "028cklfqaab24glva1ks2aqa1zxa6w6xmc8q34zs1sb7h22dxspg";
|
||||
binutils = {
|
||||
platform,
|
||||
target,
|
||||
zlib,
|
||||
}:
|
||||
pkgs.stdenv.mkDerivation rec {
|
||||
basename = "binutils";
|
||||
version = "2.30";
|
||||
name = "${basename}-${platform}-${version}";
|
||||
src = pkgs.fetchurl {
|
||||
url = "https://ftp.gnu.org/gnu/binutils/binutils-${version}.tar.bz2";
|
||||
sha256 = "028cklfqaab24glva1ks2aqa1zxa6w6xmc8q34zs1sb7h22dxspg";
|
||||
};
|
||||
configureFlags = ["--enable-shared" "--enable-deterministic-archives" "--target=${target}"];
|
||||
outputs = ["out" "info" "man"];
|
||||
depsBuildBuild = [pkgs.buildPackages.stdenv.cc];
|
||||
buildInputs = [zlib];
|
||||
enableParallelBuilding = true;
|
||||
};
|
||||
configureFlags =
|
||||
[ "--enable-shared" "--enable-deterministic-archives" "--target=${target}"];
|
||||
outputs = [ "out" "info" "man" ];
|
||||
depsBuildBuild = [ pkgs.buildPackages.stdenv.cc ];
|
||||
buildInputs = [ zlib ];
|
||||
enableParallelBuilding = true;
|
||||
binutils-arm = pkgs.callPackage binutils {
|
||||
platform = "arm";
|
||||
target = "armv7-unknown-linux-gnueabihf";
|
||||
};
|
||||
binutils-arm = pkgs.callPackage binutils { platform = "arm"; target = "armv7-unknown-linux-gnueabihf"; };
|
||||
|
||||
# FSBL configuration supplied by Vivado 2020.1 for these boards:
|
||||
fsblTargets = ["zc702" "zc706" "zed"];
|
||||
@@ -111,76 +129,97 @@
|
||||
# kasli-soc satellite variants
|
||||
"satellite"
|
||||
# zc706 satellite variants
|
||||
"nist_clock_satellite" "nist_qc2_satellite" "acpki_nist_clock_satellite" "acpki_nist_qc2_satellite"
|
||||
"nist_clock_satellite_100mhz" "nist_qc2_satellite_100mhz" "acpki_nist_clock_satellite_100mhz" "acpki_nist_qc2_satellite_100mhz"
|
||||
"nist_clock_satellite"
|
||||
"nist_qc2_satellite"
|
||||
"acpki_nist_clock_satellite"
|
||||
"acpki_nist_qc2_satellite"
|
||||
"nist_clock_satellite_100mhz"
|
||||
"nist_qc2_satellite_100mhz"
|
||||
"acpki_nist_clock_satellite_100mhz"
|
||||
"acpki_nist_qc2_satellite_100mhz"
|
||||
];
|
||||
board-package-set = { target, variant, json ? null }: let
|
||||
board-package-set = {
|
||||
target,
|
||||
variant,
|
||||
json ? null,
|
||||
}: let
|
||||
szl = zynqpkgs."${target}-szl";
|
||||
fsbl = zynqpkgs."${target}-fsbl";
|
||||
fwtype = if builtins.elem variant sat_variants then "satman" else "runtime";
|
||||
fwtype =
|
||||
if builtins.elem variant sat_variants
|
||||
then "satman"
|
||||
else "runtime";
|
||||
|
||||
firmware = rustPlatform.buildRustPackage rec {
|
||||
firmware = naerskLib.buildPackage rec {
|
||||
name = "firmware";
|
||||
src = ./src;
|
||||
cargoLock = {
|
||||
lockFile = src/Cargo.lock;
|
||||
outputHashes = {
|
||||
"tar-no-std-0.1.8" = "sha256-xm17108v4smXOqxdLvHl9CxTCJslmeogjm4Y87IXFuM=";
|
||||
};
|
||||
};
|
||||
additionalCargoLock = "${rust}/lib/rustlib/src/rust/library/Cargo.lock";
|
||||
singleStep = true;
|
||||
|
||||
nativeBuildInputs = [
|
||||
pkgs.gnumake
|
||||
(pkgs.python3.withPackages(ps: [ ps.jsonschema artiqpkgs.migen migen-axi artiqpkgs.misoc artiqpkgs.artiq ]))
|
||||
zynqpkgs.cargo-xbuild
|
||||
llvmPackages_11.llvm
|
||||
llvmPackages_11.clang-unwrapped
|
||||
(pkgs.python3.withPackages (ps: [artiqpkgs.migen migen-axi artiqpkgs.misoc artiqpkgs.artiq-build]))
|
||||
pkgs.llvmPackages_20.llvm
|
||||
pkgs.llvmPackages_20.clang-unwrapped
|
||||
];
|
||||
buildPhase = ''
|
||||
export XARGO_RUST_SRC="${rust}/lib/rustlib/src/rust/library"
|
||||
export CLANG_EXTRA_INCLUDE_DIR="${llvmPackages_11.clang-unwrapped.lib}/lib/clang/11.1.0/include"
|
||||
export CARGO_HOME=$(mktemp -d cargo-home.XXX)
|
||||
export ZYNQ_RS=${zynq-rs}
|
||||
make TARGET=${target} GWARGS="${if json == null then "-V ${variant}" else json}" ${fwtype}
|
||||
'';
|
||||
|
||||
installPhase = ''
|
||||
mkdir -p $out $out/nix-support
|
||||
cp ../build/${fwtype}.bin $out/${fwtype}.bin
|
||||
cp ../build/firmware/armv7-none-eabihf/release/${fwtype} $out/${fwtype}.elf
|
||||
echo file binary-dist $out/${fwtype}.bin >> $out/nix-support/hydra-build-products
|
||||
echo file binary-dist $out/${fwtype}.elf >> $out/nix-support/hydra-build-products
|
||||
'';
|
||||
overrideMain = _: {
|
||||
buildPhase = ''
|
||||
export ZYNQ_REV=${zynqRev}
|
||||
export CLANG_EXTRA_INCLUDE_DIR="${pkgs.llvmPackages_20.clang-unwrapped.lib}/lib/clang/20/include"
|
||||
export ZYNQ_RS=${zynq-rs}
|
||||
make TARGET=${target} GWARGS="${
|
||||
if json == null
|
||||
then "-V ${variant}"
|
||||
else json
|
||||
}" ${fwtype}
|
||||
'';
|
||||
|
||||
doCheck = false;
|
||||
dontFixup = true;
|
||||
auditable = false;
|
||||
installPhase = ''
|
||||
mkdir -p $out $out/nix-support
|
||||
cp ../build/${fwtype}.bin $out/${fwtype}.bin
|
||||
cp ../build/firmware/armv7-none-eabihf/release/${fwtype} $out/${fwtype}.elf
|
||||
echo file binary-dist $out/${fwtype}.bin >> $out/nix-support/hydra-build-products
|
||||
echo file binary-dist $out/${fwtype}.elf >> $out/nix-support/hydra-build-products
|
||||
'';
|
||||
|
||||
doCheck = false;
|
||||
dontFixup = true;
|
||||
};
|
||||
};
|
||||
gateware = pkgs.runCommand "${target}-${variant}-gateware"
|
||||
gateware =
|
||||
pkgs.runCommand "${target}-${variant}-gateware"
|
||||
{
|
||||
nativeBuildInputs = [
|
||||
(pkgs.python3.withPackages(ps: [ ps.jsonschema artiqpkgs.migen migen-axi artiqpkgs.misoc artiqpkgs.artiq ]))
|
||||
nativeBuildInputs = [
|
||||
(pkgs.python3.withPackages (ps: [artiqpkgs.migen migen-axi artiqpkgs.misoc artiqpkgs.artiq-build]))
|
||||
artiqpkgs.vivado
|
||||
];
|
||||
}
|
||||
''
|
||||
python ${./src/gateware}/${target}.py -g build ${if json == null then "-V ${variant}" else json}
|
||||
export ZYNQ_REV=${zynqRev}
|
||||
python ${./src/gateware}/${target}.py -g build ${
|
||||
if json == null
|
||||
then "-V ${variant}"
|
||||
else json
|
||||
}
|
||||
mkdir -p $out $out/nix-support
|
||||
cp build/top.bit $out
|
||||
echo file binary-dist $out/top.bit >> $out/nix-support/hydra-build-products
|
||||
'';
|
||||
|
||||
# SZL startup
|
||||
jtag = pkgs.runCommand "${target}-${variant}-jtag" {}
|
||||
jtag =
|
||||
pkgs.runCommand "${target}-${variant}-jtag" {}
|
||||
''
|
||||
mkdir $out
|
||||
ln -s ${szl}/szl.elf $out
|
||||
ln -s ${firmware}/${fwtype}.bin $out
|
||||
ln -s ${gateware}/top.bit $out
|
||||
'';
|
||||
sd = pkgs.runCommand "${target}-${variant}-sd"
|
||||
sd =
|
||||
pkgs.runCommand "${target}-${variant}-sd"
|
||||
{
|
||||
buildInputs = [ zynqpkgs.mkbootimage ];
|
||||
buildInputs = [zynqpkgs.mkbootimage];
|
||||
}
|
||||
''
|
||||
# Do not use "long" paths in boot.bif, because embedded developers
|
||||
@@ -195,7 +234,7 @@
|
||||
{
|
||||
[bootloader]szl.elf
|
||||
top.bit
|
||||
${fwtype}.elf
|
||||
[elf_use_ph]${fwtype}.elf
|
||||
}
|
||||
EOF
|
||||
mkdir $out $out/nix-support
|
||||
@@ -204,9 +243,10 @@
|
||||
'';
|
||||
|
||||
# FSBL startup
|
||||
fsbl-sd = pkgs.runCommand "${target}-${variant}-fsbl-sd"
|
||||
fsbl-sd =
|
||||
pkgs.runCommand "${target}-${variant}-fsbl-sd"
|
||||
{
|
||||
buildInputs = [ zynqpkgs.mkbootimage ];
|
||||
buildInputs = [zynqpkgs.mkbootimage];
|
||||
}
|
||||
''
|
||||
bifdir=`mktemp -d`
|
||||
@@ -226,33 +266,34 @@
|
||||
mkbootimage boot.bif $out/boot.bin
|
||||
echo file binary-dist $out/boot.bin >> $out/nix-support/hydra-build-products
|
||||
'';
|
||||
in {
|
||||
"${target}-${variant}-firmware" = firmware;
|
||||
"${target}-${variant}-gateware" = gateware;
|
||||
"${target}-${variant}-jtag" = jtag;
|
||||
"${target}-${variant}-sd" = sd;
|
||||
} // (
|
||||
if builtins.elem target fsblTargets
|
||||
then {
|
||||
"${target}-${variant}-fsbl-sd" = fsbl-sd;
|
||||
in
|
||||
{
|
||||
"${target}-${variant}-firmware" = firmware;
|
||||
"${target}-${variant}-gateware" = gateware;
|
||||
"${target}-${variant}-jtag" = jtag;
|
||||
"${target}-${variant}-sd" = sd;
|
||||
}
|
||||
else {}
|
||||
);
|
||||
// (
|
||||
if builtins.elem target fsblTargets
|
||||
then {
|
||||
"${target}-${variant}-fsbl-sd" = fsbl-sd;
|
||||
}
|
||||
else {}
|
||||
);
|
||||
|
||||
gateware-sim = pkgs.stdenv.mkDerivation {
|
||||
name = "gateware-sim";
|
||||
|
||||
nativeBuildInputs = [
|
||||
(pkgs.python3.withPackages(ps: [ artiqpkgs.migen migen-axi artiqpkgs.artiq ]))
|
||||
|
||||
nativeBuildInputs = [
|
||||
(pkgs.python3.withPackages (ps: [artiqpkgs.migen migen-axi artiqpkgs.artiq-build]))
|
||||
];
|
||||
|
||||
phases = [ "buildPhase" ];
|
||||
phases = ["buildPhase"];
|
||||
|
||||
buildPhase =
|
||||
''
|
||||
buildPhase = ''
|
||||
python -m unittest discover ${self}/src/gateware -v
|
||||
touch $out
|
||||
'';
|
||||
'';
|
||||
};
|
||||
|
||||
fmt-check = pkgs.stdenvNoCC.mkDerivation {
|
||||
@@ -260,35 +301,47 @@
|
||||
|
||||
src = ./src;
|
||||
|
||||
nativeBuildInputs = [ rust pkgs.gnumake ];
|
||||
nativeBuildInputs = [rust pkgs.gnumake];
|
||||
|
||||
phases = [ "unpackPhase" "buildPhase" ];
|
||||
phases = ["unpackPhase" "buildPhase"];
|
||||
|
||||
buildPhase =
|
||||
''
|
||||
buildPhase = ''
|
||||
export ZYNQ_RS=${zynq-rs}
|
||||
make manifests
|
||||
cargo fmt -- --check
|
||||
touch $out
|
||||
'';
|
||||
'';
|
||||
};
|
||||
|
||||
# for hitl-tests
|
||||
zc706-nist_qc2 = (board-package-set { target = "zc706"; variant = "nist_qc2"; });
|
||||
zc706-hitl-tests = pkgs.stdenv.mkDerivation {
|
||||
name = "zc706-hitl-tests";
|
||||
zc706-nist_qc2 = board-package-set {
|
||||
target = "zc706";
|
||||
variant = "nist_qc2";
|
||||
};
|
||||
zc706-acpki_nist_qc2 = board-package-set {
|
||||
target = "zc706";
|
||||
variant = "acpki_nist_qc2";
|
||||
};
|
||||
make-zc706-hitl-tests = { name, board-package, setup-commands ? ""}: pkgs.stdenv.mkDerivation {
|
||||
name = "zc706-hitl-tests-${name}";
|
||||
|
||||
__networked = true; # compatibility with old patched Nix
|
||||
__networked = true; # compatibility with old patched Nix
|
||||
# breaks hydra, https://github.com/NixOS/hydra/issues/1216
|
||||
#__impure = true; # Nix 2.8+
|
||||
|
||||
buildInputs = [
|
||||
pkgs.netcat pkgs.openssh pkgs.rsync artiqpkgs.artiq artiq-netboot zynqpkgs.zc706-szl
|
||||
pkgs.netcat
|
||||
pkgs.openssh
|
||||
pkgs.rsync
|
||||
artiqpkgs.artiq
|
||||
artiq-netboot
|
||||
zynqpkgs.zc706-szl
|
||||
];
|
||||
phases = [ "buildPhase" ];
|
||||
phases = ["buildPhase"];
|
||||
|
||||
buildPhase =
|
||||
''
|
||||
buildPhase = ''
|
||||
${setup-commands}
|
||||
|
||||
export NIX_SSHOPTS="-F /dev/null -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o LogLevel=ERROR -i /opt/hydra_id_ed25519"
|
||||
LOCKCTL=$(mktemp -d)
|
||||
mkfifo $LOCKCTL/lockctl
|
||||
@@ -314,7 +367,7 @@
|
||||
export USER=hydra
|
||||
export OPENOCD_ZYNQ=${zynq-rs}/openocd
|
||||
export SZL=${zynqpkgs.szl}
|
||||
bash ${self}/remote_run.sh -h rpi-4 -o "$NIX_SSHOPTS" -d ${zc706-nist_qc2.zc706-nist_qc2-jtag}
|
||||
bash ${self}/remote_run.sh -h rpi-4 -o "$NIX_SSHOPTS" -d ${board-package}
|
||||
|
||||
echo Waiting for the firmware to boot...
|
||||
sleep 15
|
||||
@@ -334,64 +387,163 @@
|
||||
(echo b; sleep 5) | nc -N -w6 192.168.1.31 3131
|
||||
echo Board powered off
|
||||
)
|
||||
'';
|
||||
'';
|
||||
};
|
||||
zc706-hitl-tests = make-zc706-hitl-tests {
|
||||
name = "nist_qc2";
|
||||
board-package = zc706-nist_qc2.zc706-nist_qc2-jtag;
|
||||
};
|
||||
zc706-acpki-hitl-tests = make-zc706-hitl-tests {
|
||||
name = "acpki_nist_qc2";
|
||||
board-package = zc706-acpki_nist_qc2.zc706-acpki_nist_qc2-jtag;
|
||||
setup-commands = "export ENABLE_ACPKI=1";
|
||||
};
|
||||
|
||||
in rec {
|
||||
packages.x86_64-linux =
|
||||
{
|
||||
inherit fastnumbers artiq-netboot ramda migen-axi binutils-arm;
|
||||
} //
|
||||
(board-package-set { target = "zc706"; variant = "nist_clock"; }) //
|
||||
(board-package-set { target = "zc706"; variant = "nist_clock_master"; }) //
|
||||
(board-package-set { target = "zc706"; variant = "nist_clock_master_100mhz"; }) //
|
||||
(board-package-set { target = "zc706"; variant = "nist_clock_satellite"; }) //
|
||||
(board-package-set { target = "zc706"; variant = "nist_clock_satellite_100mhz"; }) //
|
||||
(board-package-set { target = "zc706"; variant = "nist_qc2"; }) //
|
||||
(board-package-set { target = "zc706"; variant = "nist_qc2_master"; }) //
|
||||
(board-package-set { target = "zc706"; variant = "nist_qc2_master_100mhz"; }) //
|
||||
(board-package-set { target = "zc706"; variant = "nist_qc2_satellite"; }) //
|
||||
(board-package-set { target = "zc706"; variant = "nist_qc2_satellite_100mhz"; }) //
|
||||
(board-package-set { target = "zc706"; variant = "acpki_nist_clock"; }) //
|
||||
(board-package-set { target = "zc706"; variant = "acpki_nist_clock_master"; }) //
|
||||
(board-package-set { target = "zc706"; variant = "acpki_nist_clock_master_100mhz"; }) //
|
||||
(board-package-set { target = "zc706"; variant = "acpki_nist_clock_satellite"; }) //
|
||||
(board-package-set { target = "zc706"; variant = "acpki_nist_clock_satellite_100mhz"; }) //
|
||||
(board-package-set { target = "zc706"; variant = "acpki_nist_qc2"; }) //
|
||||
(board-package-set { target = "zc706"; variant = "acpki_nist_qc2_master"; }) //
|
||||
(board-package-set { target = "zc706"; variant = "acpki_nist_qc2_master_100mhz"; }) //
|
||||
(board-package-set { target = "zc706"; variant = "acpki_nist_qc2_satellite"; }) //
|
||||
(board-package-set { target = "zc706"; variant = "acpki_nist_qc2_satellite_100mhz"; }) //
|
||||
(board-package-set { target = "kasli_soc"; variant = "demo"; json = ./demo.json; }) //
|
||||
(board-package-set { target = "kasli_soc"; variant = "master"; json = ./kasli-soc-master.json; }) //
|
||||
(board-package-set { target = "kasli_soc"; variant = "satellite"; json = ./kasli-soc-satellite.json; });
|
||||
}
|
||||
// (board-package-set {
|
||||
target = "zc706";
|
||||
variant = "cxp_4r_fmc";
|
||||
})
|
||||
// (board-package-set {
|
||||
target = "zc706";
|
||||
variant = "nist_clock";
|
||||
})
|
||||
// (board-package-set {
|
||||
target = "zc706";
|
||||
variant = "nist_clock_master";
|
||||
})
|
||||
// (board-package-set {
|
||||
target = "zc706";
|
||||
variant = "nist_clock_master_100mhz";
|
||||
})
|
||||
// (board-package-set {
|
||||
target = "zc706";
|
||||
variant = "nist_clock_satellite";
|
||||
})
|
||||
// (board-package-set {
|
||||
target = "zc706";
|
||||
variant = "nist_clock_satellite_100mhz";
|
||||
})
|
||||
// (board-package-set {
|
||||
target = "zc706";
|
||||
variant = "nist_qc2";
|
||||
})
|
||||
// (board-package-set {
|
||||
target = "zc706";
|
||||
variant = "nist_qc2_master";
|
||||
})
|
||||
// (board-package-set {
|
||||
target = "zc706";
|
||||
variant = "nist_qc2_master_100mhz";
|
||||
})
|
||||
// (board-package-set {
|
||||
target = "zc706";
|
||||
variant = "nist_qc2_satellite";
|
||||
})
|
||||
// (board-package-set {
|
||||
target = "zc706";
|
||||
variant = "nist_qc2_satellite_100mhz";
|
||||
})
|
||||
// (board-package-set {
|
||||
target = "zc706";
|
||||
variant = "acpki_nist_clock";
|
||||
})
|
||||
// (board-package-set {
|
||||
target = "zc706";
|
||||
variant = "acpki_nist_clock_master";
|
||||
})
|
||||
// (board-package-set {
|
||||
target = "zc706";
|
||||
variant = "acpki_nist_clock_master_100mhz";
|
||||
})
|
||||
// (board-package-set {
|
||||
target = "zc706";
|
||||
variant = "acpki_nist_clock_satellite";
|
||||
})
|
||||
// (board-package-set {
|
||||
target = "zc706";
|
||||
variant = "acpki_nist_clock_satellite_100mhz";
|
||||
})
|
||||
// (board-package-set {
|
||||
target = "zc706";
|
||||
variant = "acpki_nist_qc2";
|
||||
})
|
||||
// (board-package-set {
|
||||
target = "zc706";
|
||||
variant = "acpki_nist_qc2_master";
|
||||
})
|
||||
// (board-package-set {
|
||||
target = "zc706";
|
||||
variant = "acpki_nist_qc2_master_100mhz";
|
||||
})
|
||||
// (board-package-set {
|
||||
target = "zc706";
|
||||
variant = "acpki_nist_qc2_satellite";
|
||||
})
|
||||
// (board-package-set {
|
||||
target = "zc706";
|
||||
variant = "acpki_nist_qc2_satellite_100mhz";
|
||||
})
|
||||
// (board-package-set {
|
||||
target = "kasli_soc";
|
||||
variant = "demo";
|
||||
json = ./demo.json;
|
||||
})
|
||||
// (board-package-set {
|
||||
target = "kasli_soc";
|
||||
variant = "master";
|
||||
json = ./kasli-soc-master.json;
|
||||
})
|
||||
// (board-package-set {
|
||||
target = "kasli_soc";
|
||||
variant = "satellite";
|
||||
json = ./kasli-soc-satellite.json;
|
||||
})
|
||||
// (board-package-set {
|
||||
target = "ebaz4205";
|
||||
variant = "base";
|
||||
});
|
||||
|
||||
hydraJobs = packages.x86_64-linux // { inherit zc706-hitl-tests; inherit gateware-sim; inherit fmt-check; };
|
||||
hydraJobs =
|
||||
packages.x86_64-linux
|
||||
// {
|
||||
inherit zc706-hitl-tests;
|
||||
inherit zc706-acpki-hitl-tests;
|
||||
inherit gateware-sim;
|
||||
inherit fmt-check;
|
||||
};
|
||||
|
||||
formatter.x86_64-linux = pkgs.alejandra;
|
||||
|
||||
devShell.x86_64-linux = pkgs.mkShell {
|
||||
name = "artiq-zynq-dev-shell";
|
||||
buildInputs = with pkgs; [
|
||||
rust
|
||||
llvmPackages_11.llvm
|
||||
llvmPackages_11.clang-unwrapped
|
||||
llvmPackages_20.llvm
|
||||
llvmPackages_20.clang-unwrapped
|
||||
gnumake
|
||||
cacert
|
||||
zynqpkgs.cargo-xbuild
|
||||
zynqpkgs.mkbootimage
|
||||
openocd
|
||||
openssh rsync
|
||||
(python3.withPackages(ps: (with artiqpkgs; [ migen migen-axi misoc artiq artiq-netboot ps.jsonschema ps.pyftdi ])))
|
||||
openocd
|
||||
openssh
|
||||
rsync
|
||||
(python3.withPackages (ps: (with artiqpkgs; [migen migen-axi misoc artiq artiq-netboot ps.jsonschema ps.pyftdi])))
|
||||
artiqpkgs.artiq
|
||||
artiqpkgs.vivado
|
||||
binutils-arm
|
||||
pre-commit
|
||||
];
|
||||
XARGO_RUST_SRC = "${rust}/lib/rustlib/src/rust/library";
|
||||
CLANG_EXTRA_INCLUDE_DIR = "${llvmPackages_11.clang-unwrapped.lib}/lib/clang/11.1.0/include";
|
||||
ZYNQ_REV = "${zynqRev}";
|
||||
CLANG_EXTRA_INCLUDE_DIR = "${pkgs.llvmPackages_20.clang-unwrapped.lib}/lib/clang/20/include";
|
||||
ZYNQ_RS = "${zynq-rs}";
|
||||
OPENOCD_ZYNQ = "${zynq-rs}/openocd";
|
||||
SZL = "${zynqpkgs.szl}";
|
||||
};
|
||||
|
||||
makeArtiqZynqPackage = board-package-set;
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@@ -2,8 +2,11 @@
|
||||
"target": "kasli_soc",
|
||||
"variant": "master",
|
||||
"hw_rev": "v1.0",
|
||||
"base": "master",
|
||||
"drtio_role": "master",
|
||||
"peripherals": [
|
||||
{
|
||||
"type": "coaxpress_sfp"
|
||||
},
|
||||
{
|
||||
"type": "grabber",
|
||||
"ports": [0]
|
||||
|
||||
@@ -2,8 +2,11 @@
|
||||
"target": "kasli_soc",
|
||||
"variant": "satellite",
|
||||
"hw_rev": "v1.0",
|
||||
"base": "satellite",
|
||||
"drtio_role": "satellite",
|
||||
"peripherals": [
|
||||
{
|
||||
"type": "coaxpress_sfp"
|
||||
},
|
||||
{
|
||||
"type": "grabber",
|
||||
"ports": [0]
|
||||
|
||||
@@ -13,7 +13,7 @@ if [ -z "$SZL" ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
target_host="rpi-4.m-labs.hk"
|
||||
target_host="rpi-4"
|
||||
impure=0
|
||||
pure_dir="result"
|
||||
impure_dir="build"
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
[target.armv7-none-eabihf]
|
||||
rustflags = [
|
||||
"-C", "link-arg=-Tlink.x",
|
||||
"-C", "target-feature=a9,armv7-a,neon",
|
||||
"-C", "link-arg=--no-check-sections", # required for overlapping sections
|
||||
"-C", "target-cpu=cortex-a9",
|
||||
]
|
||||
|
||||
[build]
|
||||
target = "armv7-none-eabihf.json"
|
||||
|
||||
[unstable]
|
||||
build-std = ["core", "alloc", "compiler_builtins"]
|
||||
32
src/.clang-format
Normal file
32
src/.clang-format
Normal file
@@ -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
|
||||
1
src/.clippy.toml
Normal file
1
src/.clippy.toml
Normal file
@@ -0,0 +1 @@
|
||||
doc-valid-idents = ["CPython", "NumPy", ".."]
|
||||
32
src/.pre-commit-config.yaml
Normal file
32
src/.pre-commit-config.yaml
Normal file
@@ -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]
|
||||
188
src/Cargo.lock
generated
188
src/Cargo.lock
generated
@@ -1,6 +1,15 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "approx"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "arrayvec"
|
||||
@@ -10,9 +19,9 @@ checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711"
|
||||
|
||||
[[package]]
|
||||
name = "async-recursion"
|
||||
version = "0.3.2"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d7d78656ba01f1b93024b7c3a0467f1608e4be67d725749fdcd7d2c7678fd7a2"
|
||||
checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -49,9 +58,9 @@ version = "0.0.0"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.4.3"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
|
||||
checksum = "60f0b0d4c0a382d2734228fd12b5a6b5dac185c60e938026fd31b265b94f9bd2"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
@@ -71,20 +80,10 @@ version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "compiler_builtins"
|
||||
version = "0.1.39"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3748f82c7d366a0b4950257d19db685d4958d2fa27c6d164a3f069fec42b748b"
|
||||
|
||||
[[package]]
|
||||
name = "core_io"
|
||||
version = "0.1.20210325"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97f8932064288cc79feb4d343a399d353a6f6f001e586ece47fe518a9e8507df"
|
||||
dependencies = [
|
||||
"rustc_version",
|
||||
]
|
||||
version = "0.1.0"
|
||||
source = "git+https://git.m-labs.hk/M-Labs/rs-core_io.git?rev=e9d3edf027#e9d3edf0272502b0dd6c26e8a4869c2912657615"
|
||||
|
||||
[[package]]
|
||||
name = "crc"
|
||||
@@ -106,7 +105,6 @@ name = "dwarf"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.10",
|
||||
"compiler_builtins",
|
||||
"cslice",
|
||||
"libc",
|
||||
"unwind",
|
||||
@@ -132,9 +130,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "fatfs"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e18f80a87439240dac45d927fd8f8081b6f1e34c03e97271189fa8a8c2e96c8f"
|
||||
version = "0.3.6"
|
||||
source = "git+https://git.m-labs.hk/M-Labs/rust-fatfs.git?rev=4b5e420084#4b5e420084fd1c4a9c105680b687523909b6469c"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"byteorder",
|
||||
@@ -144,9 +141,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "futures"
|
||||
version = "0.3.25"
|
||||
version = "0.3.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38390104763dc37a5145a53c29c63c1290b5d316d6086ec32c293f6736051bb0"
|
||||
checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
@@ -158,9 +155,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "futures-channel"
|
||||
version = "0.3.25"
|
||||
version = "0.3.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "52ba265a92256105f45b719605a571ffe2d1f0fea3807304b522c1d778f79eed"
|
||||
checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
@@ -168,21 +165,21 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "futures-core"
|
||||
version = "0.3.25"
|
||||
version = "0.3.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "04909a7a7e4633ae6c4a9ab280aeb86da1236243a77b694a49eacd659a4bd3ac"
|
||||
checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e"
|
||||
|
||||
[[package]]
|
||||
name = "futures-io"
|
||||
version = "0.3.25"
|
||||
version = "0.3.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "00f5fb52a06bdcadeb54e8d3671f8888a39697dcb0b81b23b55174030427f4eb"
|
||||
checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6"
|
||||
|
||||
[[package]]
|
||||
name = "futures-macro"
|
||||
version = "0.3.25"
|
||||
version = "0.3.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bdfb8ce053d86b91919aad980c220b1fb8401a9394410e1c289ed7e66b61835d"
|
||||
checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -191,21 +188,21 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "futures-sink"
|
||||
version = "0.3.25"
|
||||
version = "0.3.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "39c15cf1a4aa79df40f1bb462fb39676d0ad9e366c2a33b590d7c66f4f81fcf9"
|
||||
checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7"
|
||||
|
||||
[[package]]
|
||||
name = "futures-task"
|
||||
version = "0.3.25"
|
||||
version = "0.3.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2ffb393ac5d9a6eaa9d3fdf37ae2776656b706e200c8e16b1bdb227f5198e6ea"
|
||||
checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988"
|
||||
|
||||
[[package]]
|
||||
name = "futures-util"
|
||||
version = "0.3.25"
|
||||
version = "0.3.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "197676987abd2f9cadff84926f410af1c183608d36641465df73ae8211dc65d6"
|
||||
checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-macro",
|
||||
@@ -246,7 +243,7 @@ dependencies = [
|
||||
"libsupport_zynq",
|
||||
"log",
|
||||
"log_buffer",
|
||||
"nb 0.1.3",
|
||||
"nalgebra",
|
||||
"unwind",
|
||||
"vcell",
|
||||
"void",
|
||||
@@ -259,7 +256,6 @@ dependencies = [
|
||||
"embedded-hal",
|
||||
"libcortex_a9",
|
||||
"nb 1.0.0",
|
||||
"pin-utils",
|
||||
"smoltcp",
|
||||
]
|
||||
|
||||
@@ -268,6 +264,7 @@ name = "libboard_artiq"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"build_zynq",
|
||||
"byteorder",
|
||||
"core_io",
|
||||
"crc",
|
||||
"embedded-hal",
|
||||
@@ -277,7 +274,6 @@ dependencies = [
|
||||
"libconfig",
|
||||
"libcortex_a9",
|
||||
"libregister",
|
||||
"libsupport_zynq",
|
||||
"log",
|
||||
"log_buffer",
|
||||
"nb 1.0.0",
|
||||
@@ -315,6 +311,7 @@ dependencies = [
|
||||
"core_io",
|
||||
"fatfs",
|
||||
"libboard_zynq",
|
||||
"libcortex_a9",
|
||||
"log",
|
||||
]
|
||||
|
||||
@@ -347,7 +344,6 @@ name = "libsupport_zynq"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"compiler_builtins",
|
||||
"libboard_zynq",
|
||||
"libcortex_a9",
|
||||
"libregister",
|
||||
@@ -363,9 +359,9 @@ checksum = "822add9edb1860698b79522510da17bef885171f75aa395cff099d770c609c24"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.17"
|
||||
version = "0.4.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
|
||||
checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
]
|
||||
@@ -382,6 +378,19 @@ version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c75de51135344a4f8ed3cfe2720dc27736f7711989703a0b43aadf3753c55577"
|
||||
|
||||
[[package]]
|
||||
name = "nalgebra"
|
||||
version = "0.32.6"
|
||||
source = "git+https://git.m-labs.hk/M-Labs/nalgebra.git?rev=ad42410ab0#ad42410ab0abb014229e3ff6bc6ccd39ca92d5d1"
|
||||
dependencies = [
|
||||
"approx",
|
||||
"num-complex",
|
||||
"num-rational",
|
||||
"num-traits",
|
||||
"simba",
|
||||
"typenum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nb"
|
||||
version = "0.1.3"
|
||||
@@ -398,10 +407,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "546c37ac5d9e56f55e73b677106873d9d9f5190605e41a856503623648488cae"
|
||||
|
||||
[[package]]
|
||||
name = "num-derive"
|
||||
version = "0.3.3"
|
||||
name = "num-complex"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d"
|
||||
checksum = "26873667bbbb7c5182d4a37c1add32cdf09f841af72da53318fdb81543c15085"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-derive"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -409,14 +427,41 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.15"
|
||||
name = "num-integer"
|
||||
version = "0.1.46"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
|
||||
checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-rational"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d41702bd167c2df5520b384281bc111a4b5efcf7fbc4c9c222c815b07e0a6a6a"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"libm",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "paste"
|
||||
version = "1.0.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.9"
|
||||
@@ -431,18 +476,18 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.43"
|
||||
version = "1.0.93"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab"
|
||||
checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.21"
|
||||
version = "1.0.38"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179"
|
||||
checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
@@ -461,6 +506,7 @@ dependencies = [
|
||||
"build_zynq",
|
||||
"byteorder",
|
||||
"core_io",
|
||||
"crc",
|
||||
"cslice",
|
||||
"dwarf",
|
||||
"dyld",
|
||||
@@ -478,6 +524,7 @@ dependencies = [
|
||||
"libsupport_zynq",
|
||||
"log",
|
||||
"log_buffer",
|
||||
"nb 0.1.3",
|
||||
"num-derive",
|
||||
"num-traits",
|
||||
"tar-no-std",
|
||||
@@ -486,21 +533,15 @@ dependencies = [
|
||||
"void",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc_version"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c5f5376ea5e30ce23c03eb77cbe4962b988deead10910c372b226388b594c084"
|
||||
dependencies = [
|
||||
"semver",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "satman"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"async-recursion",
|
||||
"build_zynq",
|
||||
"byteorder",
|
||||
"core_io",
|
||||
"crc",
|
||||
"cslice",
|
||||
"embedded-hal",
|
||||
"io",
|
||||
@@ -518,10 +559,16 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "0.1.20"
|
||||
name = "simba"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d4f410fedcf71af0345d7607d246e7ad15faaadd49d240ee3b24e5dc21a820ac"
|
||||
checksum = "50582927ed6f77e4ac020c057f37a268fc6aebc29225050365aacbb9deeeddc4"
|
||||
dependencies = [
|
||||
"approx",
|
||||
"num-complex",
|
||||
"num-traits",
|
||||
"paste",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smoltcp"
|
||||
@@ -536,9 +583,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.101"
|
||||
version = "2.0.98"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e90cde112c4b9690b8cbe810cba9ddd8bc1d7472e2cae317b69e9438c1cba7d2"
|
||||
checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -555,6 +602,12 @@ dependencies = [
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.5"
|
||||
@@ -567,7 +620,6 @@ version = "0.0.0"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"cfg-if 0.1.10",
|
||||
"compiler_builtins",
|
||||
"libc",
|
||||
]
|
||||
|
||||
|
||||
14
src/Makefile
14
src/Makefile
@@ -21,20 +21,18 @@ manifests: $(manifests)
|
||||
python gateware/$(TARGET).py -r ../build/pl.rs -c ../build/rustc-cfg -m ../build/mem.rs $(GWARGS)
|
||||
|
||||
../build/firmware/armv7-none-eabihf/release/runtime: ../build/pl.rs ../build/rustc-cfg ../build/mem.rs $(manifests) $(shell find . -type f -not -name Cargo.toml -print)
|
||||
cd runtime && \
|
||||
XBUILD_SYSROOT_PATH=`pwd`/../../build/sysroot \
|
||||
cargo xbuild --release \
|
||||
--target-dir ../../build/firmware \
|
||||
cargo build --release \
|
||||
-p runtime \
|
||||
--target-dir ../build/firmware \
|
||||
--no-default-features --features=target_$(TARGET)
|
||||
|
||||
../build/runtime.bin: ../build/firmware/armv7-none-eabihf/release/runtime
|
||||
llvm-objcopy -O binary ../build/firmware/armv7-none-eabihf/release/runtime ../build/runtime.bin
|
||||
|
||||
../build/firmware/armv7-none-eabihf/release/satman: ../build/pl.rs ../build/rustc-cfg ../build/mem.rs $(manifests) $(shell find . -type f -not -name Cargo.toml -print)
|
||||
cd satman && \
|
||||
XBUILD_SYSROOT_PATH=`pwd`/../../build/sysroot \
|
||||
cargo xbuild --release \
|
||||
--target-dir ../../build/firmware \
|
||||
cargo build --release \
|
||||
-p satman \
|
||||
--target-dir ../build/firmware \
|
||||
--no-default-features --features=target_$(TARGET)
|
||||
|
||||
../build/satman.bin: ../build/firmware/armv7-none-eabihf/release/satman
|
||||
|
||||
@@ -1,30 +1,20 @@
|
||||
{
|
||||
"abi-blacklist": [
|
||||
"stdcall",
|
||||
"fastcall",
|
||||
"vectorcall",
|
||||
"thiscall",
|
||||
"win64",
|
||||
"sysv64"
|
||||
],
|
||||
"arch": "arm",
|
||||
"data-layout": "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64",
|
||||
"emit-debug-gdb-scripts": false,
|
||||
"env": "",
|
||||
"executables": true,
|
||||
"features": "+v7,+vfp3,-d32,+thumb2,-neon",
|
||||
"is-builtin": false,
|
||||
"features": "+v7,+vfp3,-d32,+thumb2,+neon,+a9,+armv7-a",
|
||||
"linker": "rust-lld",
|
||||
"linker-flavor": "ld.lld",
|
||||
"llvm-target": "armv7-unknown-none-eabihf",
|
||||
"llvm-floatabi": "hard",
|
||||
"max-atomic-width": 32,
|
||||
"os": "none",
|
||||
"panic-strategy": "abort",
|
||||
"requires-uwtable": true,
|
||||
"force-unwind-tables": "yes",
|
||||
"relocation-model": "static",
|
||||
"target-c-int-width": "32",
|
||||
"target-endian": "little",
|
||||
"target-pointer-width": "32",
|
||||
"vendor": ""
|
||||
"target-pointer-width": "32"
|
||||
}
|
||||
|
||||
@@ -7,22 +7,28 @@ from misoc.interconnect.csr import *
|
||||
|
||||
from artiq.gateware import rtio
|
||||
|
||||
OUT_BURST_LEN = 10
|
||||
IN_BURST_LEN = 4
|
||||
# Burst len defined as number of transfers (0 -> 1, 1 -> 2 ..)
|
||||
# thus equal to (64-bit) word count minus one
|
||||
FIRST_BURST_LEN = 12 - 1 # extra 2 words for meta
|
||||
OUT_BURST_LEN = 10 - 1
|
||||
IN_BURST_LEN = 3 - 1
|
||||
|
||||
RTIO_I_STATUS_WAIT_STATUS = 4
|
||||
RTIO_O_STATUS_WAIT = 1
|
||||
|
||||
BATCH_ENTRY_LEN = 80
|
||||
|
||||
class Engine(Module, AutoCSR):
|
||||
def __init__(self, bus, user):
|
||||
self.addr_base = CSRStorage(32)
|
||||
self.trig_count = CSRStatus(32)
|
||||
self.write_count = CSRStatus(32)
|
||||
self.addr_base = Signal(32)
|
||||
self.write_addr = Signal(32)
|
||||
|
||||
self.trigger_stb = Signal()
|
||||
|
||||
# Dout : Data received from CPU, output by DMA module
|
||||
# Din : Data driven into DMA module, written into CPU
|
||||
# When stb assert, index shows word being read/written, dout/din holds
|
||||
# data
|
||||
# When stb is asserted, index shows word being read/written,
|
||||
# dout/din holds data
|
||||
#
|
||||
# Cycle:
|
||||
# trigger_stb pulsed at start
|
||||
@@ -35,11 +41,10 @@ class Engine(Module, AutoCSR):
|
||||
self.din_ready = Signal()
|
||||
self.dout = Signal(64)
|
||||
self.din = Signal(64)
|
||||
self.dout_burst_len = Signal(4)
|
||||
|
||||
###
|
||||
|
||||
self.sync += If(self.trigger_stb, self.trig_count.status.eq(self.trig_count.status+1))
|
||||
|
||||
self.comb += [
|
||||
user.aruser.eq(0x1f),
|
||||
user.awuser.eq(0x1f)
|
||||
@@ -49,12 +54,12 @@ class Engine(Module, AutoCSR):
|
||||
|
||||
### Read
|
||||
self.comb += [
|
||||
ar.addr.eq(self.addr_base.storage),
|
||||
ar.addr.eq(self.addr_base),
|
||||
self.dout.eq(r.data),
|
||||
r.ready.eq(1),
|
||||
ar.burst.eq(axi.Burst.incr.value),
|
||||
ar.len.eq(OUT_BURST_LEN-1), # Number of transfers in burst (0->1 transfer, 1->2 transfers...)
|
||||
ar.size.eq(3), # Width of burst: 3 = 8 bytes = 64 bits
|
||||
ar.len.eq(self.dout_burst_len),
|
||||
ar.size.eq(3), # Width of burst: 3 = 8 bytes = 64 bits
|
||||
ar.cache.eq(0xf),
|
||||
]
|
||||
|
||||
@@ -86,22 +91,23 @@ class Engine(Module, AutoCSR):
|
||||
self.sync += [
|
||||
If(read_fsm.ongoing("IDLE"),
|
||||
self.dout_index.eq(0)
|
||||
).Else(If(r.valid & read_fsm.ongoing("READ"),
|
||||
self.dout_index.eq(self.dout_index+1)
|
||||
)
|
||||
).Elif(r.valid & read_fsm.ongoing("READ"),
|
||||
self.dout_index.eq(self.dout_index+1)
|
||||
)
|
||||
]
|
||||
|
||||
self.comb += self.dout_stb.eq(r.valid & r.ready)
|
||||
self.read_idle = Signal()
|
||||
self.comb += self.read_idle.eq(read_fsm.ongoing("IDLE"))
|
||||
|
||||
### Write
|
||||
self.comb += [
|
||||
w.data.eq(self.din),
|
||||
aw.addr.eq(self.addr_base.storage+96),
|
||||
aw.addr.eq(self.write_addr),
|
||||
w.strb.eq(0xff),
|
||||
aw.burst.eq(axi.Burst.incr.value),
|
||||
aw.len.eq(IN_BURST_LEN-1), # Number of transfers in burst minus 1
|
||||
aw.size.eq(3), # Width of burst: 3 = 8 bytes = 64 bits
|
||||
aw.len.eq(IN_BURST_LEN), # Number of transfers in burst minus 1
|
||||
aw.size.eq(3), # Width of burst: 3 = 8 bytes = 64 bits
|
||||
aw.cache.eq(0xf),
|
||||
b.ready.eq(1),
|
||||
]
|
||||
@@ -113,7 +119,7 @@ class Engine(Module, AutoCSR):
|
||||
aw.valid.eq(0),
|
||||
If(self.trigger_stb,
|
||||
aw.valid.eq(1),
|
||||
If(aw.ready, # assumes aw.ready is not randomly deasserted
|
||||
If(aw.ready, # assumes aw.ready is not deasserted from now on
|
||||
NextState("DATA_WAIT")
|
||||
).Else(
|
||||
NextState("AW_READY_WAIT")
|
||||
@@ -140,8 +146,6 @@ class Engine(Module, AutoCSR):
|
||||
)
|
||||
)
|
||||
|
||||
self.sync += If(w.ready & w.valid, self.write_count.status.eq(self.write_count.status+1))
|
||||
|
||||
self.sync += [
|
||||
If(write_fsm.ongoing("IDLE"),
|
||||
self.din_index.eq(0)
|
||||
@@ -150,18 +154,20 @@ class Engine(Module, AutoCSR):
|
||||
]
|
||||
|
||||
self.comb += [
|
||||
w.last.eq(0),
|
||||
If(self.din_index==aw.len, w.last.eq(1))
|
||||
w.last.eq(self.din_index==aw.len),
|
||||
self.din_stb.eq(w.valid & w.ready)
|
||||
]
|
||||
|
||||
self.comb += self.din_stb.eq(w.valid & w.ready)
|
||||
|
||||
|
||||
self.write_idle = Signal()
|
||||
self.comb += self.write_idle.eq(write_fsm.ongoing("IDLE"))
|
||||
|
||||
class KernelInitiator(Module, AutoCSR):
|
||||
def __init__(self, tsc, bus, user, evento):
|
||||
# Core is disabled upon reset to avoid spurious triggering if evento toggles from e.g. boot code.
|
||||
# Should be also reset between kernels (?)
|
||||
self.enable = CSRStorage()
|
||||
self.out_base = CSRStorage(32) # output data (to CRI)
|
||||
self.in_base = CSRStorage(32) # in data (RTIO reply)
|
||||
|
||||
self.counter = CSRStatus(64)
|
||||
self.counter_update = CSR()
|
||||
@@ -173,12 +179,22 @@ class KernelInitiator(Module, AutoCSR):
|
||||
|
||||
###
|
||||
|
||||
batch_en = Signal()
|
||||
|
||||
batch_offset = Signal.like(self.out_base.storage) # address offset
|
||||
batch_len = Signal(32)
|
||||
batch_ptr = Signal(32)
|
||||
batch_stb = Signal() # triggers the next event in the batch
|
||||
|
||||
evento_stb = Signal()
|
||||
evento_latched = Signal()
|
||||
evento_latched_d = Signal()
|
||||
self.specials += MultiReg(evento, evento_latched)
|
||||
self.sync += evento_latched_d.eq(evento_latched)
|
||||
self.comb += self.engine.trigger_stb.eq(self.enable.storage & (evento_latched != evento_latched_d))
|
||||
self.comb += [
|
||||
self.engine.trigger_stb.eq(self.enable.storage & ((evento_latched != evento_latched_d) | batch_stb)),
|
||||
self.engine.write_addr.eq(self.in_base.storage),
|
||||
]
|
||||
|
||||
cri = self.cri
|
||||
|
||||
@@ -186,77 +202,130 @@ class KernelInitiator(Module, AutoCSR):
|
||||
cmd_write = Signal()
|
||||
cmd_read = Signal()
|
||||
self.comb += [
|
||||
cmd_write.eq(cmd == 0),
|
||||
cmd_read.eq(cmd == 1)
|
||||
cmd_write.eq(batch_en | (cmd == 0)), # rtio output, forced in batch mode
|
||||
cmd_read.eq(~batch_en & (cmd == 1)), # rtio input, disallowed in batch mode
|
||||
]
|
||||
|
||||
out_len = Signal(8)
|
||||
dout_cases = {}
|
||||
dout_cases[0] = [
|
||||
cmd.eq(self.engine.dout[:8]),
|
||||
out_len.eq(self.engine.dout[8:16]),
|
||||
cri.chan_sel.eq(self.engine.dout[40:]),
|
||||
cri.o_address.eq(self.engine.dout[32:40])
|
||||
cmd.eq(self.engine.dout[:8]), # request_cmd: i8
|
||||
out_len.eq(self.engine.dout[8:16]), # data_width: i8
|
||||
# padding (2 bytes)
|
||||
cri.o_address.eq(self.engine.dout[32:40]), # request_target: i32
|
||||
cri.chan_sel.eq(self.engine.dout[40:]), # request_target cont.
|
||||
]
|
||||
for i in range(8):
|
||||
target = cri.o_data[i*64:(i+1)*64]
|
||||
dout_cases[0] += [If(i >= self.engine.dout[8:16], target.eq(0))]
|
||||
|
||||
dout_cases[1] = [
|
||||
cri.o_timestamp.eq(self.engine.dout),
|
||||
cri.i_timeout.eq(self.engine.dout)
|
||||
cri.o_timestamp.eq(self.engine.dout), # request_timestamp: i64
|
||||
cri.i_timeout.eq(self.engine.dout),
|
||||
]
|
||||
for i in range(8):
|
||||
target = cri.o_data[i*64:(i+1)*64]
|
||||
target = cri.o_data[i*64:(i+1)*64] # request_data: [i32; 16]
|
||||
dout_cases[i+2] = [target.eq(self.engine.dout)]
|
||||
|
||||
# first iteration has extra 8 bytes for metadata
|
||||
first_iter = Signal()
|
||||
self.sync += [
|
||||
cri.cmd.eq(rtio.cri.commands["nop"]),
|
||||
If(self.engine.dout_stb,
|
||||
Case(self.engine.dout_index, dout_cases),
|
||||
If(self.engine.dout_index == out_len + 2,
|
||||
If(cmd_write, cri.cmd.eq(rtio.cri.commands["write"])),
|
||||
If(cmd_read, cri.cmd.eq(rtio.cri.commands["read"]))
|
||||
)
|
||||
If(first_iter,
|
||||
# manual case for metadata
|
||||
If(self.engine.dout_index == 0,
|
||||
batch_len.eq(self.engine.dout[:32]),
|
||||
batch_en.eq(self.engine.dout[32:40] == 1),
|
||||
).Elif(self.engine.dout_index >= 2,
|
||||
Case(self.engine.dout_index-2, dout_cases)
|
||||
),
|
||||
If(self.engine.dout_index == out_len + 4,
|
||||
If(cmd_write, cri.cmd.eq(rtio.cri.commands["write"])),
|
||||
If(cmd_read, cri.cmd.eq(rtio.cri.commands["read"]))
|
||||
)
|
||||
).Else(
|
||||
Case(self.engine.dout_index, dout_cases),
|
||||
If(self.engine.dout_index == out_len + 2,
|
||||
If(cmd_write, cri.cmd.eq(rtio.cri.commands["write"])),
|
||||
If(cmd_read, cri.cmd.eq(rtio.cri.commands["read"]))
|
||||
)
|
||||
),
|
||||
)
|
||||
]
|
||||
|
||||
# If input event, wait for response before allow input data to be
|
||||
# sampled
|
||||
# TODO: If output, wait for wait flag clear
|
||||
RTIO_I_STATUS_WAIT_STATUS = 4
|
||||
RTIO_O_STATUS_WAIT = 1
|
||||
# If input event, wait for response before
|
||||
# allowing the input data to be sampled
|
||||
|
||||
self.submodules.fsm = fsm = FSM(reset_state="IDLE")
|
||||
|
||||
fsm.act("IDLE",
|
||||
If(self.engine.trigger_stb, NextState("WAIT_OUT_CYCLE"))
|
||||
If(self.engine.trigger_stb,
|
||||
NextState("FIRST_WAIT")),
|
||||
)
|
||||
fsm.act("WAIT_OUT_CYCLE",
|
||||
fsm.act("FIRST_WAIT",
|
||||
# first cycle - with extra 16 bytes for metadata
|
||||
self.engine.din_ready.eq(0),
|
||||
If(self.engine.dout_stb & cmd_write & (self.engine.dout_index == out_len + 2),
|
||||
NextState("WAIT_READY")
|
||||
),
|
||||
# for some reason read requires some delay until the next state
|
||||
If(self.engine.dout_stb & cmd_read & (self.engine.dout_index == out_len + 3),
|
||||
batch_stb.eq(0),
|
||||
first_iter.eq(1),
|
||||
If(self.engine.dout_stb & (self.engine.dout_index == out_len + 5),
|
||||
# prepare for the next step (no metadata for the next iterations)
|
||||
If(batch_en,
|
||||
NextValue(batch_ptr, batch_ptr + 1),
|
||||
NextValue(self.engine.addr_base, self.engine.addr_base + BATCH_ENTRY_LEN + 16),
|
||||
NextValue(self.engine.dout_burst_len, OUT_BURST_LEN),
|
||||
),
|
||||
NextState("WAIT_READY")
|
||||
)
|
||||
)
|
||||
fsm.act("WAIT_READY",
|
||||
If(cmd_read & (cri.i_status & RTIO_I_STATUS_WAIT_STATUS == 0) \
|
||||
| cmd_write & ~(cri.o_status & RTIO_O_STATUS_WAIT),
|
||||
self.engine.din_ready.eq(1),
|
||||
NextState("IDLE")
|
||||
fsm.act("BATCH_NEXT_CYCLE",
|
||||
self.engine.din_ready.eq(0),
|
||||
batch_stb.eq(0),
|
||||
first_iter.eq(0),
|
||||
If(self.engine.dout_stb & (self.engine.dout_index == out_len + 3),
|
||||
If(batch_en,
|
||||
NextValue(batch_ptr, batch_ptr + 1),
|
||||
NextValue(self.engine.addr_base, self.engine.addr_base + BATCH_ENTRY_LEN)
|
||||
),
|
||||
NextState("WAIT_READY")
|
||||
)
|
||||
)
|
||||
|
||||
fsm.act("WAIT_READY",
|
||||
batch_stb.eq(0),
|
||||
If((cmd_read & (cri.i_status & RTIO_I_STATUS_WAIT_STATUS == 0)) \
|
||||
| (cmd_write & (cri.o_status & RTIO_O_STATUS_WAIT == 0)),
|
||||
# stop the batch in case of an error or when reaching the capacity
|
||||
If(~batch_en |
|
||||
(batch_en & (((batch_len - 1) == batch_ptr) | (cri.o_status != 0))),
|
||||
self.engine.din_ready.eq(1),
|
||||
NextState("IDLE")
|
||||
).Elif(self.engine.read_idle,
|
||||
batch_stb.eq(1),
|
||||
NextState("BATCH_NEXT_CYCLE")
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
self.sync += [
|
||||
If(fsm.ongoing("IDLE"),
|
||||
batch_ptr.eq(0),
|
||||
batch_offset.eq(0),
|
||||
self.engine.addr_base.eq(self.out_base.storage),
|
||||
self.engine.dout_burst_len.eq(FIRST_BURST_LEN),
|
||||
),
|
||||
]
|
||||
|
||||
din_cases_cmdwrite = {
|
||||
0: [self.engine.din.eq((1<<16) | cri.o_status)],
|
||||
1: [self.engine.din.eq(0)],
|
||||
2: [self.engine.din.eq(batch_ptr)]
|
||||
}
|
||||
din_cases_cmdread = {
|
||||
# reply_status: VolatileCell<i32>, reply_data: VolatileCell<i32>
|
||||
0: [self.engine.din[:32].eq((1<<16) | cri.i_status), self.engine.din[32:].eq(cri.i_data)],
|
||||
1: [self.engine.din.eq(cri.i_timestamp)]
|
||||
1: [self.engine.din.eq(cri.i_timestamp)], # reply_timestamp: VolatileCell<i64>,
|
||||
2: [self.engine.din.eq(batch_ptr)] # reply_batch_count: VolatileCell<i32>
|
||||
}
|
||||
|
||||
self.comb += [
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
import os
|
||||
from artiq._version import get_version
|
||||
from misoc.integration import cpu_interface
|
||||
|
||||
|
||||
def generate_ident(variant):
|
||||
return "{}+{};{}".format(
|
||||
get_version().split(".")[0],
|
||||
os.getenv("ZYNQ_REV", default="unknown")[:8],
|
||||
variant,
|
||||
)
|
||||
|
||||
def write_csr_file(soc, filename):
|
||||
with open(filename, "w") as f:
|
||||
f.write(cpu_interface.get_csr_rust(
|
||||
|
||||
74
src/gateware/cxp_4r_fmc.py
Normal file
74
src/gateware/cxp_4r_fmc.py
Normal file
@@ -0,0 +1,74 @@
|
||||
from migen.build.generic_platform import *
|
||||
|
||||
fmc_adapter_io = [
|
||||
# CoaXPress high speed link
|
||||
("CXP_HS", 0,
|
||||
Subsignal("rxp", Pins("HPC:DP0_M2C_P")),
|
||||
Subsignal("rxn", Pins("HPC:DP0_M2C_N")),
|
||||
),
|
||||
("CXP_HS", 1,
|
||||
Subsignal("rxp", Pins("HPC:DP1_M2C_P")),
|
||||
Subsignal("rxn", Pins("HPC:DP1_M2C_N")),
|
||||
),
|
||||
("CXP_HS", 2,
|
||||
Subsignal("rxp", Pins("HPC:DP2_M2C_P")),
|
||||
Subsignal("rxn", Pins("HPC:DP2_M2C_N")),
|
||||
),
|
||||
("CXP_HS", 3,
|
||||
Subsignal("rxp", Pins("HPC:DP3_M2C_P")),
|
||||
Subsignal("rxn", Pins("HPC:DP3_M2C_N")),
|
||||
),
|
||||
|
||||
# CoaXPress low speed link
|
||||
("CXP_LS", 0, Pins("HPC:LA00_CC_P"), IOStandard("LVCMOS33")),
|
||||
("CXP_LS", 1, Pins("HPC:LA01_CC_N"), IOStandard("LVCMOS33")),
|
||||
("CXP_LS", 2, Pins("HPC:LA01_CC_P"), IOStandard("LVCMOS33")),
|
||||
("CXP_LS", 3, Pins("HPC:LA02_N"), IOStandard("LVCMOS33")),
|
||||
|
||||
# CoaXPress green and red LED
|
||||
("CXP_LED", 0,
|
||||
Subsignal("green", Pins("HPC:LA11_P"), IOStandard("LVCMOS33")),
|
||||
Subsignal("red", Pins("HPC:LA11_N"), IOStandard("LVCMOS33")),
|
||||
),
|
||||
("CXP_LED", 1,
|
||||
Subsignal("green", Pins("HPC:LA12_P"), IOStandard("LVCMOS33")),
|
||||
Subsignal("red", Pins("HPC:LA12_N"), IOStandard("LVCMOS33")),
|
||||
),
|
||||
("CXP_LED", 2,
|
||||
Subsignal("green", Pins("HPC:LA13_P"), IOStandard("LVCMOS33")),
|
||||
Subsignal("red", Pins("HPC:LA13_N"), IOStandard("LVCMOS33")),
|
||||
),
|
||||
("CXP_LED", 3,
|
||||
Subsignal("green", Pins("HPC:LA14_P"), IOStandard("LVCMOS33")),
|
||||
Subsignal("red", Pins("HPC:LA14_N"), IOStandard("LVCMOS33")),
|
||||
),
|
||||
|
||||
# Power over CoaXPress
|
||||
("PoCXP", 0,
|
||||
Subsignal("enable", Pins("HPC:LA21_N"), IOStandard("LVCMOS33")),
|
||||
Subsignal("alert", Pins("HPC:LA18_CC_P"), IOStandard("LVCMOS33")),
|
||||
),
|
||||
("PoCXP", 1,
|
||||
Subsignal("enable", Pins("HPC:LA21_P"), IOStandard("LVCMOS33")),
|
||||
Subsignal("alert", Pins("HPC:LA19_N"), IOStandard("LVCMOS33")),
|
||||
),
|
||||
("PoCXP", 2,
|
||||
Subsignal("enable", Pins("HPC:LA22_N"), IOStandard("LVCMOS33")),
|
||||
Subsignal("alert", Pins("HPC:LA19_P"), IOStandard("LVCMOS33")),
|
||||
),
|
||||
("PoCXP", 3,
|
||||
Subsignal("enable", Pins("HPC:LA22_P"), IOStandard("LVCMOS33")),
|
||||
Subsignal("alert", Pins("HPC:LA20_N"), IOStandard("LVCMOS33")),
|
||||
),
|
||||
("i2c", 0,
|
||||
Subsignal("scl", Pins("HPC:IIC_SCL")),
|
||||
Subsignal("sda", Pins("HPC:IIC_SDA")),
|
||||
IOStandard("LVCMOS33")
|
||||
),
|
||||
|
||||
# On board 125MHz reference
|
||||
("clk125", 0,
|
||||
Subsignal("p", Pins("HPC:GBTCLK0_M2C_P")),
|
||||
Subsignal("n", Pins("HPC:GBTCLK0_M2C_N")),
|
||||
),
|
||||
]
|
||||
309
src/gateware/ebaz4205.py
Normal file
309
src/gateware/ebaz4205.py
Normal file
@@ -0,0 +1,309 @@
|
||||
#!/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 generate_ident, 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, acpki_batch_size=1e5):
|
||||
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 = generate_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.config["ACPKI_BATCH_SIZE"] = int(acpki_batch_size)
|
||||
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, acpki_batch_size):
|
||||
EBAZ4205.__init__(self, rtio_clk, acpki, acpki_batch_size)
|
||||
|
||||
|
||||
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("--acpki-batch-size", default=10000, help="ACPKI batch buffer size")
|
||||
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, acpki_batch_size=args.acpki_batch_size)
|
||||
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()
|
||||
@@ -1,11 +1,9 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import argparse
|
||||
from operator import itemgetter
|
||||
|
||||
from migen import *
|
||||
from migen.build.generic_platform import *
|
||||
from migen.genlib.resetsync import AsyncResetSynchronizer
|
||||
from migen.genlib.cdc import MultiReg
|
||||
from migen_axi.integration.soc_core import SoCCore
|
||||
from migen_axi.platforms import kasli_soc
|
||||
@@ -15,7 +13,7 @@ from misoc.cores import virtual_leds
|
||||
from artiq.coredevice import jsondesc
|
||||
from artiq.gateware import rtio, eem_7series
|
||||
from artiq.gateware.rtio.xilinx_clocking import fix_serdes_timing_path
|
||||
from artiq.gateware.rtio.phy import ttl_simple
|
||||
from artiq.gateware.rtio.phy import ttl_simple, cxp_grabber
|
||||
from artiq.gateware.drtio.transceiver import gtx_7series, eem_serdes
|
||||
from artiq.gateware.drtio.siphaser import SiPhaser7Series
|
||||
from artiq.gateware.drtio.rx_synchronizer import XilinxRXSynchronizer
|
||||
@@ -24,10 +22,10 @@ from artiq.gateware.wrpll import wrpll
|
||||
|
||||
import dma
|
||||
import analyzer
|
||||
import acpki
|
||||
import acpki as acpki_lib
|
||||
import drtio_aux_controller
|
||||
import zynq_clocking
|
||||
from config import write_csr_file, write_mem_file, write_rustc_cfg_file
|
||||
from config import generate_ident, write_csr_file, write_mem_file, write_rustc_cfg_file
|
||||
|
||||
eem_iostandard_dict = {
|
||||
0: "LVDS_25",
|
||||
@@ -44,6 +42,7 @@ eem_iostandard_dict = {
|
||||
11: "LVDS",
|
||||
}
|
||||
|
||||
DRTIO_EEM_PERIPHERALS = ["shuttler", "phaser_drtio"]
|
||||
|
||||
def eem_iostandard(eem):
|
||||
return IOStandard(eem_iostandard_dict[eem])
|
||||
@@ -105,9 +104,52 @@ class GTPBootstrapClock(Module):
|
||||
raise ValueError("Bootstrap frequency must be 100 or 125MHz")
|
||||
|
||||
|
||||
def add_coaxpress_sfp(cls, clk_freq, roi_engine_count, refclk=None):
|
||||
if refclk is None:
|
||||
refclk = Signal()
|
||||
gt_refclk_pad = cls.platform.request("clk_gtp")
|
||||
cls.platform.add_period_constraint(gt_refclk_pad.p, 8.0)
|
||||
cls.specials += Instance("IBUFDS_GTE2",
|
||||
i_CEB=0,
|
||||
i_I=gt_refclk_pad.p,
|
||||
i_IB=gt_refclk_pad.n,
|
||||
o_O=refclk,
|
||||
p_CLKCM_CFG="TRUE",
|
||||
p_CLKRCV_TRST="TRUE",
|
||||
p_CLKSWING_CFG=3
|
||||
)
|
||||
|
||||
sfp_slot = 0
|
||||
cls.submodules.cxp_grabber = cxp_grabber.CXPGrabber(
|
||||
refclk=refclk,
|
||||
gt_pads=[cls.platform.request("sfp", sfp_slot)],
|
||||
sys_clk_freq=clk_freq,
|
||||
roi_engine_count=roi_engine_count
|
||||
)
|
||||
cls.config["HAS_CXP_LED"] = None
|
||||
|
||||
mem_size = cls.cxp_grabber.core.get_mem_size()
|
||||
# upper half is tx while lower half is rx
|
||||
memory_address = cls.axi2csr.register_port(cls.cxp_grabber.core.get_tx_port(), mem_size)
|
||||
cls.axi2csr.register_port(cls.cxp_grabber.core.get_rx_port(), mem_size)
|
||||
cls.add_memory_region("cxp_mem", cls.mem_map["csr"] + memory_address, mem_size * 2)
|
||||
cls.csr_devices.append("cxp_grabber")
|
||||
|
||||
print("CoaXPress-SFP (SFP{}) at RTIO channel 0x{:06x}".format(sfp_slot, len(cls.rtio_channels)))
|
||||
cls.rtio_channels += [
|
||||
rtio.Channel(cls.cxp_grabber.trigger),
|
||||
rtio.Channel(cls.cxp_grabber.config),
|
||||
rtio.Channel(cls.cxp_grabber.gate_data),
|
||||
]
|
||||
# max freq of cxp_gt_rx = linerate/internal_datawidth = 12.5Gbps/40 = 312.5MHz
|
||||
rx = cls.cxp_grabber.phy.phys[0]
|
||||
cls.platform.add_period_constraint(rx.gtx.cd_cxp_gt_rx.clk, 3.2)
|
||||
# constraint the clk path
|
||||
cls.platform.add_false_path_constraints(cls.sys_crg.cd_sys.clk, rx.gtx.cd_cxp_gt_rx.clk)
|
||||
|
||||
class GenericStandalone(SoCCore):
|
||||
def __init__(self, description, acpki=False):
|
||||
self.acpki = acpki
|
||||
def __init__(self, description):
|
||||
self.acpki = description["enable_acpki"]
|
||||
clk_freq = description["rtio_frequency"]
|
||||
with_wrpll = description["enable_wrpll"]
|
||||
|
||||
@@ -115,7 +157,7 @@ class GenericStandalone(SoCCore):
|
||||
platform.toolchain.bitstream_commands.extend([
|
||||
"set_property BITSTREAM.GENERAL.COMPRESS True [current_design]",
|
||||
])
|
||||
ident = description["variant"]
|
||||
ident = generate_ident(description["variant"])
|
||||
if self.acpki:
|
||||
ident = "acpki_" + ident
|
||||
SoCCore.__init__(self, platform=platform, csr_data_width=32, ident=ident, ps_cd_sys=False)
|
||||
@@ -161,12 +203,20 @@ class GenericStandalone(SoCCore):
|
||||
self.config["HAS_SI5324"] = None
|
||||
self.config["SI5324_SOFT_RESET"] = None
|
||||
|
||||
|
||||
self.rtio_channels = []
|
||||
has_grabber = any(peripheral["type"] == "grabber" for peripheral in description["peripherals"])
|
||||
if has_grabber:
|
||||
self.grabber_csr_group = []
|
||||
eem_7series.add_peripherals(self, description["peripherals"], iostandard=eem_iostandard)
|
||||
|
||||
has_grabber = False
|
||||
eem_peripherals = []
|
||||
for peripheral in description["peripherals"]:
|
||||
if peripheral["type"] == "coaxpress_sfp":
|
||||
add_coaxpress_sfp(self, clk_freq, peripheral["roi_engine_count"])
|
||||
elif peripheral["type"] == "grabber":
|
||||
has_grabber = True
|
||||
self.grabber_csr_group = []
|
||||
eem_peripherals.append(peripheral)
|
||||
else:
|
||||
eem_peripherals.append(peripheral)
|
||||
eem_7series.add_peripherals(self, eem_peripherals, iostandard=eem_iostandard)
|
||||
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)
|
||||
@@ -184,10 +234,11 @@ class GenericStandalone(SoCCore):
|
||||
|
||||
if self.acpki:
|
||||
self.config["KI_IMPL"] = "acp"
|
||||
self.submodules.rtio = acpki.KernelInitiator(self.rtio_tsc,
|
||||
bus=self.ps7.s_axi_acp,
|
||||
user=self.ps7.s_axi_acp_user,
|
||||
evento=self.ps7.event.o)
|
||||
self.config["ACPKI_BUFFER_SIZE"] = int(description["acpki_buffer_size"])
|
||||
self.submodules.rtio = acpki_lib.KernelInitiator(self.rtio_tsc,
|
||||
bus=self.ps7.s_axi_acp,
|
||||
user=self.ps7.s_axi_acp_user,
|
||||
evento=self.ps7.event.o)
|
||||
self.csr_devices.append("rtio")
|
||||
else:
|
||||
self.config["KI_IMPL"] = "csr"
|
||||
@@ -218,29 +269,42 @@ class GenericStandalone(SoCCore):
|
||||
|
||||
|
||||
class GenericMaster(SoCCore):
|
||||
def __init__(self, description, acpki=False):
|
||||
def __init__(self, description):
|
||||
clk_freq = description["rtio_frequency"]
|
||||
with_wrpll = description["enable_wrpll"]
|
||||
|
||||
has_drtio_over_eem = any(peripheral["type"] == "shuttler" for peripheral in description["peripherals"])
|
||||
self.acpki = acpki
|
||||
self.acpki = description["enable_acpki"]
|
||||
|
||||
platform = kasli_soc.Platform()
|
||||
platform.toolchain.bitstream_commands.extend([
|
||||
"set_property BITSTREAM.GENERAL.COMPRESS True [current_design]",
|
||||
])
|
||||
ident = description["variant"]
|
||||
ident = generate_ident(description["variant"])
|
||||
if self.acpki:
|
||||
ident = "acpki_" + ident
|
||||
SoCCore.__init__(self, platform=platform, csr_data_width=32, ident=ident, ps_cd_sys=False)
|
||||
|
||||
self.config["HW_REV"] = description["hw_rev"]
|
||||
|
||||
data_pads = [platform.request("sfp", i) for i in range(4)]
|
||||
eem_peripherals = []
|
||||
drtio_sfp_slots = list(range(4))
|
||||
has_coaxpress_sfp, has_grabber = False, False
|
||||
for peripheral in description["peripherals"]:
|
||||
if peripheral["type"] == "coaxpress_sfp":
|
||||
has_coaxpress_sfp = True
|
||||
cxp_roi_counts = peripheral["roi_engine_count"]
|
||||
# use sfp slot 0 for coaxpress_sfp
|
||||
drtio_sfp_slots = list(range(1, 4))
|
||||
elif peripheral["type"] == "grabber":
|
||||
has_grabber = True
|
||||
eem_peripherals.append(peripheral)
|
||||
else:
|
||||
eem_peripherals.append(peripheral)
|
||||
|
||||
self.submodules.gt_drtio = gtx_7series.GTX(
|
||||
clock_pads=platform.request("clk_gtp"),
|
||||
pads=data_pads,
|
||||
pads=[self.platform.request("sfp", i) for i in drtio_sfp_slots],
|
||||
clk_freq=clk_freq)
|
||||
self.csr_devices.append("gt_drtio")
|
||||
self.config["RTIO_FREQUENCY"] = str(clk_freq/1e6)
|
||||
@@ -291,12 +355,13 @@ class GenericMaster(SoCCore):
|
||||
self.config["SI5324_SOFT_RESET"] = None
|
||||
|
||||
self.rtio_channels = []
|
||||
has_grabber = any(peripheral["type"] == "grabber" for peripheral in description["peripherals"])
|
||||
if has_drtio_over_eem:
|
||||
self.eem_drtio_channels = []
|
||||
if has_grabber:
|
||||
self.grabber_csr_group = []
|
||||
eem_7series.add_peripherals(self, description["peripherals"], iostandard=eem_iostandard)
|
||||
if has_coaxpress_sfp:
|
||||
add_coaxpress_sfp(self, clk_freq, cxp_roi_counts, self.gt_drtio.refclk)
|
||||
eem_7series.add_peripherals(self, eem_peripherals, iostandard=eem_iostandard)
|
||||
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)
|
||||
@@ -349,10 +414,11 @@ class GenericMaster(SoCCore):
|
||||
|
||||
if self.acpki:
|
||||
self.config["KI_IMPL"] = "acp"
|
||||
self.submodules.rtio = acpki.KernelInitiator(self.rtio_tsc,
|
||||
bus=self.ps7.s_axi_acp,
|
||||
user=self.ps7.s_axi_acp_user,
|
||||
evento=self.ps7.event.o)
|
||||
self.config["ACPKI_BUFFER_SIZE"] = int(description["acpki_buffer_size"])
|
||||
self.submodules.rtio = acpki_lib.KernelInitiator(self.rtio_tsc,
|
||||
bus=self.ps7.s_axi_acp,
|
||||
user=self.ps7.s_axi_acp_user,
|
||||
evento=self.ps7.event.o)
|
||||
self.csr_devices.append("rtio")
|
||||
else:
|
||||
self.config["KI_IMPL"] = "csr"
|
||||
@@ -387,7 +453,7 @@ class GenericMaster(SoCCore):
|
||||
self.csr_devices.append("virtual_leds")
|
||||
|
||||
self.comb += [self.virtual_leds.get(i).eq(channel.rx_ready)
|
||||
for i, channel in enumerate(self.gt_drtio.channels)]
|
||||
for i, channel in zip(drtio_sfp_slots, self.gt_drtio.channels)]
|
||||
|
||||
def add_eem_drtio(self, eem_drtio_channels):
|
||||
# Must be called before invoking add_rtio() to construct the CRI
|
||||
@@ -428,28 +494,42 @@ class GenericMaster(SoCCore):
|
||||
|
||||
|
||||
class GenericSatellite(SoCCore):
|
||||
def __init__(self, description, acpki=False):
|
||||
def __init__(self, description):
|
||||
clk_freq = description["rtio_frequency"]
|
||||
with_wrpll = description["enable_wrpll"]
|
||||
|
||||
self.acpki = acpki
|
||||
has_drtio_over_eem = any(peripheral["type"] == "shuttler" for peripheral in description["peripherals"])
|
||||
self.acpki = description["enable_acpki"]
|
||||
|
||||
platform = kasli_soc.Platform()
|
||||
platform.toolchain.bitstream_commands.extend([
|
||||
"set_property BITSTREAM.GENERAL.COMPRESS True [current_design]",
|
||||
])
|
||||
ident = description["variant"]
|
||||
ident = generate_ident(description["variant"])
|
||||
if self.acpki:
|
||||
ident = "acpki_" + ident
|
||||
SoCCore.__init__(self, platform=platform, csr_data_width=32, ident=ident, ps_cd_sys=False)
|
||||
|
||||
self.config["HW_REV"] = description["hw_rev"]
|
||||
|
||||
data_pads = [platform.request("sfp", i) for i in range(4)]
|
||||
eem_peripherals = []
|
||||
drtio_sfp_slots = list(range(4))
|
||||
has_coaxpress_sfp, has_grabber = False, False
|
||||
for peripheral in description["peripherals"]:
|
||||
if peripheral["type"] == "coaxpress_sfp":
|
||||
has_coaxpress_sfp = True
|
||||
cxp_roi_counts = peripheral["roi_engine_count"]
|
||||
# use sfp slot 0 for coaxpress_sfp
|
||||
drtio_sfp_slots = list(range(1, 4))
|
||||
elif peripheral["type"] == "grabber":
|
||||
has_grabber = True
|
||||
eem_peripherals.append(peripheral)
|
||||
else:
|
||||
eem_peripherals.append(peripheral)
|
||||
|
||||
self.submodules.gt_drtio = gtx_7series.GTX(
|
||||
clock_pads=platform.request("clk_gtp"),
|
||||
pads=data_pads,
|
||||
pads=[platform.request("sfp", i) for i in drtio_sfp_slots],
|
||||
clk_freq=clk_freq)
|
||||
self.csr_devices.append("gt_drtio")
|
||||
|
||||
@@ -480,9 +560,13 @@ class GenericSatellite(SoCCore):
|
||||
|
||||
self.rtio_channels = []
|
||||
has_grabber = any(peripheral["type"] == "grabber" for peripheral in description["peripherals"])
|
||||
if has_drtio_over_eem:
|
||||
self.eem_drtio_channels = []
|
||||
if has_grabber:
|
||||
self.grabber_csr_group = []
|
||||
eem_7series.add_peripherals(self, description["peripherals"], iostandard=eem_iostandard)
|
||||
if has_coaxpress_sfp:
|
||||
add_coaxpress_sfp(self, clk_freq, cxp_roi_counts, self.gt_drtio.refclk)
|
||||
eem_7series.add_peripherals(self, eem_peripherals, iostandard=eem_iostandard)
|
||||
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)
|
||||
@@ -494,15 +578,15 @@ class GenericSatellite(SoCCore):
|
||||
|
||||
self.submodules.rtio_tsc = rtio.TSC(glbl_fine_ts_width=3)
|
||||
|
||||
drtioaux_csr_group = []
|
||||
drtioaux_memory_group = []
|
||||
drtiorep_csr_group = []
|
||||
self.drtioaux_csr_group = []
|
||||
self.drtioaux_memory_group = []
|
||||
self.drtiorep_csr_group = []
|
||||
self.drtio_cri = []
|
||||
for i in range(len(self.gt_drtio.channels)):
|
||||
coreaux_name = "drtioaux" + str(i)
|
||||
memory_name = "drtioaux" + str(i) + "_mem"
|
||||
drtioaux_csr_group.append(coreaux_name)
|
||||
drtioaux_memory_group.append(memory_name)
|
||||
self.drtioaux_csr_group.append(coreaux_name)
|
||||
self.drtioaux_memory_group.append(memory_name)
|
||||
|
||||
cdr = ClockDomainsRenamer({"rtio_rx": "rtio_rx" + str(i)})
|
||||
|
||||
@@ -515,7 +599,7 @@ class GenericSatellite(SoCCore):
|
||||
self.csr_devices.append("drtiosat")
|
||||
else:
|
||||
corerep_name = "drtiorep" + str(i-1)
|
||||
drtiorep_csr_group.append(corerep_name)
|
||||
self.drtiorep_csr_group.append(corerep_name)
|
||||
|
||||
core = cdr(DRTIORepeater(
|
||||
self.rtio_tsc, self.gt_drtio.channels[i]))
|
||||
@@ -538,16 +622,17 @@ class GenericSatellite(SoCCore):
|
||||
self.add_memory_region(memory_name, self.mem_map["csr"] + memory_address, mem_size * 2)
|
||||
self.config["HAS_DRTIO"] = None
|
||||
self.config["HAS_DRTIO_ROUTING"] = None
|
||||
self.add_csr_group("drtioaux", drtioaux_csr_group)
|
||||
self.add_memory_group("drtioaux_mem", drtioaux_memory_group)
|
||||
self.add_csr_group("drtiorep", drtiorep_csr_group)
|
||||
if has_drtio_over_eem:
|
||||
self.add_eem_drtio(self.eem_drtio_channels)
|
||||
self.add_drtio_cpuif_groups()
|
||||
|
||||
if self.acpki:
|
||||
self.config["KI_IMPL"] = "acp"
|
||||
self.submodules.rtio = acpki.KernelInitiator(self.rtio_tsc,
|
||||
bus=self.ps7.s_axi_acp,
|
||||
user=self.ps7.s_axi_acp_user,
|
||||
evento=self.ps7.event.o)
|
||||
self.config["ACPKI_BUFFER_SIZE"] = int(description["acpki_buffer_size"])
|
||||
self.submodules.rtio = acpki_lib.KernelInitiator(self.rtio_tsc,
|
||||
bus=self.ps7.s_axi_acp,
|
||||
user=self.ps7.s_axi_acp_user,
|
||||
evento=self.ps7.event.o)
|
||||
self.csr_devices.append("rtio")
|
||||
else:
|
||||
self.config["KI_IMPL"] = "csr"
|
||||
@@ -560,7 +645,10 @@ class GenericSatellite(SoCCore):
|
||||
self.submodules.local_io = SyncRTIO(
|
||||
self.rtio_tsc, self.rtio_channels, lane_count=description["sed_lanes"]
|
||||
)
|
||||
self.comb += self.drtiosat.async_errors.eq(self.local_io.async_errors)
|
||||
self.comb += [
|
||||
self.drtiosat.async_errors.eq(self.local_io.async_errors),
|
||||
self.local_io.sed_spread_enable.eq(self.drtiosat.sed_spread_enable.storage)
|
||||
]
|
||||
|
||||
self.submodules.cri_con = rtio.CRIInterconnectShared(
|
||||
[self.drtiosat.cri, self.rtio_dma.cri, self.rtio.cri],
|
||||
@@ -620,7 +708,51 @@ class GenericSatellite(SoCCore):
|
||||
self.csr_devices.append("virtual_leds")
|
||||
|
||||
self.comb += [self.virtual_leds.get(i).eq(channel.rx_ready)
|
||||
for i, channel in enumerate(self.gt_drtio.channels)]
|
||||
for i, channel in zip(drtio_sfp_slots, self.gt_drtio.channels)]
|
||||
|
||||
def add_eem_drtio(self, eem_drtio_channels):
|
||||
# Must be called before constructing CRIInterconnectShared
|
||||
self.submodules.eem_transceiver = eem_serdes.EEMSerdes(self.platform, eem_drtio_channels)
|
||||
self.csr_devices.append("eem_transceiver")
|
||||
self.config["HAS_DRTIO_EEM"] = None
|
||||
self.config["EEM_DRTIO_COUNT"] = len(eem_drtio_channels)
|
||||
|
||||
for i in range(len(self.eem_transceiver.channels)):
|
||||
channel = i + len(self.gt_drtio.channels)
|
||||
coreaux_name = "drtioaux" + str(channel)
|
||||
memory_name = "drtioaux" + str(channel) + "_mem"
|
||||
self.drtioaux_csr_group.append(coreaux_name)
|
||||
self.drtioaux_memory_group.append(memory_name)
|
||||
|
||||
cdr = ClockDomainsRenamer({"rtio_rx": "sys"})
|
||||
corerep_name = "drtiorep" + str(channel-1)
|
||||
self.drtiorep_csr_group.append(corerep_name)
|
||||
|
||||
core = cdr(DRTIORepeater(
|
||||
self.rtio_tsc, self.eem_transceiver.channels[i]))
|
||||
setattr(self.submodules, corerep_name, core)
|
||||
self.drtio_cri.append(core.cri)
|
||||
self.csr_devices.append(corerep_name)
|
||||
|
||||
coreaux = cdr(drtio_aux_controller.DRTIOAuxControllerBare(core.link_layer))
|
||||
setattr(self.submodules, coreaux_name, coreaux)
|
||||
self.csr_devices.append(coreaux_name)
|
||||
|
||||
mem_size = coreaux.get_mem_size()
|
||||
tx_port = coreaux.get_tx_port()
|
||||
rx_port = coreaux.get_rx_port()
|
||||
memory_address = self.axi2csr.register_port(tx_port, mem_size)
|
||||
# rcv in upper half of the memory, thus added second
|
||||
self.axi2csr.register_port(rx_port, mem_size)
|
||||
# and registered in PS interface
|
||||
# manually, because software refers to rx/tx by halves of entire memory block, not names
|
||||
self.add_memory_region(memory_name, self.mem_map["csr"] + memory_address, mem_size * 2)
|
||||
|
||||
def add_drtio_cpuif_groups(self):
|
||||
self.add_csr_group("drtiorep", self.drtiorep_csr_group)
|
||||
self.add_csr_group("drtioaux", self.drtioaux_csr_group)
|
||||
self.add_memory_group("drtioaux_mem", self.drtioaux_memory_group)
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
@@ -633,8 +765,6 @@ def main():
|
||||
help="build Rust memory interface into the specified file")
|
||||
parser.add_argument("-g", default=None,
|
||||
help="build gateware into the specified directory")
|
||||
parser.add_argument("--acpki", default=False, action="store_true",
|
||||
help="enable ACPKI")
|
||||
parser.add_argument("description", metavar="DESCRIPTION",
|
||||
help="JSON system description file")
|
||||
args = parser.parse_args()
|
||||
@@ -652,7 +782,11 @@ def main():
|
||||
else:
|
||||
raise ValueError("Invalid DRTIO role")
|
||||
|
||||
soc = cls(description, acpki=args.acpki)
|
||||
for peripheral in description["peripherals"]:
|
||||
if peripheral["type"] in DRTIO_EEM_PERIPHERALS and description["drtio_role"] == "standalone":
|
||||
raise ValueError("{} requires DRTIO, please switch role to master or satellite".format(peripheral["type"]))
|
||||
|
||||
soc = cls(description)
|
||||
soc.finalize()
|
||||
|
||||
if args.r is not None:
|
||||
|
||||
@@ -13,7 +13,7 @@ from misoc.interconnect.csr import *
|
||||
from misoc.cores import gpio
|
||||
|
||||
from artiq.gateware import rtio, nist_clock, nist_qc2
|
||||
from artiq.gateware.rtio.phy import ttl_simple, ttl_serdes_7series, dds, spi2, edge_counter
|
||||
from artiq.gateware.rtio.phy import ttl_simple, ttl_serdes_7series, dds, spi2, edge_counter, cxp_grabber
|
||||
from artiq.gateware.rtio.xilinx_clocking import fix_serdes_timing_path
|
||||
from artiq.gateware.drtio.transceiver import gtx_7series
|
||||
from artiq.gateware.drtio.siphaser import SiPhaser7Series
|
||||
@@ -25,7 +25,8 @@ import analyzer
|
||||
import acpki
|
||||
import drtio_aux_controller
|
||||
import zynq_clocking
|
||||
from config import write_csr_file, write_mem_file, write_rustc_cfg_file
|
||||
import cxp_4r_fmc
|
||||
from config import generate_ident, write_csr_file, write_mem_file, write_rustc_cfg_file
|
||||
|
||||
class SMAClkinForward(Module):
|
||||
def __init__(self, platform):
|
||||
@@ -124,13 +125,13 @@ def prepare_zc706_platform(platform):
|
||||
])
|
||||
|
||||
class ZC706(SoCCore):
|
||||
def __init__(self, acpki=False):
|
||||
def __init__(self, acpki=False, acpki_batch_size=1e5):
|
||||
self.acpki = acpki
|
||||
|
||||
platform = zc706.Platform()
|
||||
prepare_zc706_platform(platform)
|
||||
|
||||
ident = self.__class__.__name__
|
||||
ident = generate_ident(self.__class__.__name__)
|
||||
if self.acpki:
|
||||
ident = "acpki_" + ident
|
||||
SoCCore.__init__(self, platform=platform, csr_data_width=32, ident=ident, ps_cd_sys=False)
|
||||
@@ -138,7 +139,7 @@ class ZC706(SoCCore):
|
||||
platform.add_extension(si5324_fmc33)
|
||||
self.comb += platform.request("si5324_33").rst_n.eq(1)
|
||||
|
||||
cdr_clk = Signal()
|
||||
self.cdr_clk = Signal()
|
||||
cdr_clk_buf = Signal()
|
||||
si5324_out = platform.request("si5324_clkout")
|
||||
platform.add_period_constraint(si5324_out.p, 8.0)
|
||||
@@ -146,15 +147,16 @@ class ZC706(SoCCore):
|
||||
Instance("IBUFDS_GTE2",
|
||||
i_CEB=0,
|
||||
i_I=si5324_out.p, i_IB=si5324_out.n,
|
||||
o_O=cdr_clk,
|
||||
o_O=self.cdr_clk,
|
||||
p_CLKCM_CFG="TRUE",
|
||||
p_CLKRCV_TRST="TRUE",
|
||||
p_CLKSWING_CFG=3),
|
||||
Instance("BUFG", i_I=cdr_clk, o_O=cdr_clk_buf)
|
||||
Instance("BUFG", i_I=self.cdr_clk, o_O=cdr_clk_buf)
|
||||
]
|
||||
self.config["HAS_SI5324"] = None
|
||||
self.config["SI5324_AS_SYNTHESIZER"] = None
|
||||
self.config["SI5324_SOFT_RESET"] = None
|
||||
self.config["ACPKI_BATCH_SIZE"] = int(acpki_batch_size)
|
||||
|
||||
self.submodules.bootstrap = CLK200BootstrapClock(platform)
|
||||
self.submodules.sys_crg = zynq_clocking.SYSCRG(self.platform, self.ps7, cdr_clk_buf)
|
||||
@@ -196,14 +198,14 @@ class ZC706(SoCCore):
|
||||
|
||||
|
||||
class _MasterBase(SoCCore):
|
||||
def __init__(self, acpki=False, drtio100mhz=False):
|
||||
def __init__(self, acpki=False, drtio100mhz=False, acpki_batch_size=1e5):
|
||||
self.acpki = acpki
|
||||
|
||||
clk_freq = 100e6 if drtio100mhz else 125e6
|
||||
|
||||
platform = zc706.Platform()
|
||||
prepare_zc706_platform(platform)
|
||||
ident = self.__class__.__name__
|
||||
ident = generate_ident(self.__class__.__name__)
|
||||
if self.acpki:
|
||||
ident = "acpki_" + ident
|
||||
SoCCore.__init__(self, platform=platform, csr_data_width=32, ident=ident, ps_cd_sys=False)
|
||||
@@ -287,6 +289,8 @@ class _MasterBase(SoCCore):
|
||||
self.config["HAS_SI5324"] = None
|
||||
self.config["SI5324_AS_SYNTHESIZER"] = None
|
||||
|
||||
self.config["ACPKI_BATCH_SIZE"] = int(acpki_batch_size)
|
||||
|
||||
# Constrain TX & RX timing for the first transceiver channel
|
||||
# (First channel acts as master for phase alignment for all channels' TX)
|
||||
platform.add_false_path_constraints(
|
||||
@@ -337,14 +341,14 @@ class _MasterBase(SoCCore):
|
||||
|
||||
|
||||
class _SatelliteBase(SoCCore):
|
||||
def __init__(self, acpki=False, drtio100mhz=False):
|
||||
def __init__(self, acpki=False, drtio100mhz=False, acpki_batch_size=1e5):
|
||||
self.acpki = acpki
|
||||
|
||||
clk_freq = 100e6 if drtio100mhz else 125e6
|
||||
|
||||
platform = zc706.Platform()
|
||||
prepare_zc706_platform(platform)
|
||||
ident = self.__class__.__name__
|
||||
ident = generate_ident(self.__class__.__name__)
|
||||
if self.acpki:
|
||||
ident = "acpki_" + ident
|
||||
SoCCore.__init__(self, platform=platform, csr_data_width=32, ident=ident, ps_cd_sys=False)
|
||||
@@ -440,6 +444,7 @@ class _SatelliteBase(SoCCore):
|
||||
self.add_memory_group("drtioaux_mem", drtioaux_memory_group)
|
||||
|
||||
self.config["RTIO_FREQUENCY"] = str(self.gt_drtio.rtio_clk_freq/1e6)
|
||||
self.config["ACPKI_BATCH_SIZE"] = int(acpki_batch_size)
|
||||
|
||||
# Si5324 Phaser
|
||||
self.submodules.siphaser = SiPhaser7Series(
|
||||
@@ -487,6 +492,10 @@ class _SatelliteBase(SoCCore):
|
||||
self.csr_devices.append("rtio_dma")
|
||||
|
||||
self.submodules.local_io = SyncRTIO(self.rtio_tsc, rtio_channels)
|
||||
self.comb += [
|
||||
self.drtiosat.async_errors.eq(self.local_io.async_errors),
|
||||
self.local_io.sed_spread_enable.eq(self.drtiosat.sed_spread_enable.storage)
|
||||
]
|
||||
self.submodules.cri_con = rtio.CRIInterconnectShared(
|
||||
[self.drtiosat.cri, self.rtio_dma.cri, self.rtio.cri],
|
||||
[self.local_io.cri] + self.drtio_cri,
|
||||
@@ -648,40 +657,95 @@ class _NIST_QC2_RTIO:
|
||||
self.add_rtio(rtio_channels)
|
||||
|
||||
|
||||
class _CXP_4R_FMC_RTIO():
|
||||
"""
|
||||
CoaXpress host FMC card
|
||||
"""
|
||||
def __init__(self):
|
||||
platform = self.platform
|
||||
platform.add_extension(cxp_4r_fmc.fmc_adapter_io)
|
||||
platform.add_extension(leds_fmc33)
|
||||
|
||||
rtio_channels = []
|
||||
clk_freq = 125e6
|
||||
|
||||
self.submodules.cxp_grabber = cxp_grabber.CXPGrabber(
|
||||
refclk=self.cdr_clk,
|
||||
non_gt_tx_pads=[platform.request("CXP_LS", 0)],
|
||||
gt_pads=[platform.request("CXP_HS", 0)],
|
||||
sys_clk_freq=clk_freq,
|
||||
)
|
||||
mem_size = self.cxp_grabber.core.get_mem_size()
|
||||
# upper half is tx while lower half is rx
|
||||
memory_address = self.axi2csr.register_port(self.cxp_grabber.core.get_tx_port(), mem_size)
|
||||
self.axi2csr.register_port(self.cxp_grabber.core.get_rx_port(), mem_size)
|
||||
self.add_memory_region("cxp_mem", self.mem_map["csr"] + memory_address, mem_size * 2)
|
||||
self.csr_devices.append("cxp_grabber")
|
||||
|
||||
print("CoaXPress at RTIO channel 0x{:06x}".format(len(rtio_channels)))
|
||||
rtio_channels += [
|
||||
rtio.Channel(self.cxp_grabber.trigger),
|
||||
rtio.Channel(self.cxp_grabber.config),
|
||||
rtio.Channel(self.cxp_grabber.gate_data),
|
||||
]
|
||||
# max freq of cxp_gt_rx = linerate/internal_datawidth = 12.5Gbps/40 = 312.5MHz
|
||||
# zc706 use speed grade 2 which only support up to 10.3125Gbps (~4ns)
|
||||
# pushing to 12.5Gbps (3.2ns) will result in Pulse width violation but setup/hold times will still meet
|
||||
rx = self.cxp_grabber.phy_rx.phys[0]
|
||||
platform.add_period_constraint(rx.gtx.cd_cxp_gt_rx.clk, 3.2)
|
||||
# constraint the clk path
|
||||
platform.add_false_path_constraints(self.sys_crg.cd_sys.clk, rx.gtx.cd_cxp_gt_rx.clk)
|
||||
|
||||
# Add a user LED for rtio moninj
|
||||
print("USER LED at RTIO channel 0x{:06x}".format(len(rtio_channels)))
|
||||
phy = ttl_simple.Output(self.platform.request("user_led_33", 0))
|
||||
self.submodules += phy
|
||||
rtio_channels.append(rtio.Channel.from_phy(phy))
|
||||
self.config["HAS_RTIO_LOG"] = None
|
||||
rtio_channels.append(rtio.LogChannel())
|
||||
|
||||
self.config["RTIO_LOG_CHANNEL"] = len(rtio_channels)
|
||||
self.add_rtio(rtio_channels)
|
||||
|
||||
class NIST_CLOCK(ZC706, _NIST_CLOCK_RTIO):
|
||||
def __init__(self, acpki, drtio100mhz):
|
||||
ZC706.__init__(self, acpki)
|
||||
def __init__(self, acpki, drtio100mhz, acpki_batch_size):
|
||||
ZC706.__init__(self, acpki, acpki_batch_size)
|
||||
self.submodules += SMAClkinForward(self.platform)
|
||||
_NIST_CLOCK_RTIO.__init__(self)
|
||||
|
||||
class NIST_CLOCK_Master(_MasterBase, _NIST_CLOCK_RTIO):
|
||||
def __init__(self, acpki, drtio100mhz):
|
||||
_MasterBase.__init__(self, acpki, drtio100mhz)
|
||||
def __init__(self, acpki, drtio100mhz, acpki_batch_size):
|
||||
_MasterBase.__init__(self, acpki, drtio100mhz, acpki_batch_size)
|
||||
_NIST_CLOCK_RTIO.__init__(self)
|
||||
|
||||
class NIST_CLOCK_Satellite(_SatelliteBase, _NIST_CLOCK_RTIO):
|
||||
def __init__(self, acpki, drtio100mhz):
|
||||
_SatelliteBase.__init__(self, acpki, drtio100mhz)
|
||||
def __init__(self, acpki, drtio100mhz, acpki_batch_size):
|
||||
_SatelliteBase.__init__(self, acpki, drtio100mhz, acpki_batch_size)
|
||||
_NIST_CLOCK_RTIO.__init__(self)
|
||||
|
||||
class NIST_QC2(ZC706, _NIST_QC2_RTIO):
|
||||
def __init__(self, acpki, drtio100mhz):
|
||||
ZC706.__init__(self, acpki)
|
||||
def __init__(self, acpki, drtio100mhz, acpki_batch_size):
|
||||
ZC706.__init__(self, acpki, acpki_batch_size)
|
||||
self.submodules += SMAClkinForward(self.platform)
|
||||
_NIST_QC2_RTIO.__init__(self)
|
||||
|
||||
class NIST_QC2_Master(_MasterBase, _NIST_QC2_RTIO):
|
||||
def __init__(self, acpki, drtio100mhz):
|
||||
_MasterBase.__init__(self, acpki, drtio100mhz)
|
||||
def __init__(self, acpki, drtio100mhz, acpki_batch_size):
|
||||
_MasterBase.__init__(self, acpki, drtio100mhz, acpki_batch_size)
|
||||
_NIST_QC2_RTIO.__init__(self)
|
||||
|
||||
class NIST_QC2_Satellite(_SatelliteBase, _NIST_QC2_RTIO):
|
||||
def __init__(self, acpki, drtio100mhz):
|
||||
_SatelliteBase.__init__(self, acpki, drtio100mhz)
|
||||
def __init__(self, acpki, drtio100mhz, acpki_batch_size):
|
||||
_SatelliteBase.__init__(self, acpki, drtio100mhz, acpki_batch_size)
|
||||
_NIST_QC2_RTIO.__init__(self)
|
||||
|
||||
class CXP_4R_FMC(ZC706, _CXP_4R_FMC_RTIO):
|
||||
def __init__(self, acpki, drtio100mhz, acpki_batch_size):
|
||||
ZC706.__init__(self, acpki, acpki_batch_size)
|
||||
_CXP_4R_FMC_RTIO.__init__(self)
|
||||
|
||||
VARIANTS = {cls.__name__.lower(): cls for cls in [NIST_CLOCK, NIST_CLOCK_Master, NIST_CLOCK_Satellite,
|
||||
NIST_QC2, NIST_QC2_Master, NIST_QC2_Satellite]}
|
||||
NIST_QC2, NIST_QC2_Master, NIST_QC2_Satellite, CXP_4R_FMC]}
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
@@ -698,6 +762,7 @@ def main():
|
||||
help="variant: "
|
||||
"[acpki_]nist_clock/nist_qc2[_master/_satellite][_100mhz]"
|
||||
"(default: %(default)s)")
|
||||
parser.add_argument("--acpki-batch-size", default=10000, help="ACPKI batch buffer size")
|
||||
args = parser.parse_args()
|
||||
|
||||
variant = args.variant.lower()
|
||||
@@ -712,7 +777,7 @@ def main():
|
||||
except KeyError:
|
||||
raise SystemExit("Invalid variant (-V/--variant)")
|
||||
|
||||
soc = cls(acpki=acpki, drtio100mhz=drtio100mhz)
|
||||
soc = cls(acpki=acpki, drtio100mhz=drtio100mhz, acpki_batch_size=args.acpki_batch_size)
|
||||
soc.finalize()
|
||||
|
||||
if args.r is not None:
|
||||
|
||||
@@ -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]
|
||||
@@ -19,14 +20,14 @@ build_zynq = { path = "../libbuild_zynq" }
|
||||
log = "0.4"
|
||||
log_buffer = { version = "1.2" }
|
||||
crc = { version = "1.7", default-features = false }
|
||||
core_io = { version = "0.1", features = ["collections"] }
|
||||
core_io = { git = "https://git.m-labs.hk/M-Labs/rs-core_io.git", rev = "e9d3edf027", features = ["collections"] }
|
||||
embedded-hal = "0.2"
|
||||
nb = "1.0"
|
||||
void = { version = "1", default-features = false }
|
||||
byteorder = { version = "1.3", default-features = false }
|
||||
|
||||
io = { path = "../libio", features = ["byteorder"] }
|
||||
libboard_zynq = { path = "@@ZYNQ_RS@@/libboard_zynq" }
|
||||
libsupport_zynq = { path = "@@ZYNQ_RS@@/libsupport_zynq", default-features = false, features = ["alloc_core"] }
|
||||
libboard_zynq = { path = "@@ZYNQ_RS@@/libboard_zynq", features = ["async"] }
|
||||
libregister = { path = "@@ZYNQ_RS@@/libregister" }
|
||||
libconfig = { path = "@@ZYNQ_RS@@/libconfig", features = ["fat_lfn"] }
|
||||
libcortex_a9 = { path = "@@ZYNQ_RS@@/libcortex_a9" }
|
||||
|
||||
312
src/libboard_artiq/src/cxp_camera_setup.rs
Normal file
312
src/libboard_artiq/src/cxp_camera_setup.rs
Normal file
@@ -0,0 +1,312 @@
|
||||
use core::fmt;
|
||||
|
||||
use libasync::task;
|
||||
use libboard_zynq::timer;
|
||||
use log::debug;
|
||||
|
||||
use crate::{cxp_ctrl::Error as CtrlErr,
|
||||
cxp_packet::{async_read_u32, async_read_u64, async_write_u32, async_write_u64, reset_tag,
|
||||
send_test_packet, write_bytes_no_ack},
|
||||
cxp_phys::{CXPSpeed, rx, tx},
|
||||
pl::csr};
|
||||
|
||||
// Bootstrap registers address
|
||||
const STANDARD: u32 = 0x0000;
|
||||
const REVISION: u32 = 0x0004;
|
||||
const CONNECTION_RESET: u32 = 0x4000;
|
||||
const DEVICE_CONNECTION_ID: u32 = 0x4004;
|
||||
const MASTER_HOST_CONNECTION_ID: u32 = 0x4008;
|
||||
|
||||
const STREAM_PACKET_SIZE_MAX: u32 = 0x4010;
|
||||
const CONNECTION_CFG: u32 = 0x4014;
|
||||
const CONNECTION_CFG_DEFAULT: u32 = 0x4018;
|
||||
|
||||
const TESTMODE: u32 = 0x401C;
|
||||
const TEST_ERROR_COUNT_SELECTOR: u32 = 0x4020;
|
||||
const TEST_ERROR_COUNT: u32 = 0x4024;
|
||||
const TEST_PACKET_COUNT_TX: u32 = 0x4028;
|
||||
const TEST_PACKET_COUNT_RX: u32 = 0x4030;
|
||||
|
||||
const VERSION_SUPPORTED: u32 = 0x4044;
|
||||
const VERSION_USED: u32 = 0x4048;
|
||||
|
||||
// Setup const
|
||||
const CHANNEL_LEN: u8 = 1;
|
||||
const HOST_CONNECTION_ID: u32 = 0x00006303; // TODO: rename to CXP grabber sinara number when it comes out
|
||||
// The MAX_STREAM_PAK_SIZE should be set as large as possible - Section 9.5.2 (CXP-001-2021)
|
||||
// Since the ROI pipeline just consume all pixel data without buffering, any big number will do.
|
||||
const MAX_STREAM_PAK_SIZE: u32 = 16384; // 16 KiB
|
||||
const TX_TEST_CNT: u8 = 10;
|
||||
// From DS191 (v1.18.1), max CDR time lock is 37*10^6 UI,
|
||||
// 37*10^6 UI at lowest CXP linerate of 1.25Gbps = 29.6 ms, double it to account for overhead
|
||||
const MONITOR_TIMEOUT_MS: u64 = 60;
|
||||
|
||||
pub enum Error {
|
||||
CameraNotDetected,
|
||||
ConnectionLost,
|
||||
UnstableRX,
|
||||
UnstableTX,
|
||||
UnsupportedSpeed(u32),
|
||||
UnsupportedTopology,
|
||||
UnsupportedVersion,
|
||||
CtrlPacketError(CtrlErr),
|
||||
}
|
||||
|
||||
impl From<CtrlErr> for Error {
|
||||
fn from(value: CtrlErr) -> Error {
|
||||
Error::CtrlPacketError(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
&Error::CameraNotDetected => write!(f, "CameraNotDetected"),
|
||||
&Error::ConnectionLost => write!(f, "ConnectionLost - Channel #0 cannot be detected"),
|
||||
&Error::UnstableRX => write!(f, "UnstableRX - RX connection test failed"),
|
||||
&Error::UnstableTX => write!(f, "UnstableTX - TX connection test failed"),
|
||||
&Error::UnsupportedSpeed(linerate_code) => write!(
|
||||
f,
|
||||
"UnsupportedSpeed - {:#X} linerate code is not supported",
|
||||
linerate_code
|
||||
),
|
||||
&Error::UnsupportedTopology => {
|
||||
write!(
|
||||
f,
|
||||
"UnsupportedTopology - Channel #0 should be connected to the master channel"
|
||||
)
|
||||
}
|
||||
&Error::UnsupportedVersion => write!(
|
||||
f,
|
||||
"UnsupportedVersion - Cannot find a compatible protocol version between the cxp grabber & camera"
|
||||
),
|
||||
&Error::CtrlPacketError(ref err) => write!(f, "{}", err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn master_channel_ready() -> bool {
|
||||
unsafe { csr::cxp_grabber::core_rx_ready_read() == 1 }
|
||||
}
|
||||
|
||||
async fn monitor_channel_status_timeout() -> Result<(), Error> {
|
||||
let limit = timer::get_ms() + MONITOR_TIMEOUT_MS;
|
||||
while timer::get_ms() < limit {
|
||||
task::r#yield().await;
|
||||
if master_channel_ready() {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
Err(Error::ConnectionLost)
|
||||
}
|
||||
|
||||
pub async fn discover_camera() -> Result<(), Error> {
|
||||
// Section 7.6 (CXP-001-2021)
|
||||
// 1.25Gbps (CXP_1) and 3.125Gbps (CXP_3) are the discovery rate
|
||||
// both linerate need to be checked as camera only support ONE of discovery rates
|
||||
for speed in [CXPSpeed::CXP1, CXPSpeed::CXP3].iter() {
|
||||
// Section 12.1.2 (CXP-001-2021)
|
||||
// set tx linerate -> send ConnectionReset -> wait 200ms -> set rx linerate -> monitor connection status with a timeout
|
||||
tx::change_linerate(*speed);
|
||||
write_bytes_no_ack(CONNECTION_RESET, &1_u32.to_be_bytes(), false)?;
|
||||
timer::async_delay_ms(200).await;
|
||||
rx::change_linerate(*speed);
|
||||
|
||||
// Check the camera is responsive in case the RX phy picks up noise as an IDLE word
|
||||
if monitor_channel_status_timeout().await.is_ok() {
|
||||
if let Ok(0xC0A79AE5) = async_read_u32(STANDARD, false).await {
|
||||
debug!("camera detected at linerate {:}", speed);
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(Error::CameraNotDetected)
|
||||
}
|
||||
|
||||
async fn check_master_channel() -> Result<(), Error> {
|
||||
if async_read_u32(DEVICE_CONNECTION_ID, false).await? == 0 {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::UnsupportedTopology)
|
||||
}
|
||||
}
|
||||
|
||||
async fn disable_excess_channels() -> Result<(), Error> {
|
||||
let current_cfg = async_read_u32(CONNECTION_CFG, false).await?;
|
||||
let active_camera_chs = current_cfg >> 16;
|
||||
// After camera receive ConnectionReset, only the master connection should be active while
|
||||
// the extension connections shall not be active - Section 12.3.33 (CXP-001-2021)
|
||||
// In case some camera didn't follow the spec properly (e.g. Basler boA2448-250cm),
|
||||
// the grabber need to manually disable the excess channels
|
||||
if active_camera_chs > CHANNEL_LEN as u32 {
|
||||
debug!(
|
||||
"only {} channel(s) is available on cxp grabber, disabling excess channels on camera",
|
||||
CHANNEL_LEN
|
||||
);
|
||||
// disable excess channels and preserve the discovery linerate
|
||||
async_write_u32(CONNECTION_CFG, current_cfg & 0xFFFF | (CHANNEL_LEN as u32) << 16, false).await?;
|
||||
|
||||
// check if the master channel is down after the cfg change
|
||||
monitor_channel_status_timeout().await
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
async fn set_host_connection_id() -> Result<(), Error> {
|
||||
debug!("set host connection id to = {:#X}", HOST_CONNECTION_ID);
|
||||
async_write_u32(MASTER_HOST_CONNECTION_ID, HOST_CONNECTION_ID, false).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn negotiate_cxp_version() -> Result<bool, Error> {
|
||||
let rev = async_read_u32(REVISION, false).await?;
|
||||
|
||||
let mut major_rev: u32 = rev >> 16;
|
||||
let mut minor_rev: u32 = rev & 0xFF;
|
||||
debug!("camera's CoaXPress revision is {}.{}", major_rev, minor_rev);
|
||||
|
||||
// Section 12.1.4 (CXP-001-2021)
|
||||
// For CXP 2.0 and onward, Host need to check the VersionSupported register to determine
|
||||
// the highest common version that supported by both device & host
|
||||
if major_rev >= 2 {
|
||||
let reg = async_read_u32(VERSION_SUPPORTED, false).await?;
|
||||
|
||||
// grabber support CXP 2.1, 2.0 and 1.1 only
|
||||
if ((reg >> 3) & 1) == 1 {
|
||||
major_rev = 2;
|
||||
minor_rev = 1;
|
||||
} else if ((reg >> 2) & 1) == 1 {
|
||||
major_rev = 2;
|
||||
minor_rev = 0;
|
||||
} else if ((reg >> 1) & 1) == 1 {
|
||||
major_rev = 1;
|
||||
minor_rev = 1;
|
||||
} else {
|
||||
return Err(Error::UnsupportedVersion);
|
||||
}
|
||||
|
||||
async_write_u32(VERSION_USED, major_rev << 16 | minor_rev, false).await?;
|
||||
}
|
||||
debug!(
|
||||
"both camera and cxp grabber support CoaXPress {}.{}, switch to CoaXPress {}.{} protocol now",
|
||||
major_rev, minor_rev, major_rev, minor_rev
|
||||
);
|
||||
|
||||
Ok(major_rev >= 2)
|
||||
}
|
||||
|
||||
async fn negotiate_pak_max_size(with_tag: bool) -> Result<(), Error> {
|
||||
async_write_u32(STREAM_PACKET_SIZE_MAX, MAX_STREAM_PAK_SIZE, with_tag).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn decode_cxp_speed(linerate_code: u32) -> Option<CXPSpeed> {
|
||||
match linerate_code {
|
||||
0x28 => Some(CXPSpeed::CXP1),
|
||||
0x30 => Some(CXPSpeed::CXP2),
|
||||
0x38 => Some(CXPSpeed::CXP3),
|
||||
0x40 => Some(CXPSpeed::CXP5),
|
||||
0x48 => Some(CXPSpeed::CXP6),
|
||||
0x50 => Some(CXPSpeed::CXP10),
|
||||
0x58 => Some(CXPSpeed::CXP12),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
async fn set_operation_linerate(with_tag: bool) -> Result<(), Error> {
|
||||
let recommended_linerate_code = async_read_u32(CONNECTION_CFG_DEFAULT, with_tag).await? & 0xFFFF;
|
||||
|
||||
if let Some(speed) = decode_cxp_speed(recommended_linerate_code) {
|
||||
debug!("changing linerate to {}", speed);
|
||||
|
||||
// preserve the number of active channels
|
||||
let current_cfg = async_read_u32(CONNECTION_CFG, with_tag).await?;
|
||||
async_write_u32(
|
||||
CONNECTION_CFG,
|
||||
current_cfg & 0xFFFF0000 | recommended_linerate_code,
|
||||
with_tag,
|
||||
)
|
||||
.await?;
|
||||
|
||||
tx::change_linerate(speed);
|
||||
rx::change_linerate(speed);
|
||||
monitor_channel_status_timeout().await
|
||||
} else {
|
||||
Err(Error::UnsupportedSpeed(recommended_linerate_code))
|
||||
}
|
||||
}
|
||||
|
||||
async fn test_counter_reset(with_tag: bool) -> Result<(), Error> {
|
||||
unsafe { csr::cxp_grabber::core_rx_test_counts_reset_write(1) };
|
||||
async_write_u32(TEST_ERROR_COUNT_SELECTOR, 0, with_tag).await?;
|
||||
async_write_u32(TEST_ERROR_COUNT, 0, with_tag).await?;
|
||||
async_write_u64(TEST_PACKET_COUNT_TX, 0, with_tag).await?;
|
||||
async_write_u64(TEST_PACKET_COUNT_RX, 0, with_tag).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn verify_test_result(with_tag: bool) -> Result<(), Error> {
|
||||
async_write_u32(TEST_ERROR_COUNT_SELECTOR, 0, with_tag).await?;
|
||||
|
||||
// Section 9.9.3 (CXP-001-2021)
|
||||
// verify grabber -> camera connection test result
|
||||
if async_read_u64(TEST_PACKET_COUNT_RX, with_tag).await? != TX_TEST_CNT as u64 {
|
||||
return Err(Error::UnstableTX);
|
||||
};
|
||||
if async_read_u32(TEST_ERROR_COUNT, with_tag).await? > 0 {
|
||||
return Err(Error::UnstableTX);
|
||||
};
|
||||
|
||||
// Section 9.9.4 (CXP-001-2021)
|
||||
// verify camera -> grabber connection test result
|
||||
let camera_test_pak_cnt = async_read_u64(TEST_PACKET_COUNT_TX, true).await?;
|
||||
unsafe {
|
||||
if csr::cxp_grabber::core_rx_test_packet_counter_read() != camera_test_pak_cnt as u16 {
|
||||
return Err(Error::UnstableRX);
|
||||
};
|
||||
if csr::cxp_grabber::core_rx_test_error_counter_read() > 0 {
|
||||
return Err(Error::UnstableRX);
|
||||
};
|
||||
};
|
||||
debug!("channel #0 passed connection test");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn test_channel_stability(with_tag: bool) -> Result<(), Error> {
|
||||
test_counter_reset(with_tag).await?;
|
||||
|
||||
// cxp grabber -> camera connection test
|
||||
for _ in 0..TX_TEST_CNT {
|
||||
send_test_packet()?;
|
||||
// sending the whole test sequence @ 20.833Mbps will take a minimum of 1.972ms
|
||||
// and leave some room to send IDLE word
|
||||
timer::async_delay_ms(2).await;
|
||||
}
|
||||
|
||||
// camera -> grabber connection test
|
||||
// enabling the TESTMODE on master channel will send test packets on all channels
|
||||
async_write_u32(TESTMODE, 1, with_tag).await?;
|
||||
timer::async_delay_ms(2000).await;
|
||||
async_write_u32(TESTMODE, 0, with_tag).await?;
|
||||
|
||||
verify_test_result(with_tag).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn camera_setup() -> Result<bool, Error> {
|
||||
reset_tag();
|
||||
check_master_channel().await?;
|
||||
|
||||
disable_excess_channels().await?;
|
||||
set_host_connection_id().await?;
|
||||
let with_tag = negotiate_cxp_version().await?;
|
||||
|
||||
negotiate_pak_max_size(with_tag).await?;
|
||||
set_operation_linerate(with_tag).await?;
|
||||
|
||||
test_channel_stability(with_tag).await?;
|
||||
|
||||
Ok(with_tag)
|
||||
}
|
||||
250
src/libboard_artiq/src/cxp_ctrl.rs
Normal file
250
src/libboard_artiq/src/cxp_ctrl.rs
Normal file
@@ -0,0 +1,250 @@
|
||||
use core::fmt;
|
||||
|
||||
use byteorder::{ByteOrder, NetworkEndian};
|
||||
use core_io::{Error as IoError, Read, Write};
|
||||
use crc::crc32::checksum_ieee;
|
||||
use io::{Cursor, ProtoRead, ProtoWrite};
|
||||
|
||||
pub const CTRL_PACKET_MAXSIZE: usize = 128; // for compatibility with version1.x compliant Devices - Section 12.1.6 (CXP-001-2021)
|
||||
pub const DATA_MAXSIZE: usize =
|
||||
CTRL_PACKET_MAXSIZE - /*packet start KCodes, data packet types, CMD, Tag, Addr, CRC, packet end KCode*/4*7;
|
||||
|
||||
pub enum Error {
|
||||
CorruptedPacket,
|
||||
CtrlAckError(u8),
|
||||
Io(IoError),
|
||||
LengthOutOfRange(u32),
|
||||
TagMismatch,
|
||||
TimedOut,
|
||||
UnexpectedReply,
|
||||
UnknownPacket(u8),
|
||||
}
|
||||
|
||||
impl fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
&Error::CorruptedPacket => write!(f, "CorruptedPacket - Received packet fail CRC test"),
|
||||
&Error::CtrlAckError(ref ack_code) => match ack_code {
|
||||
0x40 => write!(f, "CtrlAckError - Invalid Address"),
|
||||
0x41 => write!(f, "CtrlAckError - Invalid data for the address"),
|
||||
0x42 => write!(f, "CtrlAckError - Invalid operation code"),
|
||||
0x43 => write!(f, "CtrlAckError - Write attempted to a read-only address"),
|
||||
0x44 => write!(f, "CtrlAckError - Read attempted from a write-only address"),
|
||||
0x45 => write!(f, "CtrlAckError - Size field too large, exceed packet size limit"),
|
||||
0x46 => write!(f, "CtrlAckError - Message size is inconsistent with size field"),
|
||||
0x47 => write!(f, "CtrlAckError - Malformed packet"),
|
||||
0x80 => write!(f, "CtrlAckError - Failed CRC test in last received command"),
|
||||
_ => write!(f, "CtrlAckError - Unknown ack code {:#X}", ack_code),
|
||||
},
|
||||
&Error::Io(ref err) => write!(f, "IoError - {:?}", err),
|
||||
&Error::LengthOutOfRange(length) => write!(
|
||||
f,
|
||||
"LengthOutOfRange - Message length {} is not between 1 and {}",
|
||||
length, DATA_MAXSIZE
|
||||
),
|
||||
&Error::TagMismatch => write!(f, "TagMismatch - Received tag is different from the transmitted tag"),
|
||||
&Error::TimedOut => write!(f, "MessageTimedOut"),
|
||||
&Error::UnexpectedReply => write!(f, "UnexpectedReply"),
|
||||
&Error::UnknownPacket(packet_type) => {
|
||||
write!(f, "UnknownPacket - Unknown packet type id {:#X} ", packet_type)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<IoError> for Error {
|
||||
fn from(value: IoError) -> Error {
|
||||
Error::Io(value)
|
||||
}
|
||||
}
|
||||
|
||||
fn get_cxp_crc(bytes: &[u8]) -> u32 {
|
||||
// Section 9.2.2.2 (CXP-001-2021)
|
||||
// Only Control packet need CRC32 appended in the end of the packet
|
||||
// CoaXpress use the polynomial of IEEE-802.3 (Ethernet) CRC but the checksum calculation is different
|
||||
(!checksum_ieee(bytes)).swap_bytes()
|
||||
}
|
||||
|
||||
trait CxpRead: Read {
|
||||
fn read_exact_4x(&mut self, buf: &mut [u8]) -> Result<(), Error> {
|
||||
let mut temp = [0u8; 4];
|
||||
for byte in buf {
|
||||
// Section 9.2.2.1 (CXP-001-2021)
|
||||
// decoder should immune to single bit errors when handling 4x duplicated characters
|
||||
self.read_exact(&mut temp)?;
|
||||
let [a, b, c, d] = temp;
|
||||
// vote and return majority
|
||||
*byte = a & b & c | a & b & d | a & c & d | b & c & d;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn read_4x_u8(&mut self) -> Result<u8, Error> {
|
||||
let mut bytes = [0; 1];
|
||||
self.read_exact_4x(&mut bytes)?;
|
||||
Ok(bytes[0])
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Read> CxpRead for T {}
|
||||
impl<T: Write> CxpWrite for T {}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum RXCTRLPacket {
|
||||
CtrlReply {
|
||||
tag: Option<u8>,
|
||||
length: u32,
|
||||
data: [u8; DATA_MAXSIZE],
|
||||
},
|
||||
CtrlDelay {
|
||||
tag: Option<u8>,
|
||||
time: u32,
|
||||
},
|
||||
CtrlAck {
|
||||
tag: Option<u8>,
|
||||
},
|
||||
}
|
||||
|
||||
impl RXCTRLPacket {
|
||||
pub fn read_from(reader: &mut Cursor<&[u8]>) -> Result<Self, Error> {
|
||||
match reader.read_4x_u8()? {
|
||||
0x03 => RXCTRLPacket::get_ctrl_packet(reader, false),
|
||||
0x06 => RXCTRLPacket::get_ctrl_packet(reader, true),
|
||||
ty => Err(Error::UnknownPacket(ty)),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_ctrl_packet(reader: &mut Cursor<&[u8]>, with_tag: bool) -> Result<Self, Error> {
|
||||
let mut tag: Option<u8> = None;
|
||||
if with_tag {
|
||||
tag = Some(reader.read_4x_u8()?);
|
||||
}
|
||||
|
||||
let ackcode = reader.read_4x_u8()?;
|
||||
|
||||
match ackcode {
|
||||
0x00 | 0x04 => {
|
||||
let length = reader.read_u32::<NetworkEndian>()?;
|
||||
let mut data: [u8; DATA_MAXSIZE] = [0; DATA_MAXSIZE];
|
||||
reader.read(&mut data[0..length as usize])?;
|
||||
|
||||
// Section 9.6.3 (CXP-001-2021)
|
||||
// when length is not multiple of 4, dummy bits are padded to align to the word boundary
|
||||
// set position to next word boundary for CRC calculation
|
||||
let padding = (4 - (reader.position() % 4)) % 4;
|
||||
reader.set_position(reader.position() + padding);
|
||||
|
||||
// Section 9.6.3 (CXP-001-2021)
|
||||
// only bytes after the first 4 are used in calculating the checksum
|
||||
let checksum = get_cxp_crc(&reader.get_ref()[4..reader.position()]);
|
||||
if reader.read_u32::<NetworkEndian>()? != checksum {
|
||||
return Err(Error::CorruptedPacket);
|
||||
}
|
||||
|
||||
if ackcode == 0x00 {
|
||||
return Ok(RXCTRLPacket::CtrlReply { tag, length, data });
|
||||
} else {
|
||||
return Ok(RXCTRLPacket::CtrlDelay {
|
||||
tag,
|
||||
time: NetworkEndian::read_u32(&data[..4]),
|
||||
});
|
||||
}
|
||||
}
|
||||
0x01 => return Ok(RXCTRLPacket::CtrlAck { tag }),
|
||||
_ => return Err(Error::CtrlAckError(ackcode)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
trait CxpWrite: Write {
|
||||
fn write_all_4x(&mut self, buf: &[u8]) -> Result<(), Error> {
|
||||
for byte in buf {
|
||||
self.write_all(&[*byte; 4])?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_4x_u8(&mut self, value: u8) -> Result<(), Error> {
|
||||
self.write_all_4x(&[value])
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum TXCTRLPacket {
|
||||
CtrlRead {
|
||||
tag: Option<u8>,
|
||||
addr: u32,
|
||||
length: u32,
|
||||
},
|
||||
CtrlWrite {
|
||||
tag: Option<u8>,
|
||||
addr: u32,
|
||||
length: u32,
|
||||
data: [u8; DATA_MAXSIZE],
|
||||
},
|
||||
}
|
||||
|
||||
impl TXCTRLPacket {
|
||||
pub fn write_to(&self, writer: &mut Cursor<&mut [u8]>) -> Result<(), Error> {
|
||||
match *self {
|
||||
TXCTRLPacket::CtrlRead { tag, addr, length } => {
|
||||
match tag {
|
||||
Some(t) => {
|
||||
writer.write_4x_u8(0x05)?;
|
||||
writer.write_4x_u8(t)?;
|
||||
}
|
||||
None => {
|
||||
writer.write_4x_u8(0x02)?;
|
||||
}
|
||||
}
|
||||
|
||||
let mut bytes = [0; 3];
|
||||
NetworkEndian::write_u24(&mut bytes, length);
|
||||
writer.write_all(&[0x00, bytes[0], bytes[1], bytes[2]])?;
|
||||
|
||||
writer.write_u32::<NetworkEndian>(addr)?;
|
||||
|
||||
// Section 9.6.2 (CXP-001-2021)
|
||||
// only bytes after the first 4 are used in calculating the checksum
|
||||
let checksum = get_cxp_crc(&writer.get_ref()[4..writer.position()]);
|
||||
writer.write_u32::<NetworkEndian>(checksum)?;
|
||||
}
|
||||
TXCTRLPacket::CtrlWrite {
|
||||
tag,
|
||||
addr,
|
||||
length,
|
||||
data,
|
||||
} => {
|
||||
match tag {
|
||||
Some(t) => {
|
||||
writer.write_4x_u8(0x05)?;
|
||||
writer.write_4x_u8(t)?;
|
||||
}
|
||||
None => {
|
||||
writer.write_4x_u8(0x02)?;
|
||||
}
|
||||
}
|
||||
|
||||
let mut bytes = [0; 3];
|
||||
NetworkEndian::write_u24(&mut bytes, length);
|
||||
writer.write_all(&[0x01, bytes[0], bytes[1], bytes[2]])?;
|
||||
|
||||
writer.write_u32::<NetworkEndian>(addr)?;
|
||||
writer.write_all(&data[0..length as usize])?;
|
||||
|
||||
// Section 9.6.2 (CXP-001-2021)
|
||||
// when length is not multiple of 4, dummy bites are padded to align to the word boundary
|
||||
let padding = (4 - (writer.position() % 4)) % 4;
|
||||
for _ in 0..padding {
|
||||
writer.write_u8(0)?;
|
||||
}
|
||||
|
||||
// Section 9.6.2 (CXP-001-2021)
|
||||
// only bytes after the first 4 are used in calculating the checksum
|
||||
let checksum = get_cxp_crc(&writer.get_ref()[4..writer.position()]);
|
||||
writer.write_u32::<NetworkEndian>(checksum)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
134
src/libboard_artiq/src/cxp_grabber.rs
Normal file
134
src/libboard_artiq/src/cxp_grabber.rs
Normal file
@@ -0,0 +1,134 @@
|
||||
use libboard_zynq::{i2c, timer};
|
||||
use libcortex_a9::mutex::Mutex;
|
||||
use log::{error, info};
|
||||
|
||||
#[cfg(has_cxp_led)]
|
||||
use crate::cxp_led::{LEDState, update_led};
|
||||
use crate::{cxp_camera_setup::{camera_setup, discover_camera, master_channel_ready},
|
||||
pl::csr};
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
enum State {
|
||||
Connected,
|
||||
Detected,
|
||||
Disconnected,
|
||||
}
|
||||
|
||||
// Mutex as they are needed by core1 cxp api calls
|
||||
static STATE: Mutex<State> = Mutex::new(State::Disconnected);
|
||||
static WITH_TAG: Mutex<bool> = Mutex::new(false);
|
||||
|
||||
pub fn camera_connected() -> bool {
|
||||
*STATE.lock() == State::Connected
|
||||
}
|
||||
|
||||
pub fn with_tag() -> bool {
|
||||
*WITH_TAG.lock()
|
||||
}
|
||||
|
||||
pub async fn async_camera_connected() -> bool {
|
||||
*STATE.async_lock().await == State::Connected
|
||||
}
|
||||
|
||||
pub async fn async_with_tag() -> bool {
|
||||
*WITH_TAG.async_lock().await
|
||||
}
|
||||
|
||||
pub async fn thread(i2c: &mut i2c::I2c) {
|
||||
loop {
|
||||
tick(i2c).await;
|
||||
timer::async_delay_ms(200).await;
|
||||
}
|
||||
}
|
||||
|
||||
async fn tick(_i2c: &mut i2c::I2c) {
|
||||
// Get the value and drop the mutexguard to prevent blocking other async task that need to use it
|
||||
let current_state = { *STATE.async_lock().await };
|
||||
let next_state = match current_state {
|
||||
State::Disconnected => {
|
||||
#[cfg(has_cxp_led)]
|
||||
update_led(_i2c, LEDState::RedFlash1Hz);
|
||||
match discover_camera().await {
|
||||
Ok(_) => {
|
||||
info!("camera detected, setting up camera...");
|
||||
State::Detected
|
||||
}
|
||||
Err(_) => State::Disconnected,
|
||||
}
|
||||
}
|
||||
State::Detected => {
|
||||
#[cfg(has_cxp_led)]
|
||||
update_led(_i2c, LEDState::OrangeFlash12Hz5);
|
||||
match camera_setup().await {
|
||||
Ok(with_tag) => {
|
||||
info!("camera setup complete");
|
||||
*WITH_TAG.async_lock().await = with_tag;
|
||||
State::Connected
|
||||
}
|
||||
Err(e) => {
|
||||
error!("camera setup failure: {}", e);
|
||||
*WITH_TAG.async_lock().await = false;
|
||||
State::Disconnected
|
||||
}
|
||||
}
|
||||
}
|
||||
State::Connected => {
|
||||
#[cfg(has_cxp_led)]
|
||||
update_led(_i2c, LEDState::GreenSolid);
|
||||
if master_channel_ready() {
|
||||
unsafe {
|
||||
if csr::cxp_grabber::stream_decoder_crc_error_read() == 1 {
|
||||
error!("frame packet has CRC error");
|
||||
csr::cxp_grabber::stream_decoder_crc_error_write(1);
|
||||
};
|
||||
|
||||
if csr::cxp_grabber::stream_decoder_stream_type_error_read() == 1 {
|
||||
error!("Non CoaXPress stream type detected, the CXP grabber doesn't support GenDC stream type");
|
||||
csr::cxp_grabber::stream_decoder_stream_type_error_write(1);
|
||||
};
|
||||
|
||||
if csr::cxp_grabber::core_rx_trigger_ack_read() == 1 {
|
||||
info!("received CXP linktrigger ack");
|
||||
csr::cxp_grabber::core_rx_trigger_ack_write(1);
|
||||
};
|
||||
|
||||
if csr::cxp_grabber::stream_decoder_new_frame_read() == 1 {
|
||||
let width = csr::cxp_grabber::stream_decoder_x_size_read();
|
||||
let height = csr::cxp_grabber::stream_decoder_y_size_read();
|
||||
match csr::cxp_grabber::stream_decoder_pixel_format_code_read() {
|
||||
0x0101 => info!("received frame: {}x{} with MONO8 format", width, height),
|
||||
0x0102 => info!("received frame: {}x{} with MONO10 format", width, height),
|
||||
0x0103 => info!("received frame: {}x{} with MONO12 format", width, height),
|
||||
0x0104 => info!("received frame: {}x{} with MONO14 format", width, height),
|
||||
0x0105 => info!("received frame: {}x{} with MONO16 format", width, height),
|
||||
_ => info!("received frame: {}x{} with Unsupported pixel format", width, height),
|
||||
};
|
||||
csr::cxp_grabber::stream_decoder_new_frame_write(1);
|
||||
};
|
||||
}
|
||||
State::Connected
|
||||
} else {
|
||||
*WITH_TAG.async_lock().await = false;
|
||||
info!("camera disconnected");
|
||||
State::Disconnected
|
||||
}
|
||||
}
|
||||
};
|
||||
{
|
||||
*STATE.async_lock().await = next_state
|
||||
};
|
||||
}
|
||||
|
||||
pub fn roi_viewer_setup(x0: u16, y0: u16, x1: u16, y1: u16) {
|
||||
unsafe {
|
||||
// flush the fifo before arming
|
||||
while csr::cxp_grabber::roi_viewer_fifo_stb_read() == 1 {
|
||||
csr::cxp_grabber::roi_viewer_fifo_ack_write(1);
|
||||
}
|
||||
csr::cxp_grabber::roi_viewer_x0_write(x0);
|
||||
csr::cxp_grabber::roi_viewer_x1_write(x1);
|
||||
csr::cxp_grabber::roi_viewer_y0_write(y0);
|
||||
csr::cxp_grabber::roi_viewer_y1_write(y1);
|
||||
csr::cxp_grabber::roi_viewer_arm_write(1);
|
||||
}
|
||||
}
|
||||
84
src/libboard_artiq/src/cxp_led.rs
Normal file
84
src/libboard_artiq/src/cxp_led.rs
Normal file
@@ -0,0 +1,84 @@
|
||||
use libboard_zynq::i2c;
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub enum LEDState {
|
||||
Off,
|
||||
RedFlash1Hz, // Not connected
|
||||
OrangeFlash12Hz5, // camera setup
|
||||
GreenSolid, // Connected
|
||||
}
|
||||
|
||||
const SFP_SLOT: u8 = 0;
|
||||
static mut PREVIOUS_STATE: LEDState = LEDState::Off;
|
||||
|
||||
const PCA9530_ADDR: u8 = 0x60;
|
||||
const PSC0_ADDR: u8 = 0x01;
|
||||
const PWM0_ADDR: u8 = 0x02;
|
||||
const LS0_ADDR: u8 = 0x05;
|
||||
|
||||
pub fn update_led(i2c: &mut i2c::I2c, state: LEDState) {
|
||||
if unsafe { state != PREVIOUS_STATE } {
|
||||
match write_settings(i2c, state) {
|
||||
Ok(_) => unsafe { PREVIOUS_STATE = state },
|
||||
Err(_) => {
|
||||
// stop i2c in case error happen during read/write operation
|
||||
let _ = i2c.stop();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn write_settings(i2c: &mut i2c::I2c, state: LEDState) -> Result<(), i2c::Error> {
|
||||
i2c.pca954x_select(0x70, None)?;
|
||||
i2c.pca954x_select(0x71, Some(SFP_SLOT))?;
|
||||
write_pwm_freq(i2c, state)?;
|
||||
write_pwm_duty(i2c, state)?;
|
||||
write_pwm_output(i2c, state)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_pwm_freq(i2c: &mut i2c::I2c, state: LEDState) -> Result<(), i2c::Error> {
|
||||
match state {
|
||||
LEDState::OrangeFlash12Hz5 => {
|
||||
i2c_write(i2c, PSC0_ADDR, 0xB)?; // set PWM0 frequency to 12.5 Hz
|
||||
}
|
||||
LEDState::RedFlash1Hz => {
|
||||
i2c_write(i2c, PSC0_ADDR, 0x97)?; // set PWM0 frequency to 1 Hz
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
fn write_pwm_duty(i2c: &mut i2c::I2c, state: LEDState) -> Result<(), i2c::Error> {
|
||||
match state {
|
||||
LEDState::OrangeFlash12Hz5 => {
|
||||
i2c_write(i2c, PWM0_ADDR, 0x40)?; // set PWM0 duty cycle to 25%
|
||||
}
|
||||
LEDState::RedFlash1Hz => {
|
||||
i2c_write(i2c, PWM0_ADDR, 0x33)?; // set PWM0 duty cycle to 20%
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
fn write_pwm_output(i2c: &mut i2c::I2c, state: LEDState) -> Result<(), i2c::Error> {
|
||||
let reg = match state {
|
||||
LEDState::GreenSolid => 0xF1, // Green: always on, Red: off
|
||||
LEDState::Off => 0xF0, // Green: off, Red: off
|
||||
LEDState::OrangeFlash12Hz5 => 0xFA, // Green: use PWM0, Red: use PWM0
|
||||
LEDState::RedFlash1Hz => 0xF8, // Green: off, Red: use PWM0
|
||||
};
|
||||
|
||||
i2c_write(i2c, LS0_ADDR, reg)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn i2c_write(i2c: &mut i2c::I2c, reg_addr: u8, val: u8) -> Result<(), i2c::Error> {
|
||||
i2c.start()?;
|
||||
i2c.write(PCA9530_ADDR << 1)?;
|
||||
i2c.write(reg_addr)?;
|
||||
i2c.write(val)?;
|
||||
i2c.stop()?;
|
||||
Ok(())
|
||||
}
|
||||
275
src/libboard_artiq/src/cxp_packet.rs
Normal file
275
src/libboard_artiq/src/cxp_packet.rs
Normal file
@@ -0,0 +1,275 @@
|
||||
use core::slice;
|
||||
|
||||
use byteorder::{ByteOrder, NetworkEndian};
|
||||
use io::Cursor;
|
||||
use libasync::task;
|
||||
use libboard_zynq::timer;
|
||||
|
||||
use crate::{cxp_ctrl::{CTRL_PACKET_MAXSIZE, DATA_MAXSIZE, Error, RXCTRLPacket, TXCTRLPacket},
|
||||
mem::mem,
|
||||
pl::csr};
|
||||
|
||||
const TRANSMISSION_TIMEOUT: u64 = 200;
|
||||
|
||||
// Section 9.6.1.2 (CXP-001-2021)
|
||||
// CTRL packet need to be tagged for CXP 2.0 or greater
|
||||
static mut TAG: u8 = 0;
|
||||
|
||||
pub fn reset_tag() {
|
||||
unsafe { TAG = 0 };
|
||||
}
|
||||
|
||||
fn increment_tag() {
|
||||
unsafe { TAG = TAG.wrapping_add(1) };
|
||||
}
|
||||
|
||||
fn check_tag(tag: Option<u8>) -> Result<(), Error> {
|
||||
unsafe {
|
||||
if tag.is_some() && tag != Some(TAG) {
|
||||
Err(Error::TagMismatch)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn receive_ctrl_packet() -> Result<Option<RXCTRLPacket>, Error> {
|
||||
if unsafe { csr::cxp_grabber::core_rx_pending_packet_read() == 1 } {
|
||||
unsafe {
|
||||
let read_buffer_ptr = csr::cxp_grabber::core_rx_read_ptr_read() as usize;
|
||||
let ptr = (mem::CXP_MEM_BASE + mem::CXP_MEM_SIZE / 2 + read_buffer_ptr * CTRL_PACKET_MAXSIZE) as *mut u32;
|
||||
|
||||
let mut reader = Cursor::new(slice::from_raw_parts(ptr as *const u8, CTRL_PACKET_MAXSIZE));
|
||||
let packet = RXCTRLPacket::read_from(&mut reader);
|
||||
|
||||
csr::cxp_grabber::core_rx_pending_packet_write(1);
|
||||
Ok(Some(packet?))
|
||||
}
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
fn receive_ctrl_packet_timeout(timeout_ms: u64) -> Result<RXCTRLPacket, Error> {
|
||||
// assume timer was initialized successfully
|
||||
let limit = timer::get_ms() + timeout_ms;
|
||||
while timer::get_ms() < limit {
|
||||
match receive_ctrl_packet()? {
|
||||
None => (),
|
||||
Some(packet) => return Ok(packet),
|
||||
}
|
||||
}
|
||||
Err(Error::TimedOut)
|
||||
}
|
||||
|
||||
async fn async_receive_ctrl_packet_timeout(timeout_ms: u64) -> Result<RXCTRLPacket, Error> {
|
||||
// assume timer was initialized successfully
|
||||
let limit = timer::get_ms() + timeout_ms;
|
||||
while timer::get_ms() < limit {
|
||||
match receive_ctrl_packet()? {
|
||||
None => (),
|
||||
Some(packet) => return Ok(packet),
|
||||
}
|
||||
task::r#yield().await;
|
||||
}
|
||||
Err(Error::TimedOut)
|
||||
}
|
||||
|
||||
fn send_ctrl_packet(packet: &TXCTRLPacket) -> Result<(), Error> {
|
||||
unsafe {
|
||||
while csr::cxp_grabber::core_tx_writer_busy_read() == 1 {}
|
||||
let ptr = mem::CXP_MEM_BASE as *mut u32;
|
||||
let mut writer = Cursor::new(slice::from_raw_parts_mut(ptr as *mut u8, CTRL_PACKET_MAXSIZE));
|
||||
|
||||
packet.write_to(&mut writer)?;
|
||||
|
||||
csr::cxp_grabber::core_tx_writer_word_len_write((writer.position() / 4) as u8);
|
||||
csr::cxp_grabber::core_tx_writer_stb_write(1);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn send_test_packet() -> Result<(), Error> {
|
||||
unsafe {
|
||||
while csr::cxp_grabber::core_tx_writer_busy_read() == 1 {}
|
||||
csr::cxp_grabber::core_tx_writer_stb_testseq_write(1);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_ctrl_ack(packet: RXCTRLPacket, timeout_ms: &mut u64) -> Result<bool, Error> {
|
||||
match packet {
|
||||
RXCTRLPacket::CtrlDelay { tag, time } => {
|
||||
check_tag(tag)?;
|
||||
*timeout_ms = time.into();
|
||||
Ok(false)
|
||||
}
|
||||
RXCTRLPacket::CtrlAck { tag } => {
|
||||
check_tag(tag)?;
|
||||
Ok(true)
|
||||
}
|
||||
_ => Err(Error::UnexpectedReply),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_ctrl_reply(
|
||||
packet: RXCTRLPacket,
|
||||
timeout_ms: &mut u64,
|
||||
expected_length: u32,
|
||||
) -> Result<Option<[u8; DATA_MAXSIZE]>, Error> {
|
||||
match packet {
|
||||
RXCTRLPacket::CtrlDelay { tag, time } => {
|
||||
check_tag(tag)?;
|
||||
*timeout_ms = time.into();
|
||||
Ok(None)
|
||||
}
|
||||
RXCTRLPacket::CtrlReply {
|
||||
tag,
|
||||
length: replied_length,
|
||||
data,
|
||||
} => {
|
||||
check_tag(tag)?;
|
||||
if replied_length != expected_length {
|
||||
return Err(Error::UnexpectedReply);
|
||||
};
|
||||
Ok(Some(data))
|
||||
}
|
||||
_ => Err(Error::UnexpectedReply),
|
||||
}
|
||||
}
|
||||
|
||||
fn check_length(length: u32) -> Result<(), Error> {
|
||||
if length > DATA_MAXSIZE as u32 || length == 0 {
|
||||
Err(Error::LengthOutOfRange(length))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write_bytes_no_ack(addr: u32, val: &[u8], with_tag: bool) -> Result<(), Error> {
|
||||
let length = val.len() as u32;
|
||||
check_length(length)?;
|
||||
|
||||
let mut data: [u8; DATA_MAXSIZE] = [0; DATA_MAXSIZE];
|
||||
data[..length as usize].clone_from_slice(val);
|
||||
|
||||
let tag: Option<u8> = if with_tag { Some(unsafe { TAG }) } else { None };
|
||||
send_ctrl_packet(&TXCTRLPacket::CtrlWrite {
|
||||
tag,
|
||||
addr,
|
||||
length,
|
||||
data,
|
||||
})
|
||||
}
|
||||
|
||||
fn write_bytes(addr: u32, val: &[u8], with_tag: bool) -> Result<(), Error> {
|
||||
write_bytes_no_ack(addr, val, with_tag)?;
|
||||
|
||||
let mut timeout_ms = TRANSMISSION_TIMEOUT;
|
||||
loop {
|
||||
let packet = receive_ctrl_packet_timeout(timeout_ms)?;
|
||||
if get_ctrl_ack(packet, &mut timeout_ms)? {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if with_tag {
|
||||
increment_tag();
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn write_u32(addr: u32, val: u32, with_tag: bool) -> Result<(), Error> {
|
||||
write_bytes(addr, &val.to_be_bytes(), with_tag)
|
||||
}
|
||||
|
||||
async fn async_write_bytes(addr: u32, val: &[u8], with_tag: bool) -> Result<(), Error> {
|
||||
write_bytes_no_ack(addr, val, with_tag)?;
|
||||
|
||||
let mut timeout_ms = TRANSMISSION_TIMEOUT;
|
||||
loop {
|
||||
let packet = async_receive_ctrl_packet_timeout(timeout_ms).await?;
|
||||
if get_ctrl_ack(packet, &mut timeout_ms)? {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if with_tag {
|
||||
increment_tag();
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn async_write_u32(addr: u32, val: u32, with_tag: bool) -> Result<(), Error> {
|
||||
async_write_bytes(addr, &val.to_be_bytes(), with_tag).await
|
||||
}
|
||||
|
||||
pub async fn async_write_u64(addr: u32, val: u64, with_tag: bool) -> Result<(), Error> {
|
||||
async_write_bytes(addr, &val.to_be_bytes(), with_tag).await
|
||||
}
|
||||
|
||||
pub fn read_bytes(addr: u32, bytes: &mut [u8], with_tag: bool) -> Result<(), Error> {
|
||||
let length = bytes.len() as u32;
|
||||
check_length(length)?;
|
||||
let tag: Option<u8> = if with_tag { Some(unsafe { TAG }) } else { None };
|
||||
send_ctrl_packet(&TXCTRLPacket::CtrlRead { tag, addr, length })?;
|
||||
|
||||
let mut timeout_ms = TRANSMISSION_TIMEOUT;
|
||||
loop {
|
||||
let packet = receive_ctrl_packet_timeout(timeout_ms)?;
|
||||
if let Some(data) = get_ctrl_reply(packet, &mut timeout_ms, length)? {
|
||||
bytes.copy_from_slice(&data[..length as usize]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if with_tag {
|
||||
increment_tag();
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn read_u32(addr: u32, with_tag: bool) -> Result<u32, Error> {
|
||||
let mut bytes: [u8; 4] = [0; 4];
|
||||
read_bytes(addr, &mut bytes, with_tag)?;
|
||||
let val = NetworkEndian::read_u32(&bytes);
|
||||
|
||||
Ok(val)
|
||||
}
|
||||
|
||||
pub async fn async_read_bytes(addr: u32, bytes: &mut [u8], with_tag: bool) -> Result<(), Error> {
|
||||
let length = bytes.len() as u32;
|
||||
check_length(length)?;
|
||||
let tag: Option<u8> = if with_tag { Some(unsafe { TAG }) } else { None };
|
||||
send_ctrl_packet(&TXCTRLPacket::CtrlRead { tag, addr, length })?;
|
||||
|
||||
let mut timeout_ms = TRANSMISSION_TIMEOUT;
|
||||
loop {
|
||||
let packet = async_receive_ctrl_packet_timeout(timeout_ms).await?;
|
||||
if let Some(data) = get_ctrl_reply(packet, &mut timeout_ms, length)? {
|
||||
bytes.copy_from_slice(&data[..length as usize]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if with_tag {
|
||||
increment_tag();
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn async_read_u32(addr: u32, with_tag: bool) -> Result<u32, Error> {
|
||||
let mut bytes: [u8; 4] = [0; 4];
|
||||
async_read_bytes(addr, &mut bytes, with_tag).await?;
|
||||
let val = NetworkEndian::read_u32(&bytes);
|
||||
|
||||
Ok(val)
|
||||
}
|
||||
|
||||
pub async fn async_read_u64(addr: u32, with_tag: bool) -> Result<u64, Error> {
|
||||
let mut bytes: [u8; 8] = [0; 8];
|
||||
async_read_bytes(addr, &mut bytes, with_tag).await?;
|
||||
let val = NetworkEndian::read_u64(&bytes);
|
||||
|
||||
Ok(val)
|
||||
}
|
||||
203
src/libboard_artiq/src/cxp_phys.rs
Normal file
203
src/libboard_artiq/src/cxp_phys.rs
Normal file
@@ -0,0 +1,203 @@
|
||||
use core::fmt;
|
||||
|
||||
use crate::pl::csr;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum CXPSpeed {
|
||||
CXP1,
|
||||
CXP2,
|
||||
CXP3,
|
||||
CXP5,
|
||||
CXP6,
|
||||
CXP10,
|
||||
CXP12,
|
||||
}
|
||||
|
||||
impl fmt::Display for CXPSpeed {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
&CXPSpeed::CXP1 => write!(f, "1.25 Gbps"),
|
||||
&CXPSpeed::CXP2 => write!(f, "2.5 Gbps"),
|
||||
&CXPSpeed::CXP3 => write!(f, "3.125 Gbps"),
|
||||
&CXPSpeed::CXP5 => write!(f, "5 Gbps"),
|
||||
&CXPSpeed::CXP6 => write!(f, "6.25 Gbps"),
|
||||
&CXPSpeed::CXP10 => write!(f, "10 Gbps"),
|
||||
&CXPSpeed::CXP12 => write!(f, "12.5 Gbps"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn setup() {
|
||||
let init_speed = CXPSpeed::CXP1;
|
||||
tx::setup();
|
||||
tx::change_linerate(init_speed);
|
||||
rx::setup();
|
||||
rx::change_linerate(init_speed);
|
||||
}
|
||||
|
||||
pub mod tx {
|
||||
use super::*;
|
||||
|
||||
pub fn setup() {
|
||||
unsafe {
|
||||
csr::cxp_grabber::phy_tx_enable_write(1);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn change_linerate(speed: CXPSpeed) {
|
||||
unsafe {
|
||||
match speed {
|
||||
CXPSpeed::CXP1 | CXPSpeed::CXP2 | CXPSpeed::CXP3 | CXPSpeed::CXP5 | CXPSpeed::CXP6 => {
|
||||
csr::cxp_grabber::phy_tx_bitrate2x_enable_write(0);
|
||||
}
|
||||
CXPSpeed::CXP10 | CXPSpeed::CXP12 => {
|
||||
csr::cxp_grabber::phy_tx_bitrate2x_enable_write(1);
|
||||
}
|
||||
};
|
||||
csr::cxp_grabber::phy_tx_clk_reset_write(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub mod rx {
|
||||
use super::*;
|
||||
|
||||
pub fn setup() {
|
||||
unsafe {
|
||||
csr::cxp_grabber::phy_rx_gtx_refclk_stable_write(1);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn change_linerate(speed: CXPSpeed) {
|
||||
change_qpll_fb_divider(speed);
|
||||
change_gtx_divider(speed);
|
||||
change_cdr_cfg(speed);
|
||||
change_eq_cfg(speed);
|
||||
|
||||
unsafe {
|
||||
csr::cxp_grabber::phy_rx_qpll_reset_write(1);
|
||||
while csr::cxp_grabber::phy_rx_qpll_locked_read() != 1 {}
|
||||
// Changing RXOUT_DIV via DRP requires a manual reset
|
||||
// https://adaptivesupport.amd.com/s/question/0D52E00006hplwnSAA/re-gtx-line-rate-change
|
||||
csr::cxp_grabber::phy_rx_gtx_restart_write(1);
|
||||
}
|
||||
}
|
||||
|
||||
fn change_qpll_fb_divider(speed: CXPSpeed) {
|
||||
let qpll_div_reg = match speed {
|
||||
CXPSpeed::CXP1 | CXPSpeed::CXP2 | CXPSpeed::CXP5 | CXPSpeed::CXP10 => 0x0120, // FB_Divider = 80, QPLL VCO @ 10GHz
|
||||
CXPSpeed::CXP3 | CXPSpeed::CXP6 | CXPSpeed::CXP12 => 0x0170, // FB_Divider = 100, QPLL VCO @ 12.5GHz
|
||||
};
|
||||
|
||||
qpll_write(0x36, qpll_div_reg);
|
||||
}
|
||||
|
||||
fn change_gtx_divider(speed: CXPSpeed) {
|
||||
let div_reg = match speed {
|
||||
CXPSpeed::CXP1 => 0x03, // TXOUT_DIV = 1, RXOUT_DIV = 8
|
||||
CXPSpeed::CXP2 | CXPSpeed::CXP3 => 0x02, // TXOUT_DIV = 1, RXOUT_DIV = 4
|
||||
CXPSpeed::CXP5 | CXPSpeed::CXP6 => 0x01, // TXOUT_DIV = 1, RXOUT_DIV = 2
|
||||
CXPSpeed::CXP10 | CXPSpeed::CXP12 => 0x00, // TXOUT_DIV = 1, RXOUT_DIV = 1
|
||||
};
|
||||
|
||||
gtx_write(0x88, div_reg);
|
||||
}
|
||||
|
||||
fn change_cdr_cfg(speed: CXPSpeed) {
|
||||
struct CdrConfig {
|
||||
pub cfg_reg0: u16, // addr = 0xA8
|
||||
pub cfg_reg1: u16, // addr = 0xA9
|
||||
pub cfg_reg2: u16, // addr = 0xAA
|
||||
pub cfg_reg3: u16, // addr = 0xAB
|
||||
pub cfg_reg4: u16, // addr = 0xAC
|
||||
}
|
||||
|
||||
let cdr_cfg = match speed {
|
||||
// when RXOUT_DIV = 8
|
||||
CXPSpeed::CXP1 => CdrConfig {
|
||||
cfg_reg0: 0x0020,
|
||||
cfg_reg1: 0x1008,
|
||||
cfg_reg2: 0x23FF,
|
||||
cfg_reg3: 0x0000,
|
||||
cfg_reg4: 0x0003,
|
||||
},
|
||||
// when RXOUT_DIV = 4
|
||||
CXPSpeed::CXP2 | CXPSpeed::CXP5 => CdrConfig {
|
||||
cfg_reg0: 0x0020,
|
||||
cfg_reg1: 0x1010,
|
||||
cfg_reg2: 0x23FF,
|
||||
cfg_reg3: 0x0000,
|
||||
cfg_reg4: 0x0003,
|
||||
},
|
||||
// when RXOUT_DIV= 2
|
||||
CXPSpeed::CXP3 | CXPSpeed::CXP6 => CdrConfig {
|
||||
cfg_reg0: 0x0020,
|
||||
cfg_reg1: 0x1020,
|
||||
cfg_reg2: 0x23FF,
|
||||
cfg_reg3: 0x0000,
|
||||
cfg_reg4: 0x0003,
|
||||
},
|
||||
// when RXOUT_DIV= 1
|
||||
CXPSpeed::CXP10 | CXPSpeed::CXP12 => CdrConfig {
|
||||
cfg_reg0: 0x0020,
|
||||
cfg_reg1: 0x1040,
|
||||
cfg_reg2: 0x23FF,
|
||||
cfg_reg3: 0x0000,
|
||||
cfg_reg4: 0x000B,
|
||||
},
|
||||
};
|
||||
|
||||
gtx_write(0x0A8, cdr_cfg.cfg_reg0);
|
||||
gtx_write(0x0A9, cdr_cfg.cfg_reg1);
|
||||
gtx_write(0x0AA, cdr_cfg.cfg_reg2);
|
||||
gtx_write(0x0AB, cdr_cfg.cfg_reg3);
|
||||
gtx_write(0x0AC, cdr_cfg.cfg_reg4);
|
||||
}
|
||||
|
||||
fn change_eq_cfg(speed: CXPSpeed) {
|
||||
let eq_cfg = match speed {
|
||||
CXPSpeed::CXP1 | CXPSpeed::CXP2 | CXPSpeed::CXP3 | CXPSpeed::CXP5 | CXPSpeed::CXP6 => 0x0904,
|
||||
CXPSpeed::CXP10 | CXPSpeed::CXP12 => 0x0104,
|
||||
};
|
||||
|
||||
gtx_write(0x029, eq_cfg);
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn gtx_read(address: u16) -> u16 {
|
||||
unsafe {
|
||||
csr::cxp_grabber::phy_rx_gtx_daddr_write(address);
|
||||
csr::cxp_grabber::phy_rx_gtx_dread_write(1);
|
||||
while csr::cxp_grabber::phy_rx_gtx_dready_read() != 1 {}
|
||||
csr::cxp_grabber::phy_rx_gtx_dout_read()
|
||||
}
|
||||
}
|
||||
|
||||
fn gtx_write(address: u16, value: u16) {
|
||||
unsafe {
|
||||
csr::cxp_grabber::phy_rx_gtx_daddr_write(address);
|
||||
csr::cxp_grabber::phy_rx_gtx_din_write(value);
|
||||
csr::cxp_grabber::phy_rx_gtx_din_stb_write(1);
|
||||
while csr::cxp_grabber::phy_rx_gtx_dready_read() != 1 {}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn qpll_read(address: u8) -> u16 {
|
||||
unsafe {
|
||||
csr::cxp_grabber::phy_rx_qpll_daddr_write(address);
|
||||
csr::cxp_grabber::phy_rx_qpll_dread_write(1);
|
||||
while csr::cxp_grabber::phy_rx_qpll_dready_read() != 1 {}
|
||||
csr::cxp_grabber::phy_rx_qpll_dout_read()
|
||||
}
|
||||
}
|
||||
|
||||
fn qpll_write(address: u8, value: u16) {
|
||||
unsafe {
|
||||
csr::cxp_grabber::phy_rx_qpll_daddr_write(address);
|
||||
csr::cxp_grabber::phy_rx_qpll_din_write(value);
|
||||
csr::cxp_grabber::phy_rx_qpll_din_stb_write(1);
|
||||
while csr::cxp_grabber::phy_rx_qpll_dready_read() != 1 {}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
use embedded_hal::prelude::_embedded_hal_blocking_delay_DelayUs;
|
||||
use libboard_zynq::timer::GlobalTimer;
|
||||
use libconfig::Config;
|
||||
use libsupport_zynq::alloc::format;
|
||||
use alloc::format;
|
||||
|
||||
use libboard_zynq::timer;
|
||||
use libconfig;
|
||||
use log::{debug, error, info};
|
||||
|
||||
use crate::pl;
|
||||
@@ -27,23 +27,23 @@ fn select_lane(lane_no: u8) {
|
||||
}
|
||||
}
|
||||
|
||||
fn apply_delay(tap: u8, timer: &mut GlobalTimer) {
|
||||
fn apply_delay(tap: u8) {
|
||||
unsafe {
|
||||
pl::csr::eem_transceiver::dly_cnt_in_write(tap);
|
||||
pl::csr::eem_transceiver::dly_ld_write(1);
|
||||
timer.delay_us(1);
|
||||
timer::delay_us(1);
|
||||
assert!(tap as u8 == pl::csr::eem_transceiver::dly_cnt_out_read());
|
||||
}
|
||||
}
|
||||
|
||||
fn apply_config(config: &SerdesConfig, timer: &mut GlobalTimer) {
|
||||
fn apply_config(config: &SerdesConfig) {
|
||||
for lane_no in 0..4 {
|
||||
select_lane(lane_no as u8);
|
||||
apply_delay(config.delay[lane_no], timer);
|
||||
apply_delay(config.delay[lane_no]);
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn assign_delay(timer: &mut GlobalTimer) -> SerdesConfig {
|
||||
unsafe fn assign_delay() -> SerdesConfig {
|
||||
// Select an appropriate delay for lane 0
|
||||
select_lane(0);
|
||||
|
||||
@@ -54,8 +54,8 @@ unsafe fn assign_delay(timer: &mut GlobalTimer) -> SerdesConfig {
|
||||
loop {
|
||||
let mut prev = None;
|
||||
for curr_dly in 0..32 {
|
||||
//let read_align = read_align_fn(curr_dly, timer);
|
||||
let curr_low_rate = read_align(curr_dly, timer);
|
||||
//let read_align = read_align_fn(curr_dly);
|
||||
let curr_low_rate = read_align(curr_dly);
|
||||
|
||||
if let Some(prev_low_rate) = prev {
|
||||
// This is potentially a crossover position
|
||||
@@ -86,7 +86,7 @@ unsafe fn assign_delay(timer: &mut GlobalTimer) -> SerdesConfig {
|
||||
|
||||
if best_dly.is_none() {
|
||||
error!("setup/hold timing calibration failed, retry in 1s...");
|
||||
timer.delay_us(1_000_000);
|
||||
timer::delay_us(1_000_000);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
@@ -94,7 +94,7 @@ unsafe fn assign_delay(timer: &mut GlobalTimer) -> SerdesConfig {
|
||||
|
||||
let best_dly = best_dly.unwrap();
|
||||
|
||||
apply_delay(best_dly, timer);
|
||||
apply_delay(best_dly);
|
||||
let mut delay_list = [best_dly; 4];
|
||||
|
||||
// Assign delay for other lanes
|
||||
@@ -105,7 +105,7 @@ unsafe fn assign_delay(timer: &mut GlobalTimer) -> SerdesConfig {
|
||||
let mut min_idx = 0;
|
||||
for dly_delta in -3..=3 {
|
||||
let index = (best_dly as isize + dly_delta) as u8;
|
||||
let low_rate = read_align(index, timer);
|
||||
let low_rate = read_align(index);
|
||||
// abs() from f32 is not available in core library
|
||||
let deviation = if low_rate < 0.5 { 0.5 - low_rate } else { low_rate - 0.5 };
|
||||
|
||||
@@ -115,7 +115,7 @@ unsafe fn assign_delay(timer: &mut GlobalTimer) -> SerdesConfig {
|
||||
}
|
||||
}
|
||||
|
||||
apply_delay(min_idx, timer);
|
||||
apply_delay(min_idx);
|
||||
delay_list[lane_no] = min_idx;
|
||||
}
|
||||
|
||||
@@ -124,13 +124,13 @@ unsafe fn assign_delay(timer: &mut GlobalTimer) -> SerdesConfig {
|
||||
SerdesConfig { delay: delay_list }
|
||||
}
|
||||
|
||||
fn read_align(dly: u8, timer: &mut GlobalTimer) -> f32 {
|
||||
fn read_align(dly: u8) -> f32 {
|
||||
unsafe {
|
||||
apply_delay(dly, timer);
|
||||
apply_delay(dly);
|
||||
pl::csr::eem_transceiver::counter_reset_write(1);
|
||||
|
||||
pl::csr::eem_transceiver::counter_enable_write(1);
|
||||
timer.delay_us(2000);
|
||||
timer::delay_us(2000);
|
||||
pl::csr::eem_transceiver::counter_enable_write(0);
|
||||
|
||||
let (high, low) = (
|
||||
@@ -145,7 +145,7 @@ fn read_align(dly: u8, timer: &mut GlobalTimer) -> f32 {
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn align_comma(timer: &mut GlobalTimer) {
|
||||
unsafe fn align_comma() {
|
||||
loop {
|
||||
for slip in 1..=10 {
|
||||
// The soft transceiver has 2 8b10b decoders, which receives lane
|
||||
@@ -169,10 +169,10 @@ unsafe fn align_comma(timer: &mut GlobalTimer) {
|
||||
// timing is met.
|
||||
pl::csr::eem_transceiver::bitslip_write(1);
|
||||
pl::csr::eem_transceiver::bitslip_write(1);
|
||||
timer.delay_us(1);
|
||||
timer::delay_us(1);
|
||||
|
||||
pl::csr::eem_transceiver::comma_align_reset_write(1);
|
||||
timer.delay_us(100);
|
||||
timer::delay_us(100);
|
||||
|
||||
if pl::csr::eem_transceiver::comma_read() == 1 {
|
||||
debug!("comma alignment completed after {} bitslips", slip);
|
||||
@@ -181,11 +181,29 @@ unsafe fn align_comma(timer: &mut GlobalTimer) {
|
||||
}
|
||||
|
||||
error!("comma alignment failed, retrying in 1s...");
|
||||
timer.delay_us(1_000_000);
|
||||
timer::delay_us(1_000_000);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn init(timer: &mut GlobalTimer, cfg: &Config) {
|
||||
pub unsafe fn align_wordslip(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() {
|
||||
for trx_no in 0..pl::csr::CONFIG_EEM_DRTIO_COUNT {
|
||||
unsafe {
|
||||
pl::csr::eem_transceiver::transceiver_sel_write(trx_no as u8);
|
||||
@@ -193,19 +211,19 @@ pub fn init(timer: &mut GlobalTimer, cfg: &Config) {
|
||||
|
||||
let key = format!("eem_drtio_delay{}", trx_no);
|
||||
|
||||
let cfg_read = cfg.read(&key);
|
||||
let cfg_read = libconfig::read(&key);
|
||||
match cfg_read {
|
||||
Ok(record) => {
|
||||
info!("loading calibrated timing values from sd card");
|
||||
unsafe {
|
||||
apply_config(&*(record.as_ptr() as *const SerdesConfig), timer);
|
||||
apply_config(&*(record.as_ptr() as *const SerdesConfig));
|
||||
}
|
||||
}
|
||||
Err(_) => {
|
||||
info!("calibrating...");
|
||||
let config = unsafe { assign_delay(timer) };
|
||||
let config = unsafe { assign_delay() };
|
||||
|
||||
match cfg.write(&key, config.as_bytes().to_vec()) {
|
||||
match libconfig::write(&key, config.as_bytes().to_vec()) {
|
||||
Ok(()) => {
|
||||
info!("storing calibration timing values into sd card");
|
||||
}
|
||||
@@ -221,8 +239,7 @@ pub fn init(timer: &mut GlobalTimer, cfg: &Config) {
|
||||
}
|
||||
|
||||
unsafe {
|
||||
align_comma(timer);
|
||||
pl::csr::eem_transceiver::rx_ready_write(1);
|
||||
align_comma();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use core::fmt;
|
||||
|
||||
use libconfig::Config;
|
||||
use libconfig;
|
||||
use log::{info, warn};
|
||||
|
||||
#[cfg(has_drtio_routing)]
|
||||
@@ -56,9 +56,9 @@ impl fmt::Display for RoutingTable {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn config_routing_table(default_n_links: usize, cfg: &Config) -> RoutingTable {
|
||||
pub fn config_routing_table(default_n_links: usize) -> RoutingTable {
|
||||
let mut ret = RoutingTable::default_master(default_n_links);
|
||||
if let Ok(data) = cfg.read("routing_table") {
|
||||
if let Ok(data) = libconfig::read("routing_table") {
|
||||
if data.len() == DEST_COUNT * MAX_HOPS {
|
||||
for i in 0..DEST_COUNT {
|
||||
for j in 0..MAX_HOPS {
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
use core::slice;
|
||||
use core::{arch::asm, slice};
|
||||
|
||||
use byteorder::NativeEndian;
|
||||
use core_io::{Error as IoError, ErrorKind as IoErrorKind};
|
||||
use crc;
|
||||
use io::{proto::{ProtoRead, ProtoWrite},
|
||||
Cursor};
|
||||
use libboard_zynq::{time::Milliseconds, timer::GlobalTimer};
|
||||
use io::{Cursor,
|
||||
proto::{ProtoRead, ProtoWrite}};
|
||||
use libboard_zynq::timer;
|
||||
|
||||
pub use crate::drtioaux_proto::Packet;
|
||||
pub use crate::drtioaux_proto::{MAX_PACKET, Packet};
|
||||
use crate::{drtioaux_proto::Error as ProtocolError, mem::mem::DRTIOAUX_MEM, pl::csr::DRTIOAUX};
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -35,6 +35,16 @@ impl From<IoError> for Error {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn copy_work_buffer(src: *mut u32, dst: *mut u32, len: isize) {
|
||||
// fix for artiq-zynq#344
|
||||
unsafe {
|
||||
for i in 0..(len / 4) {
|
||||
asm!("", options(preserves_flags, nostack, readonly));
|
||||
*dst.offset(i) = *src.offset(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reset(linkno: u8) {
|
||||
let linkno = linkno as usize;
|
||||
unsafe {
|
||||
@@ -90,17 +100,17 @@ pub fn recv(linkno: u8) -> Result<Option<Packet>, Error> {
|
||||
let checksum_at = reader.position() + padding;
|
||||
let checksum = crc::crc32::checksum_ieee(&reader.get_ref()[0..checksum_at]);
|
||||
reader.set_position(checksum_at);
|
||||
if reader.read_u32()? != checksum {
|
||||
if reader.read_u32::<NativeEndian>()? != checksum {
|
||||
return Err(Error::CorruptedPacket);
|
||||
}
|
||||
Ok(packet)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn recv_timeout(linkno: u8, timeout_ms: Option<u64>, timer: GlobalTimer) -> Result<Packet, Error> {
|
||||
let timeout_ms = Milliseconds(timeout_ms.unwrap_or(10));
|
||||
let limit = timer.get_time() + timeout_ms;
|
||||
while timer.get_time() < limit {
|
||||
pub fn recv_timeout(linkno: u8, timeout_ms: Option<u64>) -> Result<Packet, Error> {
|
||||
let timeout_ms = timeout_ms.unwrap_or(10);
|
||||
let limit = timer::get_ms() + timeout_ms;
|
||||
while timer::get_ms() < limit {
|
||||
match recv(linkno)? {
|
||||
None => (),
|
||||
Some(packet) => return Ok(packet),
|
||||
@@ -115,7 +125,9 @@ where F: FnOnce(&mut [u8]) -> Result<usize, Error> {
|
||||
unsafe {
|
||||
while (DRTIOAUX[linkno].aux_tx_read)() != 0 {}
|
||||
let ptr = DRTIOAUX_MEM[linkno].base as *mut u32;
|
||||
let len = f(slice::from_raw_parts_mut(ptr as *mut u8, 0x400 as usize))?;
|
||||
let mut buf: [u8; MAX_PACKET] = [0; MAX_PACKET];
|
||||
let len = f(&mut buf)?;
|
||||
copy_work_buffer(buf.as_mut_ptr() as *mut u32, ptr, len as isize);
|
||||
(DRTIOAUX[linkno].aux_tx_length_write)(len as u16);
|
||||
(DRTIOAUX[linkno].aux_tx_write)(1);
|
||||
Ok(())
|
||||
@@ -135,7 +147,7 @@ pub fn send(linkno: u8, packet: &Packet) -> Result<(), Error> {
|
||||
}
|
||||
|
||||
let checksum = crc::crc32::checksum_ieee(&writer.get_ref()[0..writer.position()]);
|
||||
writer.write_u32(checksum)?;
|
||||
writer.write_u32::<NativeEndian>(checksum)?;
|
||||
|
||||
Ok(writer.position())
|
||||
})
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
use core::slice;
|
||||
|
||||
use byteorder::NativeEndian;
|
||||
use core_io::{Error as IoError, ErrorKind as IoErrorKind};
|
||||
use crc;
|
||||
use io::{proto::{ProtoRead, ProtoWrite},
|
||||
Cursor};
|
||||
use io::{Cursor,
|
||||
proto::{ProtoRead, ProtoWrite}};
|
||||
use libasync::{block_async, task};
|
||||
use libboard_zynq::{time::Milliseconds, timer::GlobalTimer};
|
||||
use nb;
|
||||
use libboard_zynq::timer;
|
||||
use void::Void;
|
||||
|
||||
pub use crate::drtioaux_proto::Packet;
|
||||
use crate::{drtioaux::{has_rx_error, Error},
|
||||
pub use crate::drtioaux_proto::{MAX_PACKET, Packet};
|
||||
use crate::{drtioaux::{Error, copy_work_buffer, has_rx_error},
|
||||
mem::mem::DRTIOAUX_MEM,
|
||||
pl::csr::DRTIOAUX};
|
||||
|
||||
@@ -68,7 +67,7 @@ pub async fn recv(linkno: u8) -> Result<Option<Packet>, Error> {
|
||||
let checksum_at = reader.position() + padding;
|
||||
let checksum = crc::crc32::checksum_ieee(&reader.get_ref()[0..checksum_at]);
|
||||
reader.set_position(checksum_at);
|
||||
if reader.read_u32()? != checksum {
|
||||
if reader.read_u32::<NativeEndian>()? != checksum {
|
||||
return Err(Error::CorruptedPacket);
|
||||
}
|
||||
Ok(packet)
|
||||
@@ -76,11 +75,11 @@ pub async fn recv(linkno: u8) -> Result<Option<Packet>, Error> {
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn recv_timeout(linkno: u8, timeout_ms: Option<u64>, timer: GlobalTimer) -> Result<Packet, Error> {
|
||||
let timeout_ms = Milliseconds(timeout_ms.unwrap_or(10));
|
||||
let limit = timer.get_time() + timeout_ms;
|
||||
pub async fn recv_timeout(linkno: u8, timeout_ms: Option<u64>) -> Result<Packet, Error> {
|
||||
let timeout_ms = timeout_ms.unwrap_or(10);
|
||||
let limit = timer::get_ms() + timeout_ms;
|
||||
let mut would_block = false;
|
||||
while timer.get_time() < limit {
|
||||
while timer::get_ms() < limit {
|
||||
// to ensure one last time recv would run one last time
|
||||
// in case async would return after timeout
|
||||
if would_block {
|
||||
@@ -102,7 +101,9 @@ where F: FnOnce(&mut [u8]) -> Result<usize, Error> {
|
||||
unsafe {
|
||||
let _ = block_async!(tx_ready(linkno)).await;
|
||||
let ptr = DRTIOAUX_MEM[linkno].base as *mut u32;
|
||||
let len = f(slice::from_raw_parts_mut(ptr as *mut u8, 0x400 as usize))?;
|
||||
let mut buf: [u8; MAX_PACKET] = [0; MAX_PACKET];
|
||||
let len = f(&mut buf)?;
|
||||
copy_work_buffer(buf.as_mut_ptr() as *mut u32, ptr, len as isize);
|
||||
(DRTIOAUX[linkno].aux_tx_length_write)(len as u16);
|
||||
(DRTIOAUX[linkno].aux_tx_write)(1);
|
||||
Ok(())
|
||||
@@ -122,7 +123,7 @@ pub async fn send(linkno: u8, packet: &Packet) -> Result<(), Error> {
|
||||
}
|
||||
|
||||
let checksum = crc::crc32::checksum_ieee(&writer.get_ref()[0..writer.position()]);
|
||||
writer.write_u32(checksum)?;
|
||||
writer.write_u32::<NativeEndian>(checksum)?;
|
||||
|
||||
Ok(writer.position())
|
||||
})
|
||||
|
||||
@@ -1,11 +1,18 @@
|
||||
use core_io::{Error as IoError, Read, Write};
|
||||
use byteorder::NativeEndian;
|
||||
use core_io::Error as IoError;
|
||||
use io::proto::{ProtoRead, ProtoWrite};
|
||||
|
||||
const MAX_PACKET: usize = 1024;
|
||||
pub const MAX_PACKET: usize = 1024;
|
||||
|
||||
// maximum size of arbitrary payloads
|
||||
// used by satellite -> master CoaXPress communication and errors
|
||||
pub const CXP_PAYLOAD_MAX_SIZE: usize = /*max size*/
|
||||
MAX_PACKET - /*packet ID*/1 - /*length*/2 - /*CRC*/4 - /*padding to keep CXP register access 4 bytes align*/1;
|
||||
// used by satellite -> master CoaXPress roi viewer pixel data transfer
|
||||
pub const CXP_PAYLOAD_MAX_SIZE_U64: usize = CXP_PAYLOAD_MAX_SIZE / 8;
|
||||
// used by satellite -> master analyzer, subkernel exceptions
|
||||
pub const SAT_PAYLOAD_MAX_SIZE: usize = /*max size*/MAX_PACKET - /*CRC*/4 - /*packet ID*/1 - /*last*/1 - /*length*/2;
|
||||
pub const SAT_PAYLOAD_MAX_SIZE: usize = /*max size*/
|
||||
MAX_PACKET - /*CRC*/4 - /*packet ID*/1 - /*last*/1 - /*length*/2;
|
||||
// used by DDMA, subkernel program data (need to provide extra ID and destination)
|
||||
pub const MASTER_PAYLOAD_MAX_SIZE: usize = SAT_PAYLOAD_MAX_SIZE - /*source*/1 - /*destination*/1 - /*ID*/4;
|
||||
|
||||
@@ -255,6 +262,7 @@ pub enum Packet {
|
||||
destination: u8,
|
||||
id: u32,
|
||||
run: bool,
|
||||
timestamp: u64,
|
||||
},
|
||||
SubkernelLoadRunReply {
|
||||
destination: u8,
|
||||
@@ -267,12 +275,14 @@ pub enum Packet {
|
||||
exception_src: u8,
|
||||
},
|
||||
SubkernelExceptionRequest {
|
||||
source: u8,
|
||||
destination: u8,
|
||||
},
|
||||
SubkernelException {
|
||||
destination: u8,
|
||||
last: bool,
|
||||
length: u16,
|
||||
data: [u8; SAT_PAYLOAD_MAX_SIZE],
|
||||
data: [u8; MASTER_PAYLOAD_MAX_SIZE],
|
||||
},
|
||||
SubkernelMessage {
|
||||
source: u8,
|
||||
@@ -285,11 +295,113 @@ pub enum Packet {
|
||||
SubkernelMessageAck {
|
||||
destination: u8,
|
||||
},
|
||||
|
||||
CoreMgmtGetLogRequest {
|
||||
destination: | ||||