forked from M-Labs/artiq-zynq
Compare commits
66 Commits
78080eae2b
...
3c70203709
| Author | SHA1 | Date | |
|---|---|---|---|
| 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 |
@@ -2,7 +2,7 @@
|
||||
"target": "kasli_soc",
|
||||
"variant": "demo",
|
||||
"hw_rev": "v1.0",
|
||||
"base": "standalone",
|
||||
"drtio_role": "standalone",
|
||||
"peripherals": [
|
||||
{
|
||||
"type": "coaxpress_sfp"
|
||||
|
||||
@@ -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
|
||||
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"
|
||||
}
|
||||
|
||||
149
flake.lock
generated
149
flake.lock
generated
@@ -12,11 +12,11 @@
|
||||
"src-pythonparser": "src-pythonparser"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1753945412,
|
||||
"narHash": "sha256-TWMNAkzFWSg0MyR0MylG5Va9K+KnQ6wPiCc5UXxjJx8=",
|
||||
"lastModified": 1768732816,
|
||||
"narHash": "sha256-0KkkAC2SJkWU8E/KNeyzFSj0RpW2sHZ7l7p1GwXGNxI=",
|
||||
"ref": "refs/heads/master",
|
||||
"rev": "b2ef8fb3987fb4eb142f42bcad4f06c48433f9dc",
|
||||
"revCount": 9304,
|
||||
"rev": "7d7b85f377e0c172ae3496f0c03cfb6cb85ba022",
|
||||
"revCount": 9600,
|
||||
"type": "git",
|
||||
"url": "https://github.com/m-labs/artiq.git"
|
||||
},
|
||||
@@ -38,17 +38,17 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1753274984,
|
||||
"narHash": "sha256-VZhmNafIj++z2cYLwCxWvnhOctqnIOAvA1/r+WEy+LI=",
|
||||
"owner": "m-labs",
|
||||
"repo": "artiq-comtools",
|
||||
"rev": "25f1f2aae1b7e38f1315e40e448211430c3924df",
|
||||
"type": "github"
|
||||
"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": {
|
||||
"owner": "m-labs",
|
||||
"repo": "artiq-comtools",
|
||||
"type": "github"
|
||||
"type": "git",
|
||||
"url": "https://git.m-labs.hk/M-Labs/artiq-comtools.git"
|
||||
}
|
||||
},
|
||||
"fenix": {
|
||||
@@ -74,6 +74,29 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"fenix_2": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"zynq-rs",
|
||||
"naersk",
|
||||
"nixpkgs"
|
||||
],
|
||||
"rust-analyzer-src": "rust-analyzer-src_2"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1752475459,
|
||||
"narHash": "sha256-z6QEu4ZFuHiqdOPbYss4/Q8B0BFhacR8ts6jO/F/aOU=",
|
||||
"owner": "nix-community",
|
||||
"repo": "fenix",
|
||||
"rev": "bf0d6f70f4c9a9cf8845f992105652173f4b617f",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"repo": "fenix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils": {
|
||||
"inputs": {
|
||||
"systems": "systems"
|
||||
@@ -101,11 +124,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1752689277,
|
||||
"narHash": "sha256-uldUBFkZe/E7qbvxa3mH1ItrWZyT6w1dBKJQF/3ZSsc=",
|
||||
"lastModified": 1763384566,
|
||||
"narHash": "sha256-r+wgI+WvNaSdxQmqaM58lVNvJYJ16zoq+tKN20cLst4=",
|
||||
"owner": "nix-community",
|
||||
"repo": "naersk",
|
||||
"rev": "0e72363d0938b0208d6c646d10649164c43f4d64",
|
||||
"rev": "d4155d6ebb70fbe2314959842f744aa7cabbbf6a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -116,17 +139,18 @@
|
||||
},
|
||||
"naersk_2": {
|
||||
"inputs": {
|
||||
"fenix": "fenix_2",
|
||||
"nixpkgs": [
|
||||
"zynq-rs",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1745925850,
|
||||
"narHash": "sha256-cyAAMal0aPrlb1NgzMxZqeN1mAJ2pJseDhm2m6Um8T0=",
|
||||
"lastModified": 1768908532,
|
||||
"narHash": "sha256-HIdLXEFaUVE8FiaCPJbCfBMsnF+mVtDub8Jwj2BD+mk=",
|
||||
"owner": "nix-community",
|
||||
"repo": "naersk",
|
||||
"rev": "38bc60bbc157ae266d4a0c96671c6c742ee17a5f",
|
||||
"rev": "8d97452673640eb7fabe428e8b6a425bc355008b",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -137,16 +161,16 @@
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1752950548,
|
||||
"narHash": "sha256-NS6BLD0lxOrnCiEOcvQCDVPXafX1/ek1dfJHX1nUIzc=",
|
||||
"lastModified": 1767047869,
|
||||
"narHash": "sha256-tzYsEzXEVa7op1LTnrLSiPGrcCY6948iD0EcNLWcmzo=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "c87b95e25065c028d31a94f06a62927d18763fdf",
|
||||
"rev": "89dbf01df72eb5ebe3b24a86334b12c27d68016a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-unstable",
|
||||
"ref": "nixos-25.11",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
@@ -174,6 +198,23 @@
|
||||
"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": [
|
||||
@@ -204,11 +245,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1750041667,
|
||||
"narHash": "sha256-/8F9L6T9w/Fx1D6L+BtWIXg5m9F6jwOFg6uhZpKnM/0=",
|
||||
"lastModified": 1769136478,
|
||||
"narHash": "sha256-8UNd5lmGf8phCr/aKxagJ4kNsF0pCHLish2G4ZKCFFY=",
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"rev": "d72bd8c9fda03c9834ea89d7a5a21c7880b79277",
|
||||
"rev": "470ee44393bb19887056b557ea2c03fc5230bd5a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -225,51 +266,51 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1753275053,
|
||||
"narHash": "sha256-ukZqfmWV0zyMTZL3UK4gBZlIsEW/HdE0Kc6DO+Opoes=",
|
||||
"owner": "m-labs",
|
||||
"repo": "sipyco",
|
||||
"rev": "7a0d0d7a95695cf18f1b60b8320b10a26df53f36",
|
||||
"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": 1749544952,
|
||||
"narHash": "sha256-NshlPiORBHWljSUP5bB7YBxe7k8dW0t8UXOsIq2EK8I=",
|
||||
"owner": "m-labs",
|
||||
"repo": "migen",
|
||||
"rev": "6e3a9e150fb006dabc4b55043d3af18dbfecd7e8",
|
||||
"type": "github"
|
||||
"lastModified": 1767354910,
|
||||
"narHash": "sha256-gRAvl5cUvrjq4t7htXsDBt4F8MEbHXFZoS0jbhrEs1I=",
|
||||
"ref": "refs/heads/master",
|
||||
"rev": "0efcff4cb875746dce46987d2fa476897c8c671e",
|
||||
"revCount": 2064,
|
||||
"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": 1747128843,
|
||||
"narHash": "sha256-TCFPoaQFaFCg3my3wyl3Gkz4ZnyzWa/ZXbcZG/OEsCU=",
|
||||
"lastModified": 1765867404,
|
||||
"narHash": "sha256-YPYUHVIryXDp4W2hUtHUtBbRKIrbhInWImT0NKaacSY=",
|
||||
"ref": "refs/heads/master",
|
||||
"rev": "9e07cf5f3b7d4949d3b775d4d946ca22900ab528",
|
||||
"revCount": 2498,
|
||||
"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": {
|
||||
@@ -313,11 +354,11 @@
|
||||
"rust-overlay": "rust-overlay_2"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1753867338,
|
||||
"narHash": "sha256-Xw50x/Tx+Y/dbqpAb4M8Fu7DCeYW6psmWnT2UPl2e4E=",
|
||||
"lastModified": 1769164212,
|
||||
"narHash": "sha256-NPZ7bV+bJbqZT2EV4YJUZrzKcAt7gV3HzTm2COrz8ps=",
|
||||
"ref": "refs/heads/master",
|
||||
"rev": "b69de9f37fe6b16c0bf8d3d6bfcec7fe05a3ee03",
|
||||
"revCount": 726,
|
||||
"rev": "6cfb6fd1fc44b9be73872ab362afe7f1b0926c2c",
|
||||
"revCount": 739,
|
||||
"type": "git",
|
||||
"url": "https://git.m-labs.hk/m-labs/zynq-rs"
|
||||
},
|
||||
|
||||
352
flake.nix
352
flake.nix
@@ -5,9 +5,15 @@
|
||||
inputs.zynq-rs.url = git+https://git.m-labs.hk/m-labs/zynq-rs;
|
||||
inputs.zynq-rs.inputs.nixpkgs.follows = "artiq/nixpkgs";
|
||||
|
||||
outputs = { self, zynq-rs, artiq }:
|
||||
let
|
||||
pkgs = import artiq.inputs.nixpkgs { system = "x86_64-linux"; overlays = [ (import zynq-rs.inputs.rust-overlay) ]; };
|
||||
outputs = {
|
||||
self,
|
||||
zynq-rs,
|
||||
artiq,
|
||||
}: let
|
||||
pkgs = import artiq.inputs.nixpkgs {
|
||||
system = "x86_64-linux";
|
||||
overlays = [(import zynq-rs.inputs.rust-overlay)];
|
||||
};
|
||||
zynqpkgs = zynq-rs.packages.x86_64-linux;
|
||||
artiqpkgs = artiq.packages.x86_64-linux;
|
||||
zynqRev = self.sourceInfo.rev or "unknown";
|
||||
@@ -53,10 +59,10 @@
|
||||
pyproject = true;
|
||||
build-system = [pkgs.python3Packages.setuptools];
|
||||
|
||||
nativeBuildInputs = with pkgs.python3Packages; [ pbr ];
|
||||
propagatedBuildInputs = with pkgs.python3Packages; [ fastnumbers ];
|
||||
nativeBuildInputs = with pkgs.python3Packages; [pbr];
|
||||
propagatedBuildInputs = with pkgs.python3Packages; [fastnumbers];
|
||||
|
||||
checkInputs = with pkgs.python3Packages; [ pytest ];
|
||||
checkInputs = with pkgs.python3Packages; [pytest];
|
||||
checkPhase = "pytest";
|
||||
doCheck = false;
|
||||
|
||||
@@ -78,9 +84,9 @@
|
||||
pyproject = true;
|
||||
build-system = [pkgs.python3Packages.setuptools];
|
||||
|
||||
propagatedBuildInputs = with pkgs.python3Packages; [ setuptools click numpy toolz jinja2 ramda artiqpkgs.migen artiqpkgs.misoc ];
|
||||
propagatedBuildInputs = with pkgs.python3Packages; [setuptools click numpy toolz jinja2 ramda artiqpkgs.migen artiqpkgs.misoc];
|
||||
|
||||
checkInputs = with pkgs.python3Packages; [ pytestCheckHook pytest-timeout ];
|
||||
checkInputs = with pkgs.python3Packages; [pytestCheckHook pytest-timeout];
|
||||
|
||||
# migen/misoc version checks are broken with pyproject for some reason
|
||||
postPatch = ''
|
||||
@@ -93,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"];
|
||||
@@ -116,13 +129,26 @@
|
||||
# kasli-soc satellite variants
|
||||
"satellite"
|
||||
# zc706 satellite variants
|
||||
"nist_clock_satellite" "nist_qc2_satellite" "acpki_nist_clock_satellite" "acpki_nist_qc2_satellite"
|
||||
"nist_clock_satellite_100mhz" "nist_qc2_satellite_100mhz" "acpki_nist_clock_satellite_100mhz" "acpki_nist_qc2_satellite_100mhz"
|
||||
"nist_clock_satellite"
|
||||
"nist_qc2_satellite"
|
||||
"acpki_nist_clock_satellite"
|
||||
"acpki_nist_qc2_satellite"
|
||||
"nist_clock_satellite_100mhz"
|
||||
"nist_qc2_satellite_100mhz"
|
||||
"acpki_nist_clock_satellite_100mhz"
|
||||
"acpki_nist_qc2_satellite_100mhz"
|
||||
];
|
||||
board-package-set = { target, variant, json ? null }: let
|
||||
board-package-set = {
|
||||
target,
|
||||
variant,
|
||||
json ? null,
|
||||
}: let
|
||||
szl = zynqpkgs."${target}-szl";
|
||||
fsbl = zynqpkgs."${target}-fsbl";
|
||||
fwtype = if builtins.elem variant sat_variants then "satman" else "runtime";
|
||||
fwtype =
|
||||
if builtins.elem variant sat_variants
|
||||
then "satman"
|
||||
else "runtime";
|
||||
|
||||
firmware = naerskLib.buildPackage rec {
|
||||
name = "firmware";
|
||||
@@ -132,7 +158,7 @@
|
||||
|
||||
nativeBuildInputs = [
|
||||
pkgs.gnumake
|
||||
(pkgs.python3.withPackages(ps: [ ps.jsonschema artiqpkgs.migen migen-axi artiqpkgs.misoc artiqpkgs.artiq ]))
|
||||
(pkgs.python3.withPackages (ps: [artiqpkgs.migen migen-axi artiqpkgs.misoc artiqpkgs.artiq-build]))
|
||||
pkgs.llvmPackages_20.llvm
|
||||
pkgs.llvmPackages_20.clang-unwrapped
|
||||
];
|
||||
@@ -142,7 +168,11 @@
|
||||
export ZYNQ_REV=${zynqRev}
|
||||
export CLANG_EXTRA_INCLUDE_DIR="${pkgs.llvmPackages_20.clang-unwrapped.lib}/lib/clang/20/include"
|
||||
export ZYNQ_RS=${zynq-rs}
|
||||
make TARGET=${target} GWARGS="${if json == null then "-V ${variant}" else json}" ${fwtype}
|
||||
make TARGET=${target} GWARGS="${
|
||||
if json == null
|
||||
then "-V ${variant}"
|
||||
else json
|
||||
}" ${fwtype}
|
||||
'';
|
||||
|
||||
installPhase = ''
|
||||
@@ -157,32 +187,39 @@
|
||||
dontFixup = true;
|
||||
};
|
||||
};
|
||||
gateware = pkgs.runCommand "${target}-${variant}-gateware"
|
||||
gateware =
|
||||
pkgs.runCommand "${target}-${variant}-gateware"
|
||||
{
|
||||
nativeBuildInputs = [
|
||||
(pkgs.python3.withPackages(ps: [ ps.jsonschema artiqpkgs.migen migen-axi artiqpkgs.misoc artiqpkgs.artiq ]))
|
||||
nativeBuildInputs = [
|
||||
(pkgs.python3.withPackages (ps: [artiqpkgs.migen migen-axi artiqpkgs.misoc artiqpkgs.artiq-build]))
|
||||
artiqpkgs.vivado
|
||||
];
|
||||
}
|
||||
''
|
||||
export ZYNQ_REV=${zynqRev}
|
||||
python ${./src/gateware}/${target}.py -g build ${if json == null then "-V ${variant}" else json}
|
||||
python ${./src/gateware}/${target}.py -g build ${
|
||||
if json == null
|
||||
then "-V ${variant}"
|
||||
else json
|
||||
}
|
||||
mkdir -p $out $out/nix-support
|
||||
cp build/top.bit $out
|
||||
echo file binary-dist $out/top.bit >> $out/nix-support/hydra-build-products
|
||||
'';
|
||||
|
||||
# SZL startup
|
||||
jtag = pkgs.runCommand "${target}-${variant}-jtag" {}
|
||||
jtag =
|
||||
pkgs.runCommand "${target}-${variant}-jtag" {}
|
||||
''
|
||||
mkdir $out
|
||||
ln -s ${szl}/szl.elf $out
|
||||
ln -s ${firmware}/${fwtype}.bin $out
|
||||
ln -s ${gateware}/top.bit $out
|
||||
'';
|
||||
sd = pkgs.runCommand "${target}-${variant}-sd"
|
||||
sd =
|
||||
pkgs.runCommand "${target}-${variant}-sd"
|
||||
{
|
||||
buildInputs = [ zynqpkgs.mkbootimage ];
|
||||
buildInputs = [zynqpkgs.mkbootimage];
|
||||
}
|
||||
''
|
||||
# Do not use "long" paths in boot.bif, because embedded developers
|
||||
@@ -206,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`
|
||||
@@ -228,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 {
|
||||
@@ -262,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
|
||||
@@ -316,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
|
||||
@@ -336,40 +387,137 @@
|
||||
(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 = "cxp_4r_fmc"; }) //
|
||||
(board-package-set { target = "zc706"; variant = "nist_clock"; }) //
|
||||
(board-package-set { target = "zc706"; variant = "nist_clock_master"; }) //
|
||||
(board-package-set { target = "zc706"; variant = "nist_clock_master_100mhz"; }) //
|
||||
(board-package-set { target = "zc706"; variant = "nist_clock_satellite"; }) //
|
||||
(board-package-set { target = "zc706"; variant = "nist_clock_satellite_100mhz"; }) //
|
||||
(board-package-set { target = "zc706"; variant = "nist_qc2"; }) //
|
||||
(board-package-set { target = "zc706"; variant = "nist_qc2_master"; }) //
|
||||
(board-package-set { target = "zc706"; variant = "nist_qc2_master_100mhz"; }) //
|
||||
(board-package-set { target = "zc706"; variant = "nist_qc2_satellite"; }) //
|
||||
(board-package-set { target = "zc706"; variant = "nist_qc2_satellite_100mhz"; }) //
|
||||
(board-package-set { target = "zc706"; variant = "acpki_nist_clock"; }) //
|
||||
(board-package-set { target = "zc706"; variant = "acpki_nist_clock_master"; }) //
|
||||
(board-package-set { target = "zc706"; variant = "acpki_nist_clock_master_100mhz"; }) //
|
||||
(board-package-set { target = "zc706"; variant = "acpki_nist_clock_satellite"; }) //
|
||||
(board-package-set { target = "zc706"; variant = "acpki_nist_clock_satellite_100mhz"; }) //
|
||||
(board-package-set { target = "zc706"; variant = "acpki_nist_qc2"; }) //
|
||||
(board-package-set { target = "zc706"; variant = "acpki_nist_qc2_master"; }) //
|
||||
(board-package-set { target = "zc706"; variant = "acpki_nist_qc2_master_100mhz"; }) //
|
||||
(board-package-set { target = "zc706"; variant = "acpki_nist_qc2_satellite"; }) //
|
||||
(board-package-set { target = "zc706"; variant = "acpki_nist_qc2_satellite_100mhz"; }) //
|
||||
(board-package-set { target = "kasli_soc"; variant = "demo"; json = ./demo.json; }) //
|
||||
(board-package-set { target = "kasli_soc"; variant = "master"; json = ./kasli-soc-master.json; }) //
|
||||
(board-package-set { target = "kasli_soc"; variant = "satellite"; json = ./kasli-soc-satellite.json; }) //
|
||||
(board-package-set { target = "ebaz4205"; variant = "base"; });
|
||||
}
|
||||
// (board-package-set {
|
||||
target = "zc706";
|
||||
variant = "cxp_4r_fmc";
|
||||
})
|
||||
// (board-package-set {
|
||||
target = "zc706";
|
||||
variant = "nist_clock";
|
||||
})
|
||||
// (board-package-set {
|
||||
target = "zc706";
|
||||
variant = "nist_clock_master";
|
||||
})
|
||||
// (board-package-set {
|
||||
target = "zc706";
|
||||
variant = "nist_clock_master_100mhz";
|
||||
})
|
||||
// (board-package-set {
|
||||
target = "zc706";
|
||||
variant = "nist_clock_satellite";
|
||||
})
|
||||
// (board-package-set {
|
||||
target = "zc706";
|
||||
variant = "nist_clock_satellite_100mhz";
|
||||
})
|
||||
// (board-package-set {
|
||||
target = "zc706";
|
||||
variant = "nist_qc2";
|
||||
})
|
||||
// (board-package-set {
|
||||
target = "zc706";
|
||||
variant = "nist_qc2_master";
|
||||
})
|
||||
// (board-package-set {
|
||||
target = "zc706";
|
||||
variant = "nist_qc2_master_100mhz";
|
||||
})
|
||||
// (board-package-set {
|
||||
target = "zc706";
|
||||
variant = "nist_qc2_satellite";
|
||||
})
|
||||
// (board-package-set {
|
||||
target = "zc706";
|
||||
variant = "nist_qc2_satellite_100mhz";
|
||||
})
|
||||
// (board-package-set {
|
||||
target = "zc706";
|
||||
variant = "acpki_nist_clock";
|
||||
})
|
||||
// (board-package-set {
|
||||
target = "zc706";
|
||||
variant = "acpki_nist_clock_master";
|
||||
})
|
||||
// (board-package-set {
|
||||
target = "zc706";
|
||||
variant = "acpki_nist_clock_master_100mhz";
|
||||
})
|
||||
// (board-package-set {
|
||||
target = "zc706";
|
||||
variant = "acpki_nist_clock_satellite";
|
||||
})
|
||||
// (board-package-set {
|
||||
target = "zc706";
|
||||
variant = "acpki_nist_clock_satellite_100mhz";
|
||||
})
|
||||
// (board-package-set {
|
||||
target = "zc706";
|
||||
variant = "acpki_nist_qc2";
|
||||
})
|
||||
// (board-package-set {
|
||||
target = "zc706";
|
||||
variant = "acpki_nist_qc2_master";
|
||||
})
|
||||
// (board-package-set {
|
||||
target = "zc706";
|
||||
variant = "acpki_nist_qc2_master_100mhz";
|
||||
})
|
||||
// (board-package-set {
|
||||
target = "zc706";
|
||||
variant = "acpki_nist_qc2_satellite";
|
||||
})
|
||||
// (board-package-set {
|
||||
target = "zc706";
|
||||
variant = "acpki_nist_qc2_satellite_100mhz";
|
||||
})
|
||||
// (board-package-set {
|
||||
target = "kasli_soc";
|
||||
variant = "demo";
|
||||
json = ./demo.json;
|
||||
})
|
||||
// (board-package-set {
|
||||
target = "kasli_soc";
|
||||
variant = "master";
|
||||
json = ./kasli-soc-master.json;
|
||||
})
|
||||
// (board-package-set {
|
||||
target = "kasli_soc";
|
||||
variant = "satellite";
|
||||
json = ./kasli-soc-satellite.json;
|
||||
})
|
||||
// (board-package-set {
|
||||
target = "ebaz4205";
|
||||
variant = "base";
|
||||
});
|
||||
|
||||
hydraJobs = packages.x86_64-linux // { inherit zc706-hitl-tests; inherit gateware-sim; inherit fmt-check; };
|
||||
hydraJobs =
|
||||
packages.x86_64-linux
|
||||
// {
|
||||
inherit zc706-hitl-tests;
|
||||
inherit zc706-acpki-hitl-tests;
|
||||
inherit gateware-sim;
|
||||
inherit fmt-check;
|
||||
};
|
||||
|
||||
formatter.x86_64-linux = pkgs.alejandra;
|
||||
|
||||
devShell.x86_64-linux = pkgs.mkShell {
|
||||
name = "artiq-zynq-dev-shell";
|
||||
@@ -380,15 +528,16 @@
|
||||
gnumake
|
||||
cacert
|
||||
zynqpkgs.mkbootimage
|
||||
openocd
|
||||
openssh rsync
|
||||
(python3.withPackages(ps: (with artiqpkgs; [ migen migen-axi misoc artiq artiq-netboot ps.jsonschema ps.pyftdi ])))
|
||||
openocd
|
||||
openssh
|
||||
rsync
|
||||
(python3.withPackages (ps: (with artiqpkgs; [migen migen-axi misoc artiq artiq-netboot ps.jsonschema ps.pyftdi])))
|
||||
artiqpkgs.artiq
|
||||
artiqpkgs.vivado
|
||||
binutils-arm
|
||||
pre-commit
|
||||
];
|
||||
ZYNQ_REV="${zynqRev}";
|
||||
ZYNQ_REV = "${zynqRev}";
|
||||
CLANG_EXTRA_INCLUDE_DIR = "${pkgs.llvmPackages_20.clang-unwrapped.lib}/lib/clang/20/include";
|
||||
ZYNQ_RS = "${zynq-rs}";
|
||||
OPENOCD_ZYNQ = "${zynq-rs}/openocd";
|
||||
@@ -396,6 +545,5 @@
|
||||
};
|
||||
|
||||
makeArtiqZynqPackage = board-package-set;
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"target": "kasli_soc",
|
||||
"variant": "master",
|
||||
"hw_rev": "v1.0",
|
||||
"base": "master",
|
||||
"drtio_role": "master",
|
||||
"peripherals": [
|
||||
{
|
||||
"type": "coaxpress_sfp"
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"target": "kasli_soc",
|
||||
"variant": "satellite",
|
||||
"hw_rev": "v1.0",
|
||||
"base": "satellite",
|
||||
"drtio_role": "satellite",
|
||||
"peripherals": [
|
||||
{
|
||||
"type": "coaxpress_sfp"
|
||||
|
||||
@@ -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,6 +1,7 @@
|
||||
[target.armv7-none-eabihf]
|
||||
rustflags = [
|
||||
"-C", "link-arg=-Tlink.x",
|
||||
"-C", "link-arg=--no-check-sections", # required for overlapping sections
|
||||
"-C", "target-cpu=cortex-a9",
|
||||
]
|
||||
|
||||
|
||||
2
src/Cargo.lock
generated
2
src/Cargo.lock
generated
@@ -244,7 +244,6 @@ dependencies = [
|
||||
"log",
|
||||
"log_buffer",
|
||||
"nalgebra",
|
||||
"nb 0.1.3",
|
||||
"unwind",
|
||||
"vcell",
|
||||
"void",
|
||||
@@ -525,6 +524,7 @@ dependencies = [
|
||||
"libsupport_zynq",
|
||||
"log",
|
||||
"log_buffer",
|
||||
"nb 0.1.3",
|
||||
"num-derive",
|
||||
"num-traits",
|
||||
"tar-no-std",
|
||||
|
||||
@@ -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 += [
|
||||
|
||||
@@ -103,7 +103,7 @@ def _create_ttl():
|
||||
|
||||
|
||||
class EBAZ4205(SoCCore):
|
||||
def __init__(self, rtio_clk=125e6, acpki=False):
|
||||
def __init__(self, rtio_clk=125e6, acpki=False, acpki_batch_size=1e5):
|
||||
self.acpki = acpki
|
||||
|
||||
platform = ebaz4205.Platform()
|
||||
@@ -213,6 +213,7 @@ class EBAZ4205(SoCCore):
|
||||
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,
|
||||
@@ -245,8 +246,8 @@ class EBAZ4205(SoCCore):
|
||||
|
||||
|
||||
class BASE(EBAZ4205):
|
||||
def __init__(self, rtio_clk, acpki):
|
||||
EBAZ4205.__init__(self, rtio_clk, acpki)
|
||||
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]}
|
||||
@@ -271,6 +272,7 @@ def main():
|
||||
"-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",
|
||||
@@ -290,7 +292,7 @@ def main():
|
||||
except KeyError:
|
||||
raise SystemExit("Invalid variant (-V/--variant)")
|
||||
|
||||
soc = cls(rtio_clk=rtio_clk, acpki=acpki)
|
||||
soc = cls(rtio_clk=rtio_clk, acpki=acpki, acpki_batch_size=args.acpki_batch_size)
|
||||
soc.finalize()
|
||||
|
||||
if args.r is not None:
|
||||
|
||||
@@ -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
|
||||
@@ -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])
|
||||
@@ -149,8 +148,8 @@ def add_coaxpress_sfp(cls, clk_freq, roi_engine_count, refclk=None):
|
||||
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"]
|
||||
|
||||
@@ -235,6 +234,7 @@ class GenericStandalone(SoCCore):
|
||||
|
||||
if self.acpki:
|
||||
self.config["KI_IMPL"] = "acp"
|
||||
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,
|
||||
@@ -269,12 +269,12 @@ 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([
|
||||
@@ -414,6 +414,7 @@ class GenericMaster(SoCCore):
|
||||
|
||||
if self.acpki:
|
||||
self.config["KI_IMPL"] = "acp"
|
||||
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,
|
||||
@@ -493,12 +494,12 @@ 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"]
|
||||
|
||||
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([
|
||||
@@ -627,6 +628,7 @@ class GenericSatellite(SoCCore):
|
||||
|
||||
if self.acpki:
|
||||
self.config["KI_IMPL"] = "acp"
|
||||
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,
|
||||
@@ -763,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()
|
||||
@@ -782,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:
|
||||
|
||||
@@ -125,7 +125,7 @@ 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()
|
||||
@@ -156,6 +156,7 @@ class ZC706(SoCCore):
|
||||
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)
|
||||
@@ -197,7 +198,7 @@ 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
|
||||
@@ -288,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(
|
||||
@@ -338,7 +341,7 @@ 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
|
||||
@@ -441,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(
|
||||
@@ -704,40 +708,40 @@ class _CXP_4R_FMC_RTIO():
|
||||
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):
|
||||
ZC706.__init__(self, acpki)
|
||||
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,
|
||||
@@ -758,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()
|
||||
@@ -772,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:
|
||||
|
||||
@@ -72,6 +72,7 @@ pub mod rx {
|
||||
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);
|
||||
@@ -153,6 +154,15 @@ pub mod rx {
|
||||
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 {
|
||||
|
||||
@@ -303,14 +303,6 @@ pub enum Packet {
|
||||
CoreMgmtClearLogRequest {
|
||||
destination: u8,
|
||||
},
|
||||
CoreMgmtSetLogLevelRequest {
|
||||
destination: u8,
|
||||
log_level: u8,
|
||||
},
|
||||
CoreMgmtSetUartLogLevelRequest {
|
||||
destination: u8,
|
||||
log_level: u8,
|
||||
},
|
||||
CoreMgmtConfigReadRequest {
|
||||
destination: u8,
|
||||
length: u16,
|
||||
@@ -689,15 +681,7 @@ impl Packet {
|
||||
0xd1 => Packet::CoreMgmtClearLogRequest {
|
||||
destination: reader.read_u8()?,
|
||||
},
|
||||
0xd2 => Packet::CoreMgmtSetLogLevelRequest {
|
||||
destination: reader.read_u8()?,
|
||||
log_level: reader.read_u8()?,
|
||||
},
|
||||
0xd3 => Packet::CoreMgmtSetUartLogLevelRequest {
|
||||
destination: reader.read_u8()?,
|
||||
log_level: reader.read_u8()?,
|
||||
},
|
||||
0xd4 => {
|
||||
0xd2 => {
|
||||
let destination = reader.read_u8()?;
|
||||
let length = reader.read_u16::<NativeEndian>()?;
|
||||
let mut key: [u8; MASTER_PAYLOAD_MAX_SIZE] = [0; MASTER_PAYLOAD_MAX_SIZE];
|
||||
@@ -708,10 +692,10 @@ impl Packet {
|
||||
key: key,
|
||||
}
|
||||
}
|
||||
0xd5 => Packet::CoreMgmtConfigReadContinue {
|
||||
0xd3 => Packet::CoreMgmtConfigReadContinue {
|
||||
destination: reader.read_u8()?,
|
||||
},
|
||||
0xd6 => {
|
||||
0xd4 => {
|
||||
let destination = reader.read_u8()?;
|
||||
let last = reader.read_bool()?;
|
||||
let length = reader.read_u16::<NativeEndian>()?;
|
||||
@@ -724,7 +708,7 @@ impl Packet {
|
||||
data: data,
|
||||
}
|
||||
}
|
||||
0xd7 => {
|
||||
0xd5 => {
|
||||
let destination = reader.read_u8()?;
|
||||
let length = reader.read_u16::<NativeEndian>()?;
|
||||
let mut key: [u8; MASTER_PAYLOAD_MAX_SIZE] = [0; MASTER_PAYLOAD_MAX_SIZE];
|
||||
@@ -735,20 +719,20 @@ impl Packet {
|
||||
key: key,
|
||||
}
|
||||
}
|
||||
0xd8 => Packet::CoreMgmtConfigEraseRequest {
|
||||
0xd6 => Packet::CoreMgmtConfigEraseRequest {
|
||||
destination: reader.read_u8()?,
|
||||
},
|
||||
0xd9 => Packet::CoreMgmtRebootRequest {
|
||||
0xd7 => Packet::CoreMgmtRebootRequest {
|
||||
destination: reader.read_u8()?,
|
||||
},
|
||||
0xda => Packet::CoreMgmtAllocatorDebugRequest {
|
||||
0xd8 => Packet::CoreMgmtAllocatorDebugRequest {
|
||||
destination: reader.read_u8()?,
|
||||
},
|
||||
0xdb => Packet::CoreMgmtFlashRequest {
|
||||
0xd9 => Packet::CoreMgmtFlashRequest {
|
||||
destination: reader.read_u8()?,
|
||||
payload_length: reader.read_u32::<NativeEndian>()?,
|
||||
},
|
||||
0xdc => {
|
||||
0xda => {
|
||||
let destination = reader.read_u8()?;
|
||||
let last = reader.read_bool()?;
|
||||
let length = reader.read_u16::<NativeEndian>()?;
|
||||
@@ -761,11 +745,11 @@ impl Packet {
|
||||
data: data,
|
||||
}
|
||||
}
|
||||
0xdd => Packet::CoreMgmtDropLinkAck {
|
||||
0xdb => Packet::CoreMgmtDropLinkAck {
|
||||
destination: reader.read_u8()?,
|
||||
},
|
||||
0xde => Packet::CoreMgmtDropLink,
|
||||
0xdf => {
|
||||
0xdc => Packet::CoreMgmtDropLink,
|
||||
0xdd => {
|
||||
let last = reader.read_bool()?;
|
||||
let length = reader.read_u16::<NativeEndian>()?;
|
||||
let mut data: [u8; SAT_PAYLOAD_MAX_SIZE] = [0; SAT_PAYLOAD_MAX_SIZE];
|
||||
@@ -776,7 +760,7 @@ impl Packet {
|
||||
data: data,
|
||||
}
|
||||
}
|
||||
0xe0 => {
|
||||
0xde => {
|
||||
let last = reader.read_bool()?;
|
||||
let length = reader.read_u16::<NativeEndian>()?;
|
||||
let mut value: [u8; SAT_PAYLOAD_MAX_SIZE] = [0; SAT_PAYLOAD_MAX_SIZE];
|
||||
@@ -787,45 +771,45 @@ impl Packet {
|
||||
value: value,
|
||||
}
|
||||
}
|
||||
0xe1 => Packet::CoreMgmtReply {
|
||||
0xdf => Packet::CoreMgmtReply {
|
||||
succeeded: reader.read_bool()?,
|
||||
},
|
||||
0xe2 => {
|
||||
0xe0 => {
|
||||
let length = reader.read_u16::<NativeEndian>()?;
|
||||
let mut message: [u8; CXP_PAYLOAD_MAX_SIZE] = [0; CXP_PAYLOAD_MAX_SIZE];
|
||||
reader.read_exact(&mut message[0..length as usize])?;
|
||||
Packet::CXPError { length, message }
|
||||
}
|
||||
0xe3 => Self::CXPWaitReply,
|
||||
0xe4 => Packet::CXPReadRequest {
|
||||
0xe1 => Self::CXPWaitReply,
|
||||
0xe2 => Packet::CXPReadRequest {
|
||||
destination: reader.read_u8()?,
|
||||
address: reader.read_u32::<NativeEndian>()?,
|
||||
length: reader.read_u16::<NativeEndian>()?,
|
||||
},
|
||||
0xe5 => {
|
||||
0xe3 => {
|
||||
let length = reader.read_u16::<NativeEndian>()?;
|
||||
let mut data: [u8; CXP_PAYLOAD_MAX_SIZE] = [0; CXP_PAYLOAD_MAX_SIZE];
|
||||
reader.read_exact(&mut data[0..length as usize])?;
|
||||
Packet::CXPReadReply { length, data }
|
||||
}
|
||||
0xe6 => Packet::CXPWrite32Request {
|
||||
0xe4 => Packet::CXPWrite32Request {
|
||||
destination: reader.read_u8()?,
|
||||
address: reader.read_u32::<NativeEndian>()?,
|
||||
value: reader.read_u32::<NativeEndian>()?,
|
||||
},
|
||||
0xe7 => Packet::CXPWrite32Reply,
|
||||
0xe8 => Packet::CXPROIViewerSetupRequest {
|
||||
0xe5 => Packet::CXPWrite32Reply,
|
||||
0xe6 => Packet::CXPROIViewerSetupRequest {
|
||||
destination: reader.read_u8()?,
|
||||
x0: reader.read_u16::<NativeEndian>()?,
|
||||
y0: reader.read_u16::<NativeEndian>()?,
|
||||
x1: reader.read_u16::<NativeEndian>()?,
|
||||
y1: reader.read_u16::<NativeEndian>()?,
|
||||
},
|
||||
0xe9 => Packet::CXPROIViewerSetupReply,
|
||||
0xea => Packet::CXPROIViewerDataRequest {
|
||||
0xe7 => Packet::CXPROIViewerSetupReply,
|
||||
0xe8 => Packet::CXPROIViewerDataRequest {
|
||||
destination: reader.read_u8()?,
|
||||
},
|
||||
0xeb => {
|
||||
0xe9 => {
|
||||
let length = reader.read_u16::<NativeEndian>()?;
|
||||
let mut data: [u64; CXP_PAYLOAD_MAX_SIZE / 8] = [0; CXP_PAYLOAD_MAX_SIZE / 8];
|
||||
for i in 0..length as usize {
|
||||
@@ -833,7 +817,7 @@ impl Packet {
|
||||
}
|
||||
Packet::CXPROIViewerPixelDataReply { length, data }
|
||||
}
|
||||
0xec => Packet::CXPROIViewerFrameDataReply {
|
||||
0xea => Packet::CXPROIViewerFrameDataReply {
|
||||
width: reader.read_u16::<NativeEndian>()?,
|
||||
height: reader.read_u16::<NativeEndian>()?,
|
||||
pixel_code: reader.read_u16::<NativeEndian>()?,
|
||||
@@ -1224,28 +1208,18 @@ impl Packet {
|
||||
writer.write_u8(0xd1)?;
|
||||
writer.write_u8(destination)?;
|
||||
}
|
||||
Packet::CoreMgmtSetLogLevelRequest { destination, log_level } => {
|
||||
writer.write_u8(0xd2)?;
|
||||
writer.write_u8(destination)?;
|
||||
writer.write_u8(log_level)?;
|
||||
}
|
||||
Packet::CoreMgmtSetUartLogLevelRequest { destination, log_level } => {
|
||||
writer.write_u8(0xd3)?;
|
||||
writer.write_u8(destination)?;
|
||||
writer.write_u8(log_level)?;
|
||||
}
|
||||
Packet::CoreMgmtConfigReadRequest {
|
||||
destination,
|
||||
length,
|
||||
key,
|
||||
} => {
|
||||
writer.write_u8(0xd4)?;
|
||||
writer.write_u8(0xd2)?;
|
||||
writer.write_u8(destination)?;
|
||||
writer.write_u16::<NativeEndian>(length)?;
|
||||
writer.write_all(&key[0..length as usize])?;
|
||||
}
|
||||
Packet::CoreMgmtConfigReadContinue { destination } => {
|
||||
writer.write_u8(0xd5)?;
|
||||
writer.write_u8(0xd3)?;
|
||||
writer.write_u8(destination)?;
|
||||
}
|
||||
Packet::CoreMgmtConfigWriteRequest {
|
||||
@@ -1254,7 +1228,7 @@ impl Packet {
|
||||
length,
|
||||
data,
|
||||
} => {
|
||||
writer.write_u8(0xd6)?;
|
||||
writer.write_u8(0xd4)?;
|
||||
writer.write_u8(destination)?;
|
||||
writer.write_bool(last)?;
|
||||
writer.write_u16::<NativeEndian>(length)?;
|
||||
@@ -1265,28 +1239,28 @@ impl Packet {
|
||||
length,
|
||||
key,
|
||||
} => {
|
||||
writer.write_u8(0xd7)?;
|
||||
writer.write_u8(0xd5)?;
|
||||
writer.write_u8(destination)?;
|
||||
writer.write_u16::<NativeEndian>(length)?;
|
||||
writer.write_all(&key[0..length as usize])?;
|
||||
}
|
||||
Packet::CoreMgmtConfigEraseRequest { destination } => {
|
||||
writer.write_u8(0xd8)?;
|
||||
writer.write_u8(0xd6)?;
|
||||
writer.write_u8(destination)?;
|
||||
}
|
||||
Packet::CoreMgmtRebootRequest { destination } => {
|
||||
writer.write_u8(0xd9)?;
|
||||
writer.write_u8(0xd7)?;
|
||||
writer.write_u8(destination)?;
|
||||
}
|
||||
Packet::CoreMgmtAllocatorDebugRequest { destination } => {
|
||||
writer.write_u8(0xda)?;
|
||||
writer.write_u8(0xd8)?;
|
||||
writer.write_u8(destination)?;
|
||||
}
|
||||
Packet::CoreMgmtFlashRequest {
|
||||
destination,
|
||||
payload_length,
|
||||
} => {
|
||||
writer.write_u8(0xdb)?;
|
||||
writer.write_u8(0xd9)?;
|
||||
writer.write_u8(destination)?;
|
||||
writer.write_u32::<NativeEndian>(payload_length)?;
|
||||
}
|
||||
@@ -1296,53 +1270,53 @@ impl Packet {
|
||||
length,
|
||||
data,
|
||||
} => {
|
||||
writer.write_u8(0xdc)?;
|
||||
writer.write_u8(0xda)?;
|
||||
writer.write_u8(destination)?;
|
||||
writer.write_bool(last)?;
|
||||
writer.write_u16::<NativeEndian>(length)?;
|
||||
writer.write_all(&data[..length as usize])?;
|
||||
}
|
||||
Packet::CoreMgmtDropLinkAck { destination } => {
|
||||
writer.write_u8(0xdd)?;
|
||||
writer.write_u8(0xdb)?;
|
||||
writer.write_u8(destination)?;
|
||||
}
|
||||
Packet::CoreMgmtDropLink => writer.write_u8(0xde)?,
|
||||
Packet::CoreMgmtDropLink => writer.write_u8(0xdc)?,
|
||||
Packet::CoreMgmtGetLogReply { last, length, data } => {
|
||||
writer.write_u8(0xdf)?;
|
||||
writer.write_u8(0xdd)?;
|
||||
writer.write_bool(last)?;
|
||||
writer.write_u16::<NativeEndian>(length)?;
|
||||
writer.write_all(&data[0..length as usize])?;
|
||||
}
|
||||
Packet::CoreMgmtConfigReadReply { last, length, value } => {
|
||||
writer.write_u8(0xe0)?;
|
||||
writer.write_u8(0xde)?;
|
||||
writer.write_bool(last)?;
|
||||
writer.write_u16::<NativeEndian>(length)?;
|
||||
writer.write_all(&value[0..length as usize])?;
|
||||
}
|
||||
Packet::CoreMgmtReply { succeeded } => {
|
||||
writer.write_u8(0xe1)?;
|
||||
writer.write_u8(0xdf)?;
|
||||
writer.write_bool(succeeded)?;
|
||||
}
|
||||
Packet::CXPError { length, message } => {
|
||||
writer.write_u8(0xe2)?;
|
||||
writer.write_u8(0xe0)?;
|
||||
writer.write_u16::<NativeEndian>(length)?;
|
||||
writer.write_all(&message[0..length as usize])?;
|
||||
}
|
||||
Packet::CXPWaitReply => {
|
||||
writer.write_u8(0xe3)?;
|
||||
writer.write_u8(0xe1)?;
|
||||
}
|
||||
Packet::CXPReadRequest {
|
||||
destination,
|
||||
address,
|
||||
length,
|
||||
} => {
|
||||
writer.write_u8(0xe4)?;
|
||||
writer.write_u8(0xe2)?;
|
||||
writer.write_u8(destination)?;
|
||||
writer.write_u32::<NativeEndian>(address)?;
|
||||
writer.write_u16::<NativeEndian>(length)?;
|
||||
}
|
||||
Packet::CXPReadReply { length, data } => {
|
||||
writer.write_u8(0xe5)?;
|
||||
writer.write_u8(0xe3)?;
|
||||
writer.write_u16::<NativeEndian>(length)?;
|
||||
writer.write_all(&data[0..length as usize])?;
|
||||
}
|
||||
@@ -1351,13 +1325,13 @@ impl Packet {
|
||||
address,
|
||||
value,
|
||||
} => {
|
||||
writer.write_u8(0xe6)?;
|
||||
writer.write_u8(0xe4)?;
|
||||
writer.write_u8(destination)?;
|
||||
writer.write_u32::<NativeEndian>(address)?;
|
||||
writer.write_u32::<NativeEndian>(value)?;
|
||||
}
|
||||
Packet::CXPWrite32Reply => {
|
||||
writer.write_u8(0xe7)?;
|
||||
writer.write_u8(0xe5)?;
|
||||
}
|
||||
Packet::CXPROIViewerSetupRequest {
|
||||
destination,
|
||||
@@ -1366,7 +1340,7 @@ impl Packet {
|
||||
x1,
|
||||
y1,
|
||||
} => {
|
||||
writer.write_u8(0xe8)?;
|
||||
writer.write_u8(0xe6)?;
|
||||
writer.write_u8(destination)?;
|
||||
writer.write_u16::<NativeEndian>(x0)?;
|
||||
writer.write_u16::<NativeEndian>(y0)?;
|
||||
@@ -1374,14 +1348,14 @@ impl Packet {
|
||||
writer.write_u16::<NativeEndian>(y1)?;
|
||||
}
|
||||
Packet::CXPROIViewerSetupReply => {
|
||||
writer.write_u8(0xe9)?;
|
||||
writer.write_u8(0xe7)?;
|
||||
}
|
||||
Packet::CXPROIViewerDataRequest { destination } => {
|
||||
writer.write_u8(0xea)?;
|
||||
writer.write_u8(0xe8)?;
|
||||
writer.write_u8(destination)?;
|
||||
}
|
||||
Packet::CXPROIViewerPixelDataReply { length, data } => {
|
||||
writer.write_u8(0xeb)?;
|
||||
writer.write_u8(0xe9)?;
|
||||
writer.write_u16::<NativeEndian>(length)?;
|
||||
for i in 0..length as usize {
|
||||
writer.write_u64::<NativeEndian>(data[i])?;
|
||||
@@ -1392,7 +1366,7 @@ impl Packet {
|
||||
height,
|
||||
pixel_code,
|
||||
} => {
|
||||
writer.write_u8(0xec)?;
|
||||
writer.write_u8(0xea)?;
|
||||
writer.write_u16::<NativeEndian>(width)?;
|
||||
writer.write_u16::<NativeEndian>(height)?;
|
||||
writer.write_u16::<NativeEndian>(pixel_code)?;
|
||||
|
||||
@@ -18,8 +18,10 @@ const IODIR_OUT_SFP_TX_DISABLE: u8 = 0x02;
|
||||
const IODIR_OUT_SFP_LED: u8 = 0x40;
|
||||
#[cfg(hw_rev = "v1.0")]
|
||||
const IODIR_OUT_SFP0_LED: u8 = 0x40;
|
||||
#[cfg(hw_rev = "v1.1")]
|
||||
#[cfg(any(hw_rev = "v1.1", hw_rev = "v1.2"))]
|
||||
const IODIR_OUT_SFP0_LED: u8 = 0x80;
|
||||
#[cfg(hw_rev = "v1.2")]
|
||||
const IODIR_OUT_EEM_PWR_EN: u8 = 0x80;
|
||||
#[cfg(has_si549)]
|
||||
const IODIR_CLK_SEL: u8 = 0x80; // out
|
||||
#[cfg(has_si5324)]
|
||||
@@ -31,10 +33,16 @@ const IODIR0: [u8; 2] = [
|
||||
0xFF & !IODIR_OUT_SFP_TX_DISABLE & !IODIR_OUT_SFP_LED & !IODIR_CLK_SEL,
|
||||
];
|
||||
|
||||
#[cfg(not(hw_rev = "v1.2"))]
|
||||
const IODIR1: [u8; 2] = [
|
||||
0xFF & !IODIR_OUT_SFP_TX_DISABLE & !IODIR_OUT_SFP_LED,
|
||||
0xFF & !IODIR_OUT_SFP_TX_DISABLE & !IODIR_OUT_SFP_LED,
|
||||
];
|
||||
#[cfg(hw_rev = "v1.2")]
|
||||
const IODIR1: [u8; 2] = [
|
||||
0xFF & !IODIR_OUT_SFP_TX_DISABLE & !IODIR_OUT_SFP_LED & !IODIR_OUT_EEM_PWR_EN,
|
||||
0xFF & !IODIR_OUT_SFP_TX_DISABLE & !IODIR_OUT_SFP_LED,
|
||||
];
|
||||
|
||||
pub struct IoExpander {
|
||||
address: u8,
|
||||
@@ -50,7 +58,7 @@ impl IoExpander {
|
||||
pub fn new(i2c: &mut i2c::I2c, index: u8) -> Result<Self, &'static str> {
|
||||
#[cfg(all(hw_rev = "v1.0", has_virtual_leds))]
|
||||
const VIRTUAL_LED_MAPPING0: [(u8, u8, u8); 2] = [(0, 0, 6), (1, 1, 6)];
|
||||
#[cfg(all(hw_rev = "v1.1", has_virtual_leds))]
|
||||
#[cfg(all(any(hw_rev = "v1.1", hw_rev = "v1.2"), has_virtual_leds))]
|
||||
const VIRTUAL_LED_MAPPING0: [(u8, u8, u8); 2] = [(0, 0, 7), (1, 1, 6)];
|
||||
#[cfg(has_virtual_leds)]
|
||||
const VIRTUAL_LED_MAPPING1: [(u8, u8, u8); 2] = [(2, 0, 6), (3, 1, 6)];
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
#![feature(naked_functions)]
|
||||
#![allow(unexpected_cfgs)]
|
||||
|
||||
#[cfg(has_drtio_eem)]
|
||||
extern crate alloc;
|
||||
extern crate core_io;
|
||||
extern crate crc;
|
||||
@@ -42,8 +41,14 @@ pub mod grabber;
|
||||
pub mod si5324;
|
||||
#[cfg(has_si549)]
|
||||
pub mod si549;
|
||||
use alloc::{collections::BTreeMap, string::String};
|
||||
use core::{cmp, str};
|
||||
|
||||
use byteorder::NativeEndian;
|
||||
use io::{Cursor, ProtoRead};
|
||||
use libcortex_a9::once_lock::OnceLock;
|
||||
use log::warn;
|
||||
|
||||
#[cfg(has_cxp_grabber)]
|
||||
pub mod cxp_camera_setup;
|
||||
#[cfg(has_cxp_grabber)]
|
||||
@@ -57,6 +62,25 @@ pub mod cxp_packet;
|
||||
#[cfg(has_cxp_grabber)]
|
||||
pub mod cxp_phys;
|
||||
|
||||
#[allow(static_mut_refs)]
|
||||
pub mod i2c {
|
||||
use core::mem::MaybeUninit;
|
||||
|
||||
use libboard_zynq::i2c::I2c;
|
||||
|
||||
static mut I2C_BUS: MaybeUninit<I2c> = MaybeUninit::uninit();
|
||||
|
||||
pub fn init() {
|
||||
let mut i2c = I2c::i2c0();
|
||||
i2c.init().expect("I2C bus initialization failed");
|
||||
unsafe { I2C_BUS.write(i2c) };
|
||||
}
|
||||
|
||||
pub fn get_bus() -> &'static mut I2c {
|
||||
unsafe { I2C_BUS.assume_init_mut() }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn identifier_read(buf: &mut [u8]) -> &str {
|
||||
unsafe {
|
||||
pl::csr::identifier::address_write(0);
|
||||
@@ -69,3 +93,50 @@ pub fn identifier_read(buf: &mut [u8]) -> &str {
|
||||
str::from_utf8_unchecked(&buf[..len as usize])
|
||||
}
|
||||
}
|
||||
|
||||
static RTIO_DEVICE_MAP: OnceLock<BTreeMap<u32, String>> = OnceLock::new();
|
||||
|
||||
fn read_device_map() -> BTreeMap<u32, String> {
|
||||
let mut device_map: BTreeMap<u32, String> = BTreeMap::new();
|
||||
let _ = libconfig::read("device_map")
|
||||
.and_then(|raw_bytes| {
|
||||
let mut bytes_cr = Cursor::new(raw_bytes);
|
||||
let size = bytes_cr.read_u32::<NativeEndian>().unwrap();
|
||||
for _ in 0..size {
|
||||
let channel = bytes_cr.read_u32::<NativeEndian>().unwrap();
|
||||
let device_name = bytes_cr.read_string::<NativeEndian>().unwrap();
|
||||
if let Some(old_entry) = device_map.insert(channel, device_name.clone()) {
|
||||
warn!(
|
||||
"conflicting device map entries for RTIO channel {}: '{}' and '{}'",
|
||||
channel, old_entry, device_name
|
||||
);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
.or_else(|err| {
|
||||
warn!(
|
||||
"error reading device map ({}), device names will not be available in RTIO error messages",
|
||||
err
|
||||
);
|
||||
Err(err)
|
||||
});
|
||||
device_map
|
||||
}
|
||||
|
||||
pub fn resolve_channel_name(channel: u32) -> String {
|
||||
match RTIO_DEVICE_MAP
|
||||
.get()
|
||||
.expect("cannot get device map before it is set up")
|
||||
.get(&channel)
|
||||
{
|
||||
Some(val) => val.clone(),
|
||||
None => String::from("unknown"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn setup_device_map() {
|
||||
RTIO_DEVICE_MAP
|
||||
.set(read_device_map())
|
||||
.expect("device map can only be initialized once");
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use core::{cell::Cell, fmt::Write};
|
||||
|
||||
use libboard_zynq::{println, timer};
|
||||
use libboard_zynq::{println, stdio, timer};
|
||||
use libcortex_a9::{mutex::{Mutex, MutexGuard},
|
||||
once_lock::OnceLock};
|
||||
use log::{LevelFilter, Log};
|
||||
@@ -13,8 +13,8 @@ pub struct LogBufferRef<'a> {
|
||||
|
||||
impl<'a> LogBufferRef<'a> {
|
||||
fn new(buffer: MutexGuard<'a, LogBuffer<&'static mut [u8]>>) -> LogBufferRef<'a> {
|
||||
let old_log_level = log::max_level();
|
||||
log::set_max_level(LevelFilter::Off);
|
||||
let old_log_level = BufferLogger::get_logger().buffer_log_level();
|
||||
BufferLogger::get_logger().set_buffer_log_level(LevelFilter::Off);
|
||||
LogBufferRef { buffer, old_log_level }
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ impl<'a> LogBufferRef<'a> {
|
||||
|
||||
impl<'a> Drop for LogBufferRef<'a> {
|
||||
fn drop(&mut self) {
|
||||
log::set_max_level(self.old_log_level)
|
||||
BufferLogger::get_logger().set_buffer_log_level(self.old_log_level);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ impl BufferLogger {
|
||||
BufferLogger {
|
||||
buffer: Mutex::new(LogBuffer::new(buffer)),
|
||||
uart_filter: Cell::new(LevelFilter::Info),
|
||||
buffer_filter: Cell::new(LevelFilter::Trace),
|
||||
buffer_filter: Cell::new(LevelFilter::Info),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,7 +72,8 @@ impl BufferLogger {
|
||||
}
|
||||
|
||||
pub fn set_uart_log_level(&self, max_level: LevelFilter) {
|
||||
self.uart_filter.set(max_level)
|
||||
self.uart_filter.set(max_level);
|
||||
self.update_global_log_level()
|
||||
}
|
||||
|
||||
pub fn buffer_log_level(&self) -> LevelFilter {
|
||||
@@ -81,7 +82,16 @@ impl BufferLogger {
|
||||
|
||||
/// this should be reserved for mgmt module
|
||||
pub fn set_buffer_log_level(&self, max_level: LevelFilter) {
|
||||
self.buffer_filter.set(max_level)
|
||||
self.buffer_filter.set(max_level);
|
||||
self.update_global_log_level()
|
||||
}
|
||||
|
||||
pub fn update_global_log_level(&self) {
|
||||
let uart_level = self.uart_filter.get();
|
||||
let buffer_level = self.buffer_filter.get();
|
||||
let global_level = core::cmp::max(uart_level, buffer_level);
|
||||
|
||||
log::set_max_level(global_level);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,5 +136,8 @@ impl Log for BufferLogger {
|
||||
}
|
||||
}
|
||||
|
||||
fn flush(&self) {}
|
||||
fn flush(&self) {
|
||||
let uart = stdio::get_uart();
|
||||
while !uart.tx_idle() {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,15 +81,15 @@ mod i2c {
|
||||
sda_oe(dcxo, false);
|
||||
|
||||
// Check the I2C bus is ready
|
||||
half_period(timer);
|
||||
half_period(timer);
|
||||
half_period();
|
||||
half_period();
|
||||
if !sda_i(dcxo) {
|
||||
// Try toggling SCL a few times
|
||||
for _bit in 0..8 {
|
||||
scl_o(dcxo, false);
|
||||
half_period(timer);
|
||||
half_period();
|
||||
scl_o(dcxo, true);
|
||||
half_period(timer);
|
||||
half_period();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,21 +102,21 @@ mod i2c {
|
||||
pub fn start(dcxo: DCXO) {
|
||||
// Set SCL high then SDA low
|
||||
scl_o(dcxo, true);
|
||||
half_period(timer);
|
||||
half_period();
|
||||
sda_oe(dcxo, true);
|
||||
half_period(timer);
|
||||
half_period();
|
||||
}
|
||||
|
||||
pub fn stop(dcxo: DCXO) {
|
||||
// First, make sure SCL is low, so that the target releases the SDA line
|
||||
scl_o(dcxo, false);
|
||||
half_period(timer);
|
||||
half_period();
|
||||
// Set SCL high then SDA high
|
||||
sda_oe(dcxo, true);
|
||||
scl_o(dcxo, true);
|
||||
half_period(timer);
|
||||
half_period();
|
||||
sda_oe(dcxo, false);
|
||||
half_period(timer);
|
||||
half_period();
|
||||
}
|
||||
|
||||
pub fn write(dcxo: DCXO, data: u8) -> bool {
|
||||
@@ -125,19 +125,19 @@ mod i2c {
|
||||
// Set SCL low and set our bit on SDA
|
||||
scl_o(dcxo, false);
|
||||
sda_oe(dcxo, data & (1 << bit) == 0);
|
||||
half_period(timer);
|
||||
half_period();
|
||||
// Set SCL high ; data is shifted on the rising edge of SCL
|
||||
scl_o(dcxo, true);
|
||||
half_period(timer);
|
||||
half_period();
|
||||
}
|
||||
// Check ack
|
||||
// Set SCL low, then release SDA so that the I2C target can respond
|
||||
scl_o(dcxo, false);
|
||||
half_period(timer);
|
||||
half_period();
|
||||
sda_oe(dcxo, false);
|
||||
// Set SCL high and check for ack
|
||||
scl_o(dcxo, true);
|
||||
half_period(timer);
|
||||
half_period();
|
||||
// returns true if acked (I2C target pulled SDA low)
|
||||
!sda_i(dcxo)
|
||||
}
|
||||
@@ -146,7 +146,7 @@ mod i2c {
|
||||
// Set SCL low first, otherwise setting SDA as input may cause a transition
|
||||
// on SDA with SCL high which will be interpreted as START/STOP condition.
|
||||
scl_o(dcxo, false);
|
||||
half_period(timer); // make sure SCL has settled low
|
||||
half_period(); // make sure SCL has settled low
|
||||
sda_oe(dcxo, false);
|
||||
|
||||
let mut data: u8 = 0;
|
||||
@@ -154,10 +154,10 @@ mod i2c {
|
||||
// MSB first
|
||||
for bit in (0..8).rev() {
|
||||
scl_o(dcxo, false);
|
||||
half_period(timer);
|
||||
half_period();
|
||||
// Set SCL high and shift data
|
||||
scl_o(dcxo, true);
|
||||
half_period(timer);
|
||||
half_period();
|
||||
if sda_i(dcxo) {
|
||||
data |= 1 << bit
|
||||
}
|
||||
@@ -168,78 +168,78 @@ mod i2c {
|
||||
if ack {
|
||||
sda_oe(dcxo, true)
|
||||
}
|
||||
half_period(timer);
|
||||
half_period();
|
||||
// then set SCL high
|
||||
scl_o(dcxo, true);
|
||||
half_period(timer);
|
||||
half_period();
|
||||
|
||||
data
|
||||
}
|
||||
}
|
||||
|
||||
fn write(dcxo: i2c::DCXO, reg: u8, val: u8) -> Result<(), &'static str> {
|
||||
i2c::start(dcxo, timer);
|
||||
if !i2c::write(dcxo, ADDRESS << 1, timer) {
|
||||
i2c::start(dcxo);
|
||||
if !i2c::write(dcxo, ADDRESS << 1) {
|
||||
return Err("Si549 failed to ack write address");
|
||||
}
|
||||
if !i2c::write(dcxo, reg, timer) {
|
||||
if !i2c::write(dcxo, reg) {
|
||||
return Err("Si549 failed to ack register");
|
||||
}
|
||||
if !i2c::write(dcxo, val, timer) {
|
||||
if !i2c::write(dcxo, val) {
|
||||
return Err("Si549 failed to ack value");
|
||||
}
|
||||
i2c::stop(dcxo, timer);
|
||||
i2c::stop(dcxo);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn read(dcxo: i2c::DCXO, reg: u8) -> Result<u8, &'static str> {
|
||||
i2c::start(dcxo, timer);
|
||||
if !i2c::write(dcxo, ADDRESS << 1, timer) {
|
||||
i2c::start(dcxo);
|
||||
if !i2c::write(dcxo, ADDRESS << 1) {
|
||||
return Err("Si549 failed to ack write address");
|
||||
}
|
||||
if !i2c::write(dcxo, reg, timer) {
|
||||
if !i2c::write(dcxo, reg) {
|
||||
return Err("Si549 failed to ack register");
|
||||
}
|
||||
i2c::stop(dcxo, timer);
|
||||
i2c::stop(dcxo);
|
||||
|
||||
i2c::start(dcxo, timer);
|
||||
if !i2c::write(dcxo, (ADDRESS << 1) | 1, timer) {
|
||||
i2c::start(dcxo);
|
||||
if !i2c::write(dcxo, (ADDRESS << 1) | 1) {
|
||||
return Err("Si549 failed to ack read address");
|
||||
}
|
||||
let val = i2c::read(dcxo, false, timer);
|
||||
i2c::stop(dcxo, timer);
|
||||
let val = i2c::read(dcxo, false);
|
||||
i2c::stop(dcxo);
|
||||
Ok(val)
|
||||
}
|
||||
|
||||
fn setup(dcxo: i2c::DCXO, config: &DividerConfig) -> Result<(), &'static str> {
|
||||
i2c::init(dcxo, timer)?;
|
||||
i2c::init(dcxo)?;
|
||||
|
||||
write(dcxo, 255, 0x00, timer)?; // PAGE
|
||||
write(dcxo, 69, 0x00, timer)?; // Disable FCAL override.
|
||||
write(dcxo, 17, 0x00, timer)?; // Synchronously disable output
|
||||
write(dcxo, 255, 0x00)?; // PAGE
|
||||
write(dcxo, 69, 0x00)?; // Disable FCAL override.
|
||||
write(dcxo, 17, 0x00)?; // Synchronously disable output
|
||||
|
||||
// The Si549 has no ID register, so we check that it responds correctly
|
||||
// by writing values to a RAM-like register and reading them back.
|
||||
for test_value in 0..255 {
|
||||
write(dcxo, 23, test_value, timer)?;
|
||||
let readback = read(dcxo, 23, timer)?;
|
||||
write(dcxo, 23, test_value)?;
|
||||
let readback = read(dcxo, 23)?;
|
||||
if readback != test_value {
|
||||
return Err("Si549 detection failed");
|
||||
}
|
||||
}
|
||||
|
||||
write(dcxo, 23, config.hsdiv as u8, timer)?;
|
||||
write(dcxo, 24, (config.hsdiv >> 8) as u8 | (config.lsdiv << 4), timer)?;
|
||||
write(dcxo, 26, config.fbdiv as u8, timer)?;
|
||||
write(dcxo, 27, (config.fbdiv >> 8) as u8, timer)?;
|
||||
write(dcxo, 28, (config.fbdiv >> 16) as u8, timer)?;
|
||||
write(dcxo, 29, (config.fbdiv >> 24) as u8, timer)?;
|
||||
write(dcxo, 30, (config.fbdiv >> 32) as u8, timer)?;
|
||||
write(dcxo, 31, (config.fbdiv >> 40) as u8, timer)?;
|
||||
write(dcxo, 23, config.hsdiv as u8)?;
|
||||
write(dcxo, 24, (config.hsdiv >> 8) as u8 | (config.lsdiv << 4))?;
|
||||
write(dcxo, 26, config.fbdiv as u8)?;
|
||||
write(dcxo, 27, (config.fbdiv >> 8) as u8)?;
|
||||
write(dcxo, 28, (config.fbdiv >> 16) as u8)?;
|
||||
write(dcxo, 29, (config.fbdiv >> 24) as u8)?;
|
||||
write(dcxo, 30, (config.fbdiv >> 32) as u8)?;
|
||||
write(dcxo, 31, (config.fbdiv >> 40) as u8)?;
|
||||
|
||||
write(dcxo, 7, 0x08, timer)?; // Start FCAL
|
||||
timer.delay_us(30_000); // Internal FCAL VCO calibration
|
||||
write(dcxo, 17, 0x01, timer)?; // Synchronously enable output
|
||||
write(dcxo, 7, 0x08)?; // Start FCAL
|
||||
timer::delay_us(30_000); // Internal FCAL VCO calibration
|
||||
write(dcxo, 17, 0x01)?; // Synchronously enable output
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -2,11 +2,16 @@ ENTRY(Reset);
|
||||
|
||||
MEMORY
|
||||
{
|
||||
SDRAM : ORIGIN = 0x00100000, LENGTH = 0x1FF00000
|
||||
/* TEXT is also a part of SDRAM. However linker won't match
|
||||
VMA and LDA after we do some overlaying with the code,
|
||||
so we just create a new region. */
|
||||
TEXT : ORIGIN = 0x00100000, LENGTH = 0x400000
|
||||
SDRAM : ORIGIN = 0x00500000, LENGTH = 0x1FB00000
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
PAGE_SIZE = 1M;
|
||||
__text_start = .;
|
||||
.text :
|
||||
{
|
||||
@@ -15,10 +20,38 @@ SECTIONS
|
||||
__exceptions_end = .;
|
||||
*(.text.boot);
|
||||
*(.text .text.*);
|
||||
} > SDRAM
|
||||
__text_end = .;
|
||||
} > TEXT
|
||||
|
||||
. = ALIGN(PAGE_SIZE);
|
||||
__rtio_page = .;
|
||||
|
||||
.rtio_page __rtio_page : AT(__rtio_page)
|
||||
{
|
||||
*(rtio_output);
|
||||
. = __rtio_page + PAGE_SIZE / 2;
|
||||
*(rtio_output_wide);
|
||||
} > TEXT
|
||||
|
||||
__dma_page = __rtio_page + PAGE_SIZE;
|
||||
.dma_page __rtio_page : AT(__dma_page)
|
||||
{
|
||||
*(dma_record_output);
|
||||
. = __rtio_page + PAGE_SIZE / 2;
|
||||
*(dma_record_output_wide);
|
||||
} > TEXT
|
||||
|
||||
__batch_page = __dma_page + PAGE_SIZE;
|
||||
.batch_page __rtio_page : AT(__batch_page)
|
||||
{
|
||||
*(batch_output);
|
||||
. = __rtio_page + PAGE_SIZE / 2;
|
||||
*(batch_output_wide);
|
||||
} > TEXT
|
||||
|
||||
/* End of TEXT region, start of SDRAM region, necessary for linker not to move things around */
|
||||
__text_end = ORIGIN(SDRAM);
|
||||
__exidx_start = ORIGIN(SDRAM);
|
||||
|
||||
__exidx_start = .;
|
||||
.ARM.exidx :
|
||||
{
|
||||
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
|
||||
|
||||
@@ -11,7 +11,6 @@ build_zynq = { path = "../libbuild_zynq" }
|
||||
[dependencies]
|
||||
cslice = "0.3"
|
||||
log = "0.4"
|
||||
nb = "0.1"
|
||||
core_io = { git = "https://git.m-labs.hk/M-Labs/rs-core_io.git", rev = "e9d3edf027", features = ["collections"] }
|
||||
byteorder = { version = "1.3", default-features = false }
|
||||
void = { version = "1", default-features = false }
|
||||
|
||||
@@ -95,6 +95,22 @@ pub fn resolve(required: &[u8]) -> Option<u32> {
|
||||
api!(rtio_input_data = rtio::input_data),
|
||||
api!(rtio_input_timestamped_data = rtio::input_timestamped_data),
|
||||
|
||||
// acp rtio batching
|
||||
#[cfg(ki_impl = "acp")]
|
||||
api!(rtio_batch_start = rtio::batch_start),
|
||||
#[cfg(ki_impl = "acp")]
|
||||
api!(rtio_batch_end = rtio::batch_end),
|
||||
|
||||
// workaround: if these functions are unused, they will not appear in the binary.
|
||||
// and these in particular should be accessed by page remapping.
|
||||
#[cfg(ki_impl = "acp")]
|
||||
api!(rtio_batch_output = rtio::batch_output),
|
||||
#[cfg(ki_impl = "acp")]
|
||||
api!(rtio_batch_output_wide = rtio::batch_output_wide),
|
||||
api!(dma_record_output = dma::dma_record_output),
|
||||
api!(dma_record_output_wide = dma::dma_record_output_wide),
|
||||
// end of workaround
|
||||
|
||||
// log
|
||||
api!(core_log = core_log),
|
||||
api!(rtio_log = rtio_log),
|
||||
@@ -302,6 +318,12 @@ pub fn resolve(required: &[u8]) -> Option<u32> {
|
||||
api_libm_f64f64!(exp2),
|
||||
api_libm_f64f64!(exp10),
|
||||
api_libm_f64f64!(expm1),
|
||||
{
|
||||
extern "C" fn ldexp(arg: f64, exp: i32) -> f64 {
|
||||
libm::ldexp(arg, exp)
|
||||
}
|
||||
api!(ldexp = ldexp)
|
||||
},
|
||||
api_libm_f64f64!(fabs),
|
||||
api_libm_f64f64!(floor),
|
||||
{
|
||||
|
||||
@@ -14,7 +14,7 @@ use log::{debug, error, info};
|
||||
|
||||
use super::{CHANNEL_0TO1, CHANNEL_1TO0, CHANNEL_SEM, INIT_LOCK, KERNEL_CHANNEL_0TO1, KERNEL_CHANNEL_1TO0,
|
||||
KERNEL_IMAGE, Message, api::resolve, dma, rpc::rpc_send_async};
|
||||
use crate::{eh_artiq, get_async_errors};
|
||||
use crate::eh_artiq;
|
||||
|
||||
// linker symbols
|
||||
extern "C" {
|
||||
@@ -22,6 +22,10 @@ extern "C" {
|
||||
static __text_end: u32;
|
||||
static __exidx_start: EXIDX_Entry;
|
||||
static __exidx_end: EXIDX_Entry;
|
||||
pub static __rtio_page: u32;
|
||||
pub static __dma_page: u32;
|
||||
#[cfg(ki_impl = "acp")]
|
||||
pub static __batch_page: u32;
|
||||
}
|
||||
|
||||
unsafe fn attribute_writeback(typeinfo: *const ()) {
|
||||
@@ -183,8 +187,7 @@ pub extern "C" fn main_core1() {
|
||||
}
|
||||
}
|
||||
info!("kernel finished");
|
||||
let async_errors = unsafe { get_async_errors() };
|
||||
core1_tx.send(Message::KernelFinished(async_errors));
|
||||
core1_tx.send(Message::KernelFinished);
|
||||
}
|
||||
_ => error!("Core1 received unexpected message: {:?}", message),
|
||||
}
|
||||
@@ -199,8 +202,7 @@ pub fn terminate(
|
||||
) -> ! {
|
||||
{
|
||||
let core1_tx = unsafe { KERNEL_CHANNEL_1TO0.as_mut().unwrap() };
|
||||
let errors = unsafe { get_async_errors() };
|
||||
core1_tx.send(Message::KernelException(exceptions, stack_pointers, backtrace, errors));
|
||||
core1_tx.send(Message::KernelException(exceptions, stack_pointers, backtrace));
|
||||
}
|
||||
loop {}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,11 @@ use alloc::{string::String, vec::Vec};
|
||||
use core::{mem, ptr};
|
||||
|
||||
use cslice::CSlice;
|
||||
use libcortex_a9::mmu;
|
||||
|
||||
use super::{KERNEL_CHANNEL_0TO1, KERNEL_CHANNEL_1TO0, KERNEL_IMAGE, Message, rtio};
|
||||
use super::{KERNEL_CHANNEL_0TO1, KERNEL_CHANNEL_1TO0, Message,
|
||||
core1::{__dma_page, __rtio_page},
|
||||
rtio};
|
||||
use crate::{artiq_raise, pl::csr};
|
||||
|
||||
#[repr(C)]
|
||||
@@ -42,11 +45,7 @@ pub extern "C" fn dma_record_start(name: CSlice<u8>) {
|
||||
artiq_raise!("DMAError", "DMA is already recording")
|
||||
}
|
||||
|
||||
let library = KERNEL_IMAGE.as_ref().unwrap();
|
||||
library.rebind(b"rtio_output", dma_record_output as *const ()).unwrap();
|
||||
library
|
||||
.rebind(b"rtio_output_wide", dma_record_output_wide as *const ())
|
||||
.unwrap();
|
||||
mmu::remap_section(&__rtio_page as *const _ as u32, &__dma_page as *const _ as u32);
|
||||
|
||||
RECORDER = Some(DmaRecorder {
|
||||
name,
|
||||
@@ -63,12 +62,7 @@ pub extern "C" fn dma_record_stop(duration: i64, enable_ddma: bool) {
|
||||
artiq_raise!("DMAError", "DMA is not recording")
|
||||
}
|
||||
|
||||
let library = KERNEL_IMAGE.as_ref().unwrap();
|
||||
library.rebind(b"rtio_output", rtio::output as *const ()).unwrap();
|
||||
library
|
||||
.rebind(b"rtio_output_wide", rtio::output_wide as *const ())
|
||||
.unwrap();
|
||||
|
||||
mmu::remap_section(&__rtio_page as *const _ as u32, &__rtio_page as *const _ as u32);
|
||||
let mut recorder = RECORDER.take().unwrap();
|
||||
recorder.duration = duration;
|
||||
recorder.enable_ddma = enable_ddma;
|
||||
@@ -104,6 +98,7 @@ unsafe fn dma_record_output_prepare(timestamp: i64, target: i32, words: usize) {
|
||||
]);
|
||||
}
|
||||
|
||||
#[link_section = "dma_record_output"]
|
||||
pub extern "C" fn dma_record_output(target: i32, word: i32) {
|
||||
unsafe {
|
||||
let timestamp = rtio::now_mu();
|
||||
@@ -117,6 +112,7 @@ pub extern "C" fn dma_record_output(target: i32, word: i32) {
|
||||
}
|
||||
}
|
||||
|
||||
#[link_section = "dma_record_output_wide"]
|
||||
pub extern "C" fn dma_record_output_wide(target: i32, words: &CSlice<i32>) {
|
||||
assert!(words.len() <= 16); // enforce the hardware limit
|
||||
|
||||
|
||||
@@ -1,192 +1,96 @@
|
||||
use core::mem::MaybeUninit;
|
||||
|
||||
use libboard_zynq::i2c::{Error, I2c};
|
||||
|
||||
#[cfg(has_drtio)]
|
||||
use super::{KERNEL_CHANNEL_0TO1, KERNEL_CHANNEL_1TO0, Message};
|
||||
use crate::artiq_raise;
|
||||
|
||||
static mut I2C_BUS: MaybeUninit<I2c> = MaybeUninit::uninit();
|
||||
|
||||
pub extern "C" fn start(busno: i32) {
|
||||
let _destination = (busno >> 16) as u8;
|
||||
#[cfg(has_drtio)]
|
||||
if _destination != 0 {
|
||||
let reply = unsafe {
|
||||
KERNEL_CHANNEL_1TO0
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.send(Message::I2cStartRequest(busno as u32));
|
||||
KERNEL_CHANNEL_0TO1.as_mut().unwrap().recv()
|
||||
};
|
||||
match reply {
|
||||
Message::I2cBasicReply(true) => return,
|
||||
Message::I2cBasicReply(false) => artiq_raise!("I2CError", "I2C remote start fail"),
|
||||
msg => panic!("Expected I2cBasicReply for I2cStartRequest, got: {:?}", msg),
|
||||
}
|
||||
}
|
||||
if busno > 0 {
|
||||
artiq_raise!("I2CError", "I2C bus could not be accessed");
|
||||
}
|
||||
if get_bus().start().is_err() {
|
||||
artiq_raise!("I2CError", "I2C start failed");
|
||||
let reply = unsafe {
|
||||
KERNEL_CHANNEL_1TO0
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.send(Message::I2cStartRequest(busno as u32));
|
||||
KERNEL_CHANNEL_0TO1.as_mut().unwrap().recv()
|
||||
};
|
||||
match reply {
|
||||
Message::I2cBasicReply(true) => (),
|
||||
Message::I2cBasicReply(false) => artiq_raise!("I2CError", "I2C start fail"),
|
||||
msg => panic!("Expected I2cBasicReply for I2cStartRequest, got: {:?}", msg),
|
||||
}
|
||||
}
|
||||
|
||||
pub extern "C" fn restart(busno: i32) {
|
||||
let _destination = (busno >> 16) as u8;
|
||||
#[cfg(has_drtio)]
|
||||
if _destination != 0 {
|
||||
let reply = unsafe {
|
||||
KERNEL_CHANNEL_1TO0
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.send(Message::I2cRestartRequest(busno as u32));
|
||||
KERNEL_CHANNEL_0TO1.as_mut().unwrap().recv()
|
||||
};
|
||||
match reply {
|
||||
Message::I2cBasicReply(true) => return,
|
||||
Message::I2cBasicReply(false) => artiq_raise!("I2CError", "I2C remote restart fail"),
|
||||
msg => panic!("Expected I2cBasicReply for I2cRetartRequest, got: {:?}", msg),
|
||||
}
|
||||
}
|
||||
if busno > 0 {
|
||||
artiq_raise!("I2CError", "I2C bus could not be accessed");
|
||||
}
|
||||
if get_bus().restart().is_err() {
|
||||
artiq_raise!("I2CError", "I2C restart failed");
|
||||
let reply = unsafe {
|
||||
KERNEL_CHANNEL_1TO0
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.send(Message::I2cRestartRequest(busno as u32));
|
||||
KERNEL_CHANNEL_0TO1.as_mut().unwrap().recv()
|
||||
};
|
||||
match reply {
|
||||
Message::I2cBasicReply(true) => (),
|
||||
Message::I2cBasicReply(false) => artiq_raise!("I2CError", "I2C restart fail"),
|
||||
msg => panic!("Expected I2cBasicReply for I2cRestartRequest, got: {:?}", msg),
|
||||
}
|
||||
}
|
||||
|
||||
pub extern "C" fn stop(busno: i32) {
|
||||
let _destination = (busno >> 16) as u8;
|
||||
#[cfg(has_drtio)]
|
||||
if _destination != 0 {
|
||||
// remote
|
||||
let reply = unsafe {
|
||||
KERNEL_CHANNEL_1TO0
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.send(Message::I2cStopRequest(busno as u32));
|
||||
KERNEL_CHANNEL_0TO1.as_mut().unwrap().recv()
|
||||
};
|
||||
match reply {
|
||||
Message::I2cBasicReply(true) => return,
|
||||
Message::I2cBasicReply(false) => artiq_raise!("I2CError", "I2C remote stop fail"),
|
||||
msg => panic!("Expected I2cBasicReply for I2cStopRequest, got: {:?}", msg),
|
||||
}
|
||||
}
|
||||
if busno > 0 {
|
||||
artiq_raise!("I2CError", "I2C bus could not be accessed");
|
||||
}
|
||||
if get_bus().stop().is_err() {
|
||||
artiq_raise!("I2CError", "I2C stop failed");
|
||||
let reply = unsafe {
|
||||
KERNEL_CHANNEL_1TO0
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.send(Message::I2cStopRequest(busno as u32));
|
||||
KERNEL_CHANNEL_0TO1.as_mut().unwrap().recv()
|
||||
};
|
||||
match reply {
|
||||
Message::I2cBasicReply(true) => (),
|
||||
Message::I2cBasicReply(false) => artiq_raise!("I2CError", "I2C stop fail"),
|
||||
msg => panic!("Expected I2cBasicReply for I2cStopRequest, got: {:?}", msg),
|
||||
}
|
||||
}
|
||||
|
||||
pub extern "C" fn write(busno: i32, data: i32) -> bool {
|
||||
let _destination = (busno >> 16) as u8;
|
||||
#[cfg(has_drtio)]
|
||||
if _destination != 0 {
|
||||
// remote
|
||||
let reply = unsafe {
|
||||
KERNEL_CHANNEL_1TO0.as_mut().unwrap().send(Message::I2cWriteRequest {
|
||||
busno: busno as u32,
|
||||
data: data as u8,
|
||||
});
|
||||
KERNEL_CHANNEL_0TO1.as_mut().unwrap().recv()
|
||||
};
|
||||
match reply {
|
||||
Message::I2cWriteReply { succeeded: true, ack } => return ack,
|
||||
Message::I2cWriteReply { succeeded: false, .. } => artiq_raise!("I2CError", "I2C remote write fail"),
|
||||
msg => panic!("Expected I2cWriteReply for I2cWriteRequest, got: {:?}", msg),
|
||||
}
|
||||
}
|
||||
if busno > 0 {
|
||||
artiq_raise!("I2CError", "I2C bus could not be accessed");
|
||||
}
|
||||
match get_bus().write(data as u8) {
|
||||
Ok(()) => true,
|
||||
Err(Error::Nack) => false,
|
||||
Err(_) => artiq_raise!("I2CError", "I2C write failed"),
|
||||
let reply = unsafe {
|
||||
KERNEL_CHANNEL_1TO0.as_mut().unwrap().send(Message::I2cWriteRequest {
|
||||
busno: busno as u32,
|
||||
data: data as u8,
|
||||
});
|
||||
KERNEL_CHANNEL_0TO1.as_mut().unwrap().recv()
|
||||
};
|
||||
match reply {
|
||||
Message::I2cWriteReply { succeeded: true, ack } => ack,
|
||||
Message::I2cWriteReply { succeeded: false, .. } => artiq_raise!("I2CError", "I2C write fail"),
|
||||
msg => panic!("Expected I2cWriteReply for I2cWriteRequest, got: {:?}", msg),
|
||||
}
|
||||
}
|
||||
|
||||
pub extern "C" fn read(busno: i32, ack: bool) -> i32 {
|
||||
let _destination = (busno >> 16) as u8;
|
||||
#[cfg(has_drtio)]
|
||||
if _destination != 0 {
|
||||
let reply = unsafe {
|
||||
KERNEL_CHANNEL_1TO0.as_mut().unwrap().send(Message::I2cReadRequest {
|
||||
busno: busno as u32,
|
||||
ack,
|
||||
});
|
||||
KERNEL_CHANNEL_0TO1.as_mut().unwrap().recv()
|
||||
};
|
||||
match reply {
|
||||
Message::I2cReadReply { succeeded: true, data } => return data as i32,
|
||||
Message::I2cReadReply { succeeded: false, .. } => artiq_raise!("I2CError", "I2C remote read fail"),
|
||||
msg => panic!("Expected I2cReadReply for I2cReadRequest, got: {:?}", msg),
|
||||
}
|
||||
}
|
||||
if busno > 0 {
|
||||
artiq_raise!("I2CError", "I2C bus could not be accessed");
|
||||
}
|
||||
match get_bus().read(ack) {
|
||||
Ok(r) => r as i32,
|
||||
Err(_) => artiq_raise!("I2CError", "I2C read failed"),
|
||||
let reply = unsafe {
|
||||
KERNEL_CHANNEL_1TO0.as_mut().unwrap().send(Message::I2cReadRequest {
|
||||
busno: busno as u32,
|
||||
ack,
|
||||
});
|
||||
KERNEL_CHANNEL_0TO1.as_mut().unwrap().recv()
|
||||
};
|
||||
match reply {
|
||||
Message::I2cReadReply { succeeded: true, data } => data as i32,
|
||||
Message::I2cReadReply { succeeded: false, .. } => artiq_raise!("I2CError", "I2C read fail"),
|
||||
msg => panic!("Expected I2cReadReply for I2cReadRequest, got: {:?}", msg),
|
||||
}
|
||||
}
|
||||
|
||||
pub extern "C" fn switch_select(busno: i32, address: i32, mask: i32) {
|
||||
let _destination = (busno >> 16) as u8;
|
||||
#[cfg(has_drtio)]
|
||||
if _destination != 0 {
|
||||
// remote
|
||||
let reply = unsafe {
|
||||
KERNEL_CHANNEL_1TO0
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.send(Message::I2cSwitchSelectRequest {
|
||||
busno: busno as u32,
|
||||
address: address as u8,
|
||||
mask: mask as u8,
|
||||
});
|
||||
KERNEL_CHANNEL_0TO1.as_mut().unwrap().recv()
|
||||
};
|
||||
match reply {
|
||||
Message::I2cBasicReply(true) => return,
|
||||
Message::I2cBasicReply(false) => artiq_raise!("I2CError", "I2C remote start fail"),
|
||||
msg => panic!("Expected I2cBasicReply for I2cSwitchSelectRequest, got: {:?}", msg),
|
||||
}
|
||||
}
|
||||
if busno > 0 {
|
||||
artiq_raise!("I2CError", "I2C bus could not be accessed");
|
||||
}
|
||||
let ch = match mask {
|
||||
//decode from mainline, PCA9548-centric API
|
||||
0x00 => None,
|
||||
0x01 => Some(0),
|
||||
0x02 => Some(1),
|
||||
0x04 => Some(2),
|
||||
0x08 => Some(3),
|
||||
0x10 => Some(4),
|
||||
0x20 => Some(5),
|
||||
0x40 => Some(6),
|
||||
0x80 => Some(7),
|
||||
_ => artiq_raise!("I2CError", "switch select supports only one channel"),
|
||||
let reply = unsafe {
|
||||
KERNEL_CHANNEL_1TO0
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.send(Message::I2cSwitchSelectRequest {
|
||||
busno: busno as u32,
|
||||
address: address as u8,
|
||||
mask: mask as u8,
|
||||
});
|
||||
KERNEL_CHANNEL_0TO1.as_mut().unwrap().recv()
|
||||
};
|
||||
if get_bus().pca954x_select(address as u8, ch).is_err() {
|
||||
artiq_raise!("I2CError", "switch select failed");
|
||||
match reply {
|
||||
Message::I2cBasicReply(true) => (),
|
||||
Message::I2cBasicReply(false) => artiq_raise!("I2CError", "I2C switch select fail"),
|
||||
msg => panic!("Expected I2cBasicReply for I2cSwitchSelectRequest, got: {:?}", msg),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn init() {
|
||||
let mut i2c = I2c::i2c0();
|
||||
i2c.init().expect("I2C bus initialization failed");
|
||||
unsafe { I2C_BUS.write(i2c) };
|
||||
}
|
||||
|
||||
pub fn get_bus() -> &'static mut I2c {
|
||||
unsafe { I2C_BUS.assume_init_mut() }
|
||||
}
|
||||
|
||||
@@ -45,12 +45,11 @@ pub enum Message {
|
||||
LoadCompleted,
|
||||
LoadFailed,
|
||||
StartRequest,
|
||||
KernelFinished(u8),
|
||||
KernelFinished,
|
||||
KernelException(
|
||||
&'static [Option<eh_artiq::Exception<'static>>],
|
||||
&'static [eh_artiq::StackPointerBacktrace],
|
||||
&'static [(usize, usize)],
|
||||
u8,
|
||||
),
|
||||
|
||||
#[cfg(has_drtio)]
|
||||
@@ -93,35 +92,26 @@ pub enum Message {
|
||||
#[cfg(has_drtio)]
|
||||
UpDestinationsReply(bool),
|
||||
|
||||
#[cfg(has_drtio)]
|
||||
I2cStartRequest(u32),
|
||||
#[cfg(has_drtio)]
|
||||
I2cRestartRequest(u32),
|
||||
#[cfg(has_drtio)]
|
||||
I2cStopRequest(u32),
|
||||
#[cfg(has_drtio)]
|
||||
I2cWriteRequest {
|
||||
busno: u32,
|
||||
data: u8,
|
||||
},
|
||||
#[cfg(has_drtio)]
|
||||
I2cWriteReply {
|
||||
succeeded: bool,
|
||||
ack: bool,
|
||||
},
|
||||
#[cfg(has_drtio)]
|
||||
I2cReadRequest {
|
||||
busno: u32,
|
||||
ack: bool,
|
||||
},
|
||||
#[cfg(has_drtio)]
|
||||
I2cReadReply {
|
||||
succeeded: bool,
|
||||
data: u8,
|
||||
},
|
||||
#[cfg(has_drtio)]
|
||||
I2cBasicReply(bool),
|
||||
#[cfg(has_drtio)]
|
||||
I2cSwitchSelectRequest {
|
||||
busno: u32,
|
||||
address: u8,
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
use core::sync::atomic::{Ordering, fence};
|
||||
|
||||
use cslice::CSlice;
|
||||
use libcortex_a9::asm;
|
||||
use libcortex_a9::{asm, mmu};
|
||||
use vcell::VolatileCell;
|
||||
|
||||
use super::core1::{__batch_page, __rtio_page};
|
||||
#[cfg(has_drtio)]
|
||||
use super::{KERNEL_CHANNEL_0TO1, KERNEL_CHANNEL_1TO0, Message};
|
||||
use crate::{artiq_raise, pl::csr, resolve_channel_name, rtio_core};
|
||||
use crate::{artiq_raise, pl::csr, rtio_core};
|
||||
|
||||
pub const RTIO_O_STATUS_WAIT: i32 = 1;
|
||||
pub const RTIO_O_STATUS_UNDERFLOW: i32 = 2;
|
||||
@@ -17,46 +18,80 @@ pub const RTIO_I_STATUS_OVERFLOW: i32 = 2;
|
||||
pub const RTIO_I_STATUS_WAIT_STATUS: i32 = 4; // TODO
|
||||
pub const RTIO_I_STATUS_DESTINATION_UNREACHABLE: i32 = 8;
|
||||
|
||||
const RTIO_CMD_OUTPUT: i8 = 0;
|
||||
const RTIO_CMD_INPUT: i8 = 1;
|
||||
|
||||
const BATCH_ENABLED: i8 = 1;
|
||||
const BATCH_DISABLED: i8 = 0;
|
||||
|
||||
#[repr(C)]
|
||||
pub struct TimestampedData {
|
||||
timestamp: i64,
|
||||
data: i32,
|
||||
}
|
||||
|
||||
#[repr(C, align(64))]
|
||||
struct Transaction {
|
||||
#[repr(C, align(16))]
|
||||
#[derive(Copy, Clone)]
|
||||
struct OutTransaction {
|
||||
request_cmd: i8,
|
||||
data_width: i8,
|
||||
padding0: [i8; 2],
|
||||
padding: [i8; 2],
|
||||
request_target: i32,
|
||||
request_timestamp: i64,
|
||||
request_data: [i32; 16],
|
||||
padding1: [i64; 2],
|
||||
}
|
||||
|
||||
#[repr(C, align(16))]
|
||||
struct InTransaction {
|
||||
reply_status: VolatileCell<i32>,
|
||||
reply_data: VolatileCell<i32>,
|
||||
reply_timestamp: VolatileCell<i64>,
|
||||
padding2: [i64; 2],
|
||||
reply_batch_cnt: VolatileCell<i32>,
|
||||
padding: i32,
|
||||
}
|
||||
|
||||
static mut TRANSACTION_BUFFER: Transaction = Transaction {
|
||||
request_cmd: 0,
|
||||
data_width: 0,
|
||||
request_target: 0,
|
||||
request_timestamp: 0,
|
||||
request_data: [0; 16],
|
||||
static mut IN_BUFFER: InTransaction = InTransaction {
|
||||
reply_status: VolatileCell::new(0),
|
||||
reply_data: VolatileCell::new(0),
|
||||
reply_timestamp: VolatileCell::new(0),
|
||||
padding0: [0; 2],
|
||||
padding1: [0; 2],
|
||||
padding2: [0; 2],
|
||||
reply_batch_cnt: VolatileCell::new(0),
|
||||
padding: 0,
|
||||
};
|
||||
|
||||
const BUFFER_SIZE: usize = csr::CONFIG_ACPKI_BATCH_SIZE as usize;
|
||||
|
||||
#[repr(C, align(16))]
|
||||
struct OutBuffer {
|
||||
/* META */
|
||||
ptr: i32, // next writeable position in batch mode, also serves as len
|
||||
running: i8,
|
||||
padding: [i8; 11], // aligned to 16 bytes (per AXI alignment requirements)
|
||||
/* Output transactions */
|
||||
transactions: [OutTransaction; BUFFER_SIZE],
|
||||
}
|
||||
|
||||
static mut OUT_BUFFER: OutBuffer = OutBuffer {
|
||||
ptr: 0,
|
||||
running: 0,
|
||||
padding: [0; 11],
|
||||
transactions: [OutTransaction {
|
||||
request_cmd: 0,
|
||||
data_width: 0,
|
||||
request_target: 0,
|
||||
request_timestamp: 0,
|
||||
request_data: [0; 16],
|
||||
padding: [0; 2],
|
||||
}; BUFFER_SIZE],
|
||||
};
|
||||
|
||||
pub extern "C" fn init() {
|
||||
unsafe {
|
||||
rtio_core::reset_write(1);
|
||||
csr::rtio::engine_addr_base_write(&TRANSACTION_BUFFER as *const Transaction as u32);
|
||||
csr::rtio::in_base_write(&IN_BUFFER as *const InTransaction as u32);
|
||||
csr::rtio::out_base_write(&OUT_BUFFER as *const OutBuffer as u32);
|
||||
csr::rtio::enable_write(1);
|
||||
mmu::remap_section(&__rtio_page as *const _ as u32, &__rtio_page as *const _ as u32);
|
||||
OUT_BUFFER.running = BATCH_DISABLED;
|
||||
}
|
||||
#[cfg(has_drtio)]
|
||||
unsafe {
|
||||
@@ -90,20 +125,18 @@ pub extern "C" fn delay_mu(dt: i64) {
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
unsafe fn process_exceptional_status(channel: i32, status: i32) {
|
||||
let timestamp = now_mu();
|
||||
pub unsafe fn process_exceptional_status(channel: i32, status: i32, timestamp: i64) {
|
||||
// The gateware should handle waiting, but sometimes it will slip through the cracks
|
||||
let mut status = status;
|
||||
if status & RTIO_O_STATUS_WAIT != 0 {
|
||||
// FIXME: this is a kludge and probably buggy (kernel interrupted?)
|
||||
while csr::rtio::o_status_read() as i32 & RTIO_O_STATUS_WAIT != 0 {}
|
||||
while status & RTIO_O_STATUS_WAIT != 0 {
|
||||
status = csr::rtio::o_status_read() as i32;
|
||||
}
|
||||
}
|
||||
if status & RTIO_O_STATUS_UNDERFLOW != 0 {
|
||||
artiq_raise!(
|
||||
"RTIOUnderflow",
|
||||
format!(
|
||||
"RTIO underflow at {{1}} mu, channel 0x{:04x}:{}, slack {{2}} mu",
|
||||
channel,
|
||||
resolve_channel_name(channel as u32)
|
||||
),
|
||||
"RTIO underflow at {1} mu, channel {rtio_channel_info:0}, slack {2} mu",
|
||||
channel as i64,
|
||||
timestamp,
|
||||
timestamp - get_counter()
|
||||
@@ -112,103 +145,96 @@ unsafe fn process_exceptional_status(channel: i32, status: i32) {
|
||||
if status & RTIO_O_STATUS_DESTINATION_UNREACHABLE != 0 {
|
||||
artiq_raise!(
|
||||
"RTIODestinationUnreachable",
|
||||
format!(
|
||||
"RTIO destination unreachable, output, at {{0}} mu, channel 0x{:04x}:{}",
|
||||
channel,
|
||||
resolve_channel_name(channel as u32)
|
||||
),
|
||||
timestamp,
|
||||
"RTIO destination unreachable, output, at {1} mu, channel {rtio_channel_info:0}",
|
||||
channel as i64,
|
||||
timestamp,
|
||||
0
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub extern "C" fn output(target: i32, data: i32) {
|
||||
fn await_reply_status() -> i32 {
|
||||
unsafe {
|
||||
// Clear status so we can observe response
|
||||
TRANSACTION_BUFFER.reply_status.set(0);
|
||||
|
||||
TRANSACTION_BUFFER.request_cmd = 0;
|
||||
TRANSACTION_BUFFER.data_width = 1;
|
||||
TRANSACTION_BUFFER.request_target = target;
|
||||
TRANSACTION_BUFFER.request_timestamp = NOW;
|
||||
TRANSACTION_BUFFER.request_data[0] = data;
|
||||
|
||||
// dmb and send event (commit the event to gateware)
|
||||
fence(Ordering::SeqCst);
|
||||
asm::sev();
|
||||
let mut status;
|
||||
// actually await status
|
||||
loop {
|
||||
status = TRANSACTION_BUFFER.reply_status.get();
|
||||
let status = IN_BUFFER.reply_status.get();
|
||||
if status != 0 {
|
||||
break;
|
||||
// Clear status so we can observe response on the next call
|
||||
IN_BUFFER.reply_status.set(0);
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
let status = status & !0x10000;
|
||||
if status != 0 {
|
||||
process_exceptional_status(target >> 8, status);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[link_section = "rtio_output"]
|
||||
pub extern "C" fn output(target: i32, data: i32) {
|
||||
unsafe {
|
||||
OUT_BUFFER.transactions[0].request_cmd = RTIO_CMD_OUTPUT;
|
||||
OUT_BUFFER.transactions[0].data_width = 1;
|
||||
OUT_BUFFER.transactions[0].request_target = target;
|
||||
OUT_BUFFER.transactions[0].request_timestamp = NOW;
|
||||
OUT_BUFFER.transactions[0].request_data[0] = data;
|
||||
|
||||
let status = await_reply_status() & !(1 << 16);
|
||||
if status != 0 {
|
||||
process_exceptional_status(target >> 8, status, now_mu());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[link_section = "rtio_output_wide"]
|
||||
pub extern "C" fn output_wide(target: i32, data: CSlice<i32>) {
|
||||
unsafe {
|
||||
// Clear status so we can observe response
|
||||
TRANSACTION_BUFFER.reply_status.set(0);
|
||||
OUT_BUFFER.transactions[0].request_cmd = RTIO_CMD_OUTPUT;
|
||||
OUT_BUFFER.transactions[0].data_width = data.len() as i8;
|
||||
OUT_BUFFER.transactions[0].request_target = target;
|
||||
OUT_BUFFER.transactions[0].request_timestamp = NOW;
|
||||
OUT_BUFFER.transactions[0].request_data[..data.len()].copy_from_slice(data.as_ref());
|
||||
|
||||
TRANSACTION_BUFFER.request_cmd = 0;
|
||||
TRANSACTION_BUFFER.data_width = data.len() as i8;
|
||||
TRANSACTION_BUFFER.request_target = target;
|
||||
TRANSACTION_BUFFER.request_timestamp = NOW;
|
||||
TRANSACTION_BUFFER.request_data[..data.len()].copy_from_slice(data.as_ref());
|
||||
|
||||
fence(Ordering::SeqCst);
|
||||
asm::sev();
|
||||
let mut status;
|
||||
loop {
|
||||
status = TRANSACTION_BUFFER.reply_status.get();
|
||||
if status != 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let status = status & !0x10000;
|
||||
let status = await_reply_status() & !(1 << 16);
|
||||
if status != 0 {
|
||||
process_exceptional_status(target >> 8, status);
|
||||
process_exceptional_status(target >> 8, status, now_mu());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn process_exceptional_input_status(status: i32, channel: i32) {
|
||||
if status & RTIO_I_STATUS_OVERFLOW != 0 {
|
||||
artiq_raise!(
|
||||
"RTIOOverflow",
|
||||
"RTIO input overflow on channel {rtio_channel_info:0}",
|
||||
channel as i64,
|
||||
0,
|
||||
0
|
||||
);
|
||||
}
|
||||
if status & RTIO_I_STATUS_DESTINATION_UNREACHABLE != 0 {
|
||||
artiq_raise!(
|
||||
"RTIODestinationUnreachable",
|
||||
"RTIO destination unreachable, input, on channel {rtio_channel_info:0}",
|
||||
channel as i64,
|
||||
0,
|
||||
0
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub extern "C" fn input_timestamp(timeout: i64, channel: i32) -> i64 {
|
||||
unsafe {
|
||||
// Clear status so we can observe response
|
||||
TRANSACTION_BUFFER.reply_status.set(0);
|
||||
|
||||
TRANSACTION_BUFFER.request_cmd = 1;
|
||||
TRANSACTION_BUFFER.request_timestamp = timeout;
|
||||
TRANSACTION_BUFFER.request_target = channel << 8;
|
||||
TRANSACTION_BUFFER.data_width = 0;
|
||||
|
||||
fence(Ordering::SeqCst);
|
||||
asm::sev();
|
||||
|
||||
let mut status;
|
||||
loop {
|
||||
status = TRANSACTION_BUFFER.reply_status.get();
|
||||
if status != 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
OUT_BUFFER.transactions[0].request_cmd = RTIO_CMD_INPUT;
|
||||
OUT_BUFFER.transactions[0].request_timestamp = timeout;
|
||||
OUT_BUFFER.transactions[0].request_target = channel << 8;
|
||||
OUT_BUFFER.transactions[0].data_width = 0;
|
||||
let status = await_reply_status();
|
||||
|
||||
if status & RTIO_I_STATUS_OVERFLOW != 0 {
|
||||
artiq_raise!(
|
||||
"RTIOOverflow",
|
||||
format!(
|
||||
"RTIO input overflow on channel 0x{:04x}:{}",
|
||||
channel,
|
||||
resolve_channel_name(channel as u32)
|
||||
),
|
||||
"RTIO input overflow on channel {rtio_channel_info:0}",
|
||||
channel as i64,
|
||||
0,
|
||||
0
|
||||
@@ -220,122 +246,45 @@ pub extern "C" fn input_timestamp(timeout: i64, channel: i32) -> i64 {
|
||||
if status & RTIO_I_STATUS_DESTINATION_UNREACHABLE != 0 {
|
||||
artiq_raise!(
|
||||
"RTIODestinationUnreachable",
|
||||
format!(
|
||||
"RTIO destination unreachable, input, on channel 0x{:04x}:{}",
|
||||
channel,
|
||||
resolve_channel_name(channel as u32)
|
||||
),
|
||||
"RTIO destination unreachable, input, on channel {rtio_channel_info:0}",
|
||||
channel as i64,
|
||||
0,
|
||||
0
|
||||
);
|
||||
}
|
||||
|
||||
TRANSACTION_BUFFER.reply_timestamp.get()
|
||||
IN_BUFFER.reply_timestamp.get()
|
||||
}
|
||||
}
|
||||
|
||||
pub extern "C" fn input_data(channel: i32) -> i32 {
|
||||
unsafe {
|
||||
TRANSACTION_BUFFER.reply_status.set(0);
|
||||
OUT_BUFFER.transactions[0].request_cmd = RTIO_CMD_INPUT;
|
||||
OUT_BUFFER.transactions[0].request_timestamp = -1;
|
||||
OUT_BUFFER.transactions[0].request_target = channel << 8;
|
||||
OUT_BUFFER.transactions[0].data_width = 0;
|
||||
|
||||
TRANSACTION_BUFFER.request_cmd = 1;
|
||||
TRANSACTION_BUFFER.request_timestamp = -1;
|
||||
TRANSACTION_BUFFER.request_target = channel << 8;
|
||||
TRANSACTION_BUFFER.data_width = 0;
|
||||
let status = await_reply_status();
|
||||
|
||||
fence(Ordering::SeqCst);
|
||||
asm::sev();
|
||||
process_exceptional_input_status(status, channel);
|
||||
|
||||
let mut status;
|
||||
loop {
|
||||
status = TRANSACTION_BUFFER.reply_status.get();
|
||||
if status != 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if status & RTIO_I_STATUS_OVERFLOW != 0 {
|
||||
artiq_raise!(
|
||||
"RTIOOverflow",
|
||||
format!(
|
||||
"RTIO input overflow on channel 0x{:04x}:{}",
|
||||
channel,
|
||||
resolve_channel_name(channel as u32)
|
||||
),
|
||||
channel as i64,
|
||||
0,
|
||||
0
|
||||
);
|
||||
}
|
||||
if status & RTIO_I_STATUS_DESTINATION_UNREACHABLE != 0 {
|
||||
artiq_raise!(
|
||||
"RTIODestinationUnreachable",
|
||||
format!(
|
||||
"RTIO destination unreachable, input, on channel 0x{:04x}:{}",
|
||||
channel,
|
||||
resolve_channel_name(channel as u32)
|
||||
),
|
||||
channel as i64,
|
||||
0,
|
||||
0
|
||||
);
|
||||
}
|
||||
|
||||
TRANSACTION_BUFFER.reply_data.get()
|
||||
IN_BUFFER.reply_data.get()
|
||||
}
|
||||
}
|
||||
|
||||
pub extern "C" fn input_timestamped_data(timeout: i64, channel: i32) -> TimestampedData {
|
||||
unsafe {
|
||||
TRANSACTION_BUFFER.reply_status.set(0);
|
||||
OUT_BUFFER.transactions[0].request_cmd = RTIO_CMD_INPUT;
|
||||
OUT_BUFFER.transactions[0].request_timestamp = timeout;
|
||||
OUT_BUFFER.transactions[0].request_target = channel << 8;
|
||||
OUT_BUFFER.transactions[0].data_width = 0;
|
||||
|
||||
TRANSACTION_BUFFER.request_cmd = 1;
|
||||
TRANSACTION_BUFFER.request_timestamp = timeout;
|
||||
TRANSACTION_BUFFER.request_target = channel << 8;
|
||||
TRANSACTION_BUFFER.data_width = 0;
|
||||
|
||||
fence(Ordering::SeqCst);
|
||||
asm::sev();
|
||||
|
||||
let mut status;
|
||||
loop {
|
||||
status = TRANSACTION_BUFFER.reply_status.get();
|
||||
if status != 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if status & RTIO_I_STATUS_OVERFLOW != 0 {
|
||||
artiq_raise!(
|
||||
"RTIOOverflow",
|
||||
format!(
|
||||
"RTIO input overflow on channel 0x{:04x}:{}",
|
||||
channel,
|
||||
resolve_channel_name(channel as u32)
|
||||
),
|
||||
channel as i64,
|
||||
0,
|
||||
0
|
||||
);
|
||||
}
|
||||
if status & RTIO_I_STATUS_DESTINATION_UNREACHABLE != 0 {
|
||||
artiq_raise!(
|
||||
"RTIODestinationUnreachable",
|
||||
format!(
|
||||
"RTIO destination unreachable, input, on channel 0x{:04x}:{}",
|
||||
channel,
|
||||
resolve_channel_name(channel as u32)
|
||||
),
|
||||
channel as i64,
|
||||
0,
|
||||
0
|
||||
);
|
||||
}
|
||||
let status = await_reply_status();
|
||||
process_exceptional_input_status(status, channel);
|
||||
|
||||
TimestampedData {
|
||||
timestamp: TRANSACTION_BUFFER.reply_timestamp.get(),
|
||||
data: TRANSACTION_BUFFER.reply_data.get(),
|
||||
timestamp: IN_BUFFER.reply_timestamp.get(),
|
||||
data: IN_BUFFER.reply_data.get(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -355,3 +304,74 @@ pub fn write_log(data: &[i8]) {
|
||||
output((csr::CONFIG_RTIO_LOG_CHANNEL << 8) as i32, word as i32);
|
||||
}
|
||||
}
|
||||
|
||||
pub extern "C" fn batch_start() {
|
||||
unsafe {
|
||||
if OUT_BUFFER.running == BATCH_ENABLED {
|
||||
artiq_raise!("RuntimeError", "Batched mode is already running.");
|
||||
}
|
||||
mmu::remap_section(&__rtio_page as *const _ as u32, &__batch_page as *const _ as u32);
|
||||
OUT_BUFFER.running = BATCH_ENABLED;
|
||||
OUT_BUFFER.ptr = 0;
|
||||
}
|
||||
}
|
||||
|
||||
pub extern "C" fn batch_end() {
|
||||
unsafe {
|
||||
if OUT_BUFFER.ptr == 0 {
|
||||
OUT_BUFFER.running = BATCH_DISABLED;
|
||||
mmu::remap_section(&__rtio_page as *const _ as u32, &__rtio_page as *const _ as u32);
|
||||
return;
|
||||
}
|
||||
// dmb and send event (commit the event to gateware)
|
||||
fence(Ordering::SeqCst);
|
||||
asm::sev();
|
||||
|
||||
// start cleaning up before reading status
|
||||
OUT_BUFFER.running = BATCH_DISABLED;
|
||||
mmu::remap_section(&__rtio_page as *const _ as u32, &__rtio_page as *const _ as u32);
|
||||
let status = loop {
|
||||
let status = IN_BUFFER.reply_status.get();
|
||||
if status != 0 {
|
||||
IN_BUFFER.reply_status.set(0);
|
||||
break status & !(1 << 16);
|
||||
}
|
||||
};
|
||||
if status != 0 {
|
||||
let ptr = IN_BUFFER.reply_batch_cnt.get();
|
||||
let target = OUT_BUFFER.transactions[ptr as usize].request_target >> 8;
|
||||
let timestamp = OUT_BUFFER.transactions[ptr as usize].request_timestamp;
|
||||
process_exceptional_status(target, status, timestamp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[link_section = "batch_output"]
|
||||
pub extern "C" fn batch_output(target: i32, data: i32) {
|
||||
unsafe {
|
||||
if OUT_BUFFER.ptr as usize >= BUFFER_SIZE - 1 {
|
||||
OUT_BUFFER.ptr = 0;
|
||||
artiq_raise!("RuntimeError", "Batch buffer is full");
|
||||
}
|
||||
OUT_BUFFER.transactions[OUT_BUFFER.ptr as usize].data_width = 1;
|
||||
OUT_BUFFER.transactions[OUT_BUFFER.ptr as usize].request_target = target;
|
||||
OUT_BUFFER.transactions[OUT_BUFFER.ptr as usize].request_timestamp = NOW;
|
||||
OUT_BUFFER.transactions[OUT_BUFFER.ptr as usize].request_data[0] = data;
|
||||
OUT_BUFFER.ptr += 1;
|
||||
}
|
||||
}
|
||||
|
||||
#[link_section = "batch_output_wide"]
|
||||
pub extern "C" fn batch_output_wide(target: i32, data: CSlice<i32>) {
|
||||
unsafe {
|
||||
if OUT_BUFFER.ptr as usize >= BUFFER_SIZE - 1 {
|
||||
OUT_BUFFER.ptr = 0;
|
||||
artiq_raise!("RuntimeError", "Batch buffer is full");
|
||||
}
|
||||
OUT_BUFFER.transactions[OUT_BUFFER.ptr as usize].data_width = data.len() as i8;
|
||||
OUT_BUFFER.transactions[OUT_BUFFER.ptr as usize].request_target = target;
|
||||
OUT_BUFFER.transactions[OUT_BUFFER.ptr as usize].request_timestamp = NOW;
|
||||
OUT_BUFFER.transactions[OUT_BUFFER.ptr as usize].request_data[..data.len()].copy_from_slice(data.as_ref());
|
||||
OUT_BUFFER.ptr += 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
use core::ptr::{read_volatile, write_volatile};
|
||||
|
||||
use cslice::CSlice;
|
||||
use libcortex_a9::mmu;
|
||||
|
||||
#[cfg(has_drtio)]
|
||||
use super::{KERNEL_CHANNEL_0TO1, KERNEL_CHANNEL_1TO0, Message};
|
||||
use crate::{artiq_raise, pl::csr, resolve_channel_name, rtio_core};
|
||||
use crate::{artiq_raise, kernel::core1::__rtio_page, pl::csr, rtio_core};
|
||||
|
||||
pub const RTIO_O_STATUS_WAIT: u8 = 1;
|
||||
pub const RTIO_O_STATUS_UNDERFLOW: u8 = 2;
|
||||
@@ -23,6 +24,7 @@ pub struct TimestampedData {
|
||||
pub extern "C" fn init() {
|
||||
unsafe {
|
||||
rtio_core::reset_write(1);
|
||||
mmu::remap_section(&__rtio_page as *const _ as u32, &__rtio_page as *const _ as u32);
|
||||
}
|
||||
#[cfg(has_drtio)]
|
||||
unsafe {
|
||||
@@ -80,11 +82,7 @@ unsafe fn process_exceptional_status(channel: i32, status: u8) {
|
||||
if status & RTIO_O_STATUS_UNDERFLOW != 0 {
|
||||
artiq_raise!(
|
||||
"RTIOUnderflow",
|
||||
format!(
|
||||
"RTIO underflow at {{1}} mu, channel 0x{:04x}:{}, slack {{2}} mu",
|
||||
channel,
|
||||
resolve_channel_name(channel as u32)
|
||||
),
|
||||
"RTIO underflow at {1} mu, channel {rtio_channel_info:0}, slack {2} mu",
|
||||
channel as i64,
|
||||
timestamp,
|
||||
timestamp - get_counter()
|
||||
@@ -93,18 +91,15 @@ unsafe fn process_exceptional_status(channel: i32, status: u8) {
|
||||
if status & RTIO_O_STATUS_DESTINATION_UNREACHABLE != 0 {
|
||||
artiq_raise!(
|
||||
"RTIODestinationUnreachable",
|
||||
format!(
|
||||
"RTIO destination unreachable, output, at {{0}} mu, channel 0x{:04x}:{}",
|
||||
channel,
|
||||
resolve_channel_name(channel as u32)
|
||||
),
|
||||
timestamp,
|
||||
"RTIO destination unreachable, output, at {1} mu, channel {rtio_channel_info:0}",
|
||||
channel as i64,
|
||||
timestamp,
|
||||
0
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[link_section = "rtio_output"]
|
||||
pub extern "C" fn output(target: i32, data: i32) {
|
||||
unsafe {
|
||||
csr::rtio::target_write(target as u32);
|
||||
@@ -117,6 +112,7 @@ pub extern "C" fn output(target: i32, data: i32) {
|
||||
}
|
||||
}
|
||||
|
||||
#[link_section = "rtio_output_wide"]
|
||||
pub extern "C" fn output_wide(target: i32, data: &CSlice<i32>) {
|
||||
unsafe {
|
||||
csr::rtio::target_write(target as u32);
|
||||
@@ -144,11 +140,7 @@ pub extern "C" fn input_timestamp(timeout: i64, channel: i32) -> i64 {
|
||||
if status & RTIO_I_STATUS_OVERFLOW != 0 {
|
||||
artiq_raise!(
|
||||
"RTIOOverflow",
|
||||
format!(
|
||||
"RTIO input overflow on channel 0x{:04x}:{}",
|
||||
channel,
|
||||
resolve_channel_name(channel as u32)
|
||||
),
|
||||
"RTIO input overflow on channel {rtio_channel_info:0}",
|
||||
channel as i64,
|
||||
0,
|
||||
0
|
||||
@@ -160,11 +152,7 @@ pub extern "C" fn input_timestamp(timeout: i64, channel: i32) -> i64 {
|
||||
if status & RTIO_I_STATUS_DESTINATION_UNREACHABLE != 0 {
|
||||
artiq_raise!(
|
||||
"RTIODestinationUnreachable",
|
||||
format!(
|
||||
"RTIO destination unreachable, input, on channel 0x{:04x}:{}",
|
||||
channel,
|
||||
resolve_channel_name(channel as u32)
|
||||
),
|
||||
"RTIO destination unreachable, input, on channel {rtio_channel_info:0}",
|
||||
channel as i64,
|
||||
0,
|
||||
0
|
||||
@@ -188,11 +176,7 @@ pub extern "C" fn input_data(channel: i32) -> i32 {
|
||||
if status & RTIO_I_STATUS_OVERFLOW != 0 {
|
||||
artiq_raise!(
|
||||
"RTIOOverflow",
|
||||
format!(
|
||||
"RTIO input overflow on channel 0x{:04x}:{}",
|
||||
channel,
|
||||
resolve_channel_name(channel as u32)
|
||||
),
|
||||
"RTIO input overflow on channel {rtio_channel_info:0}",
|
||||
channel as i64,
|
||||
0,
|
||||
0
|
||||
@@ -201,11 +185,7 @@ pub extern "C" fn input_data(channel: i32) -> i32 {
|
||||
if status & RTIO_I_STATUS_DESTINATION_UNREACHABLE != 0 {
|
||||
artiq_raise!(
|
||||
"RTIODestinationUnreachable",
|
||||
format!(
|
||||
"RTIO destination unreachable, input, on channel 0x{:04x}:{}",
|
||||
channel,
|
||||
resolve_channel_name(channel as u32)
|
||||
),
|
||||
"RTIO destination unreachable, input, on channel {rtio_channel_info:0}",
|
||||
channel as i64,
|
||||
0,
|
||||
0
|
||||
@@ -229,11 +209,7 @@ pub extern "C" fn input_timestamped_data(timeout: i64, channel: i32) -> Timestam
|
||||
if status & RTIO_I_STATUS_OVERFLOW != 0 {
|
||||
artiq_raise!(
|
||||
"RTIOOverflow",
|
||||
format!(
|
||||
"RTIO input overflow on channel 0x{:04x}:{}",
|
||||
channel,
|
||||
resolve_channel_name(channel as u32)
|
||||
),
|
||||
"RTIO input overflow on channel {rtio_channel_info:0}",
|
||||
channel as i64,
|
||||
0,
|
||||
0
|
||||
@@ -245,11 +221,7 @@ pub extern "C" fn input_timestamped_data(timeout: i64, channel: i32) -> Timestam
|
||||
if status & RTIO_I_STATUS_DESTINATION_UNREACHABLE != 0 {
|
||||
artiq_raise!(
|
||||
"RTIODestinationUnreachable",
|
||||
format!(
|
||||
"RTIO destination unreachable, input, on channel 0x{:04x}:{}",
|
||||
channel,
|
||||
resolve_channel_name(channel as u32)
|
||||
),
|
||||
"RTIO destination unreachable, input, on channel {rtio_channel_info:0}",
|
||||
channel as i64,
|
||||
0,
|
||||
0
|
||||
|
||||
@@ -8,19 +8,10 @@
|
||||
#[macro_use]
|
||||
extern crate alloc;
|
||||
|
||||
use alloc::{collections::BTreeMap, string::String};
|
||||
|
||||
use byteorder::NativeEndian;
|
||||
use io::{Cursor, ProtoRead};
|
||||
use libasync::block_async;
|
||||
use libconfig;
|
||||
use libcortex_a9::once_lock::OnceLock;
|
||||
use log::{error, warn};
|
||||
#[cfg(has_drtiosat)]
|
||||
pub use pl::csr::drtiosat as rtio_core;
|
||||
#[cfg(has_rtio_core)]
|
||||
pub use pl::csr::rtio_core;
|
||||
use void::Void;
|
||||
|
||||
pub mod eh_artiq;
|
||||
pub mod irq;
|
||||
@@ -40,117 +31,3 @@ pub struct RPCException {
|
||||
pub column: i32,
|
||||
pub function: u32,
|
||||
}
|
||||
|
||||
pub static mut SEEN_ASYNC_ERRORS: u8 = 0;
|
||||
|
||||
pub const ASYNC_ERROR_COLLISION: u8 = 1 << 0;
|
||||
pub const ASYNC_ERROR_BUSY: u8 = 1 << 1;
|
||||
pub const ASYNC_ERROR_SEQUENCE_ERROR: u8 = 1 << 2;
|
||||
|
||||
pub unsafe fn get_async_errors() -> u8 {
|
||||
let errors = SEEN_ASYNC_ERRORS;
|
||||
SEEN_ASYNC_ERRORS = 0;
|
||||
errors
|
||||
}
|
||||
|
||||
fn wait_for_async_rtio_error() -> nb::Result<(), Void> {
|
||||
unsafe {
|
||||
#[cfg(has_rtio_core)]
|
||||
let errors = rtio_core::async_error_read();
|
||||
#[cfg(has_drtiosat)]
|
||||
let errors = rtio_core::protocol_error_read();
|
||||
if errors != 0 {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(nb::Error::WouldBlock)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn report_async_rtio_errors() {
|
||||
loop {
|
||||
let _ = block_async!(wait_for_async_rtio_error()).await;
|
||||
unsafe {
|
||||
#[cfg(has_rtio_core)]
|
||||
let errors = rtio_core::async_error_read();
|
||||
#[cfg(has_drtiosat)]
|
||||
let errors = rtio_core::protocol_error_read();
|
||||
if errors & ASYNC_ERROR_COLLISION != 0 {
|
||||
let channel = rtio_core::collision_channel_read();
|
||||
error!(
|
||||
"RTIO collision involving channel 0x{:04x}:{}",
|
||||
channel,
|
||||
resolve_channel_name(channel as u32)
|
||||
);
|
||||
}
|
||||
if errors & ASYNC_ERROR_BUSY != 0 {
|
||||
let channel = rtio_core::busy_channel_read();
|
||||
error!(
|
||||
"RTIO busy error involving channel 0x{:04x}:{}",
|
||||
channel,
|
||||
resolve_channel_name(channel as u32)
|
||||
);
|
||||
}
|
||||
if errors & ASYNC_ERROR_SEQUENCE_ERROR != 0 {
|
||||
let channel = rtio_core::sequence_error_channel_read();
|
||||
error!(
|
||||
"RTIO sequence error involving channel 0x{:04x}:{}",
|
||||
channel,
|
||||
resolve_channel_name(channel as u32)
|
||||
);
|
||||
}
|
||||
SEEN_ASYNC_ERRORS = errors;
|
||||
#[cfg(has_rtio_core)]
|
||||
rtio_core::async_error_write(errors);
|
||||
#[cfg(has_drtiosat)]
|
||||
rtio_core::protocol_error_write(errors);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static RTIO_DEVICE_MAP: OnceLock<BTreeMap<u32, String>> = OnceLock::new();
|
||||
|
||||
fn read_device_map() -> BTreeMap<u32, String> {
|
||||
let mut device_map: BTreeMap<u32, String> = BTreeMap::new();
|
||||
let _ = libconfig::read("device_map")
|
||||
.and_then(|raw_bytes| {
|
||||
let mut bytes_cr = Cursor::new(raw_bytes);
|
||||
let size = bytes_cr.read_u32::<NativeEndian>().unwrap();
|
||||
for _ in 0..size {
|
||||
let channel = bytes_cr.read_u32::<NativeEndian>().unwrap();
|
||||
let device_name = bytes_cr.read_string::<NativeEndian>().unwrap();
|
||||
if let Some(old_entry) = device_map.insert(channel, device_name.clone()) {
|
||||
warn!(
|
||||
"conflicting device map entries for RTIO channel {}: '{}' and '{}'",
|
||||
channel, old_entry, device_name
|
||||
);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
.or_else(|err| {
|
||||
warn!(
|
||||
"error reading device map ({}), device names will not be available in RTIO error messages",
|
||||
err
|
||||
);
|
||||
Err(err)
|
||||
});
|
||||
device_map
|
||||
}
|
||||
|
||||
pub fn resolve_channel_name(channel: u32) -> String {
|
||||
match RTIO_DEVICE_MAP
|
||||
.get()
|
||||
.expect("cannot get device map before it is set up")
|
||||
.get(&channel)
|
||||
{
|
||||
Some(val) => val.clone(),
|
||||
None => String::from("unknown"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn setup_device_map() {
|
||||
RTIO_DEVICE_MAP
|
||||
.set(read_device_map())
|
||||
.expect("device map can only be initialized once");
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ futures = { version = "0.3", default-features = false, features = ["async-await"
|
||||
async-recursion = "1.1"
|
||||
log_buffer = { version = "1.2" }
|
||||
vcell = "0.1"
|
||||
nb = "0.1"
|
||||
|
||||
libboard_zynq = { path = "@@ZYNQ_RS@@/libboard_zynq", features = ["ipv6", "async"]}
|
||||
libsupport_zynq = { path = "@@ZYNQ_RS@@/libsupport_zynq", default-features = false, features = ["alloc_core"] }
|
||||
|
||||
@@ -56,7 +56,6 @@ pub mod remote_analyzer {
|
||||
}
|
||||
|
||||
pub async fn get_data(
|
||||
routing_table: &drtio_routing::RoutingTable,
|
||||
up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>,
|
||||
) -> Result<RemoteBuffer, drtio::Error> {
|
||||
// gets data from satellites and returns consolidated data
|
||||
@@ -65,7 +64,7 @@ pub mod remote_analyzer {
|
||||
let mut remote_sent_bytes = 0;
|
||||
let mut remote_total_bytes = 0;
|
||||
|
||||
let data_vec = match drtio::analyzer_query(routing_table, up_destinations).await {
|
||||
let data_vec = match drtio::analyzer_query(up_destinations).await {
|
||||
Ok(data_vec) => data_vec,
|
||||
Err(e) => return Err(e),
|
||||
};
|
||||
@@ -106,7 +105,6 @@ async fn write_header(stream: &mut TcpStream, header: &Header) -> Result<(), Err
|
||||
|
||||
async fn handle_connection(
|
||||
stream: &mut TcpStream,
|
||||
_routing_table: &drtio_routing::RoutingTable,
|
||||
_up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>,
|
||||
) -> Result<(), Error> {
|
||||
info!("received connection");
|
||||
@@ -131,7 +129,7 @@ async fn handle_connection(
|
||||
}
|
||||
|
||||
#[cfg(has_drtio)]
|
||||
let remote = remote_analyzer::get_data(_routing_table, _up_destinations).await;
|
||||
let remote = remote_analyzer::get_data(_up_destinations).await;
|
||||
#[cfg(has_drtio)]
|
||||
let (header, remote_data) = match remote {
|
||||
Ok(remote) => (
|
||||
@@ -182,19 +180,14 @@ async fn handle_connection(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn start(
|
||||
routing_table: &Rc<RefCell<drtio_routing::RoutingTable>>,
|
||||
up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>,
|
||||
) {
|
||||
let routing_table = routing_table.clone();
|
||||
pub fn start(up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>) {
|
||||
let up_destinations = up_destinations.clone();
|
||||
task::spawn(async move {
|
||||
loop {
|
||||
arm();
|
||||
let mut stream = TcpStream::accept(1382, 2048, 2048).await.unwrap();
|
||||
disarm();
|
||||
let routing_table = routing_table.borrow();
|
||||
let _ = handle_connection(&mut stream, &routing_table, &up_destinations)
|
||||
let _ = handle_connection(&mut stream, &up_destinations)
|
||||
.await
|
||||
.map_err(|e| warn!("connection terminated: {:?}", e));
|
||||
let _ = stream.flush().await;
|
||||
|
||||
@@ -9,17 +9,20 @@ use dyld::elf;
|
||||
use futures::{future::FutureExt, select_biased};
|
||||
#[cfg(has_drtio)]
|
||||
use io::Cursor;
|
||||
use ksupport::kernel;
|
||||
#[cfg(has_drtio)]
|
||||
use ksupport::rpc;
|
||||
use ksupport::{kernel, resolve_channel_name};
|
||||
use libasync::{smoltcp::{Sockets, TcpStream},
|
||||
use libasync::{block_async,
|
||||
smoltcp::{Sockets, TcpStream},
|
||||
task};
|
||||
use libboard_artiq::drtio_routing;
|
||||
#[cfg(has_drtio)]
|
||||
use libboard_artiq::drtioaux::Packet;
|
||||
use libboard_artiq::{drtio_routing::{self, RoutingTable},
|
||||
resolve_channel_name};
|
||||
#[cfg(feature = "target_kasli_soc")]
|
||||
use libboard_zynq::error_led::ErrorLED;
|
||||
use libboard_zynq::{self as zynq,
|
||||
i2c::Error as I2cError,
|
||||
smoltcp::{self,
|
||||
iface::{EthernetInterfaceBuilder, NeighborCache},
|
||||
time::{Duration, Instant},
|
||||
@@ -27,15 +30,21 @@ use libboard_zynq::{self as zynq,
|
||||
timer};
|
||||
use libconfig::{self, net_settings};
|
||||
use libcortex_a9::{mutex::Mutex,
|
||||
once_lock::OnceLock,
|
||||
semaphore::Semaphore,
|
||||
sync_channel::{Receiver, Sender}};
|
||||
use log::{error, info, warn};
|
||||
use num_derive::{FromPrimitive, ToPrimitive};
|
||||
use num_traits::{FromPrimitive, ToPrimitive};
|
||||
#[cfg(has_drtiosat)]
|
||||
use pl::csr::drtiosat as rtio_core;
|
||||
#[cfg(has_rtio_core)]
|
||||
use pl::csr::rtio_core;
|
||||
#[cfg(has_drtio)]
|
||||
use tar_no_std::TarArchiveRef;
|
||||
use void::Void;
|
||||
|
||||
#[cfg(has_drtio)]
|
||||
#[cfg(any(has_rtio_core, has_drtiosat, has_drtio))]
|
||||
use crate::pl;
|
||||
use crate::{analyzer, mgmt, moninj, proto_async::*, rpc_async, rtio_dma, rtio_mgt};
|
||||
#[cfg(has_drtio)]
|
||||
@@ -47,7 +56,6 @@ pub enum Error {
|
||||
IoError,
|
||||
UnexpectedPattern,
|
||||
UnrecognizedPacket,
|
||||
BufferExhausted,
|
||||
#[cfg(has_drtio)]
|
||||
SubkernelError(subkernel::Error),
|
||||
#[cfg(has_drtio)]
|
||||
@@ -63,7 +71,6 @@ impl fmt::Display for Error {
|
||||
Error::IoError => write!(f, "io error"),
|
||||
Error::UnexpectedPattern => write!(f, "unexpected pattern"),
|
||||
Error::UnrecognizedPacket => write!(f, "unrecognized packet"),
|
||||
Error::BufferExhausted => write!(f, "buffer exhausted"),
|
||||
#[cfg(has_drtio)]
|
||||
Error::SubkernelError(error) => write!(f, "subkernel error: {:?}", error),
|
||||
#[cfg(has_drtio)]
|
||||
@@ -114,10 +121,79 @@ enum Reply {
|
||||
ClockFailure = 15,
|
||||
}
|
||||
|
||||
pub static mut SEEN_ASYNC_ERRORS: u8 = 0;
|
||||
|
||||
pub const ASYNC_ERROR_COLLISION: u8 = 1 << 0;
|
||||
pub const ASYNC_ERROR_BUSY: u8 = 1 << 1;
|
||||
pub const ASYNC_ERROR_SEQUENCE_ERROR: u8 = 1 << 2;
|
||||
|
||||
pub unsafe fn get_async_errors() -> u8 {
|
||||
let errors = SEEN_ASYNC_ERRORS;
|
||||
SEEN_ASYNC_ERRORS = 0;
|
||||
errors
|
||||
}
|
||||
|
||||
fn wait_for_async_rtio_error() -> nb::Result<(), Void> {
|
||||
unsafe {
|
||||
#[cfg(has_rtio_core)]
|
||||
let errors = rtio_core::async_error_read();
|
||||
#[cfg(has_drtiosat)]
|
||||
let errors = rtio_core::protocol_error_read();
|
||||
if errors != 0 {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(nb::Error::WouldBlock)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn report_async_rtio_errors() {
|
||||
loop {
|
||||
let _ = block_async!(wait_for_async_rtio_error()).await;
|
||||
unsafe {
|
||||
#[cfg(has_rtio_core)]
|
||||
let errors = rtio_core::async_error_read();
|
||||
#[cfg(has_drtiosat)]
|
||||
let errors = rtio_core::protocol_error_read();
|
||||
if errors & ASYNC_ERROR_COLLISION != 0 {
|
||||
let channel = rtio_core::collision_channel_read();
|
||||
error!(
|
||||
"RTIO collision involving channel 0x{:04x}:{}",
|
||||
channel,
|
||||
resolve_channel_name(channel as u32)
|
||||
);
|
||||
}
|
||||
if errors & ASYNC_ERROR_BUSY != 0 {
|
||||
let channel = rtio_core::busy_channel_read();
|
||||
error!(
|
||||
"RTIO busy error involving channel 0x{:04x}:{}",
|
||||
channel,
|
||||
resolve_channel_name(channel as u32)
|
||||
);
|
||||
}
|
||||
if errors & ASYNC_ERROR_SEQUENCE_ERROR != 0 {
|
||||
let channel = rtio_core::sequence_error_channel_read();
|
||||
error!(
|
||||
"RTIO sequence error involving channel 0x{:04x}:{}",
|
||||
channel,
|
||||
resolve_channel_name(channel as u32)
|
||||
);
|
||||
}
|
||||
SEEN_ASYNC_ERRORS = errors;
|
||||
#[cfg(has_rtio_core)]
|
||||
rtio_core::async_error_write(errors);
|
||||
#[cfg(has_drtiosat)]
|
||||
rtio_core::protocol_error_write(errors);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static CACHE_STORE: Mutex<BTreeMap<String, Vec<i32>>> = Mutex::new(BTreeMap::new());
|
||||
|
||||
pub static RESTART_IDLE: Semaphore = Semaphore::new(1, 1);
|
||||
|
||||
pub static ROUTING_TABLE: OnceLock<RoutingTable> = OnceLock::new();
|
||||
|
||||
async fn write_header(stream: &TcpStream, reply: Reply) -> Result<()> {
|
||||
stream
|
||||
.send_slice(&[0x5a, 0x5a, 0x5a, 0x5a, reply.to_u8().unwrap()])
|
||||
@@ -145,11 +221,8 @@ async fn read_request(stream: &TcpStream, allow_close: bool) -> Result<Option<Re
|
||||
))
|
||||
}
|
||||
|
||||
async fn read_bytes(stream: &TcpStream, max_length: usize) -> Result<Vec<u8>> {
|
||||
async fn read_bytes(stream: &TcpStream) -> Result<Vec<u8>> {
|
||||
let length = read_i32(&stream).await? as usize;
|
||||
if length > max_length {
|
||||
return Err(Error::BufferExhausted);
|
||||
}
|
||||
let mut buffer = vec![0; length];
|
||||
read_chunk(&stream, &mut buffer).await?;
|
||||
Ok(buffer)
|
||||
@@ -194,8 +267,8 @@ async fn handle_run_kernel(
|
||||
stream: Option<&TcpStream>,
|
||||
control: &Rc<RefCell<kernel::Control>>,
|
||||
_up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>,
|
||||
routing_table: &drtio_routing::RoutingTable,
|
||||
) -> Result<()> {
|
||||
let i2c_bus = libboard_artiq::i2c::get_bus();
|
||||
control.borrow_mut().tx.async_send(kernel::Message::StartRequest).await;
|
||||
loop {
|
||||
let reply = control.borrow_mut().rx.async_recv().await;
|
||||
@@ -213,7 +286,7 @@ async fn handle_run_kernel(
|
||||
let host_request = read_request(stream, false).await?.unwrap();
|
||||
match host_request {
|
||||
Request::RPCReply => {
|
||||
let tag = read_bytes(stream, 512).await?;
|
||||
let tag = read_bytes(stream).await?;
|
||||
let slot = match fast_recv(&mut control.borrow_mut().rx).await {
|
||||
kernel::Message::RpcRecvRequest(slot) => slot,
|
||||
other => panic!("expected root value slot from core1, not {:?}", other),
|
||||
@@ -281,14 +354,16 @@ async fn handle_run_kernel(
|
||||
}
|
||||
}
|
||||
}
|
||||
kernel::Message::KernelFinished(async_errors) => {
|
||||
kernel::Message::KernelFinished => {
|
||||
let async_errors = unsafe { get_async_errors() };
|
||||
if let Some(stream) = stream {
|
||||
write_header(stream, Reply::KernelFinished).await?;
|
||||
write_i8(stream, async_errors as i8).await?;
|
||||
}
|
||||
break;
|
||||
}
|
||||
kernel::Message::KernelException(exceptions, stack_pointers, backtrace, async_errors) => {
|
||||
kernel::Message::KernelException(exceptions, stack_pointers, backtrace) => {
|
||||
let async_errors = unsafe { get_async_errors() };
|
||||
match stream {
|
||||
Some(stream) => {
|
||||
// only send the exception data to host if there is host,
|
||||
@@ -357,13 +432,13 @@ async fn handle_run_kernel(
|
||||
.await;
|
||||
}
|
||||
kernel::Message::DmaPutRequest(recorder) => {
|
||||
let _id = rtio_dma::put_record(routing_table, recorder).await;
|
||||
let _id = rtio_dma::put_record(recorder).await;
|
||||
#[cfg(has_drtio)]
|
||||
rtio_dma::remote_dma::upload_traces(routing_table, _id).await;
|
||||
rtio_dma::remote_dma::upload_traces(_id).await;
|
||||
}
|
||||
kernel::Message::DmaEraseRequest(name) => {
|
||||
// prevent possible OOM when we have large DMA record replacement.
|
||||
rtio_dma::erase(name, routing_table).await;
|
||||
rtio_dma::erase(name).await;
|
||||
}
|
||||
kernel::Message::DmaGetRequest(name) => {
|
||||
let result = rtio_dma::retrieve(name).await;
|
||||
@@ -375,7 +450,7 @@ async fn handle_run_kernel(
|
||||
}
|
||||
#[cfg(has_drtio)]
|
||||
kernel::Message::DmaStartRemoteRequest { id, timestamp } => {
|
||||
rtio_dma::remote_dma::playback(routing_table, id as u32, timestamp as u64).await;
|
||||
rtio_dma::remote_dma::playback(id as u32, timestamp as u64).await;
|
||||
}
|
||||
#[cfg(has_drtio)]
|
||||
kernel::Message::DmaAwaitRemoteRequest(id) => {
|
||||
@@ -400,41 +475,110 @@ async fn handle_run_kernel(
|
||||
};
|
||||
control.borrow_mut().tx.async_send(reply).await;
|
||||
}
|
||||
#[cfg(has_drtio)]
|
||||
kernel::Message::I2cStartRequest(busno)
|
||||
| kernel::Message::I2cRestartRequest(busno)
|
||||
| kernel::Message::I2cStopRequest(busno)
|
||||
| kernel::Message::I2cSwitchSelectRequest { busno, .. } => {
|
||||
let result = rtio_mgt::drtio::i2c_send_basic(routing_table, &reply, busno).await;
|
||||
let reply = match result {
|
||||
Ok(succeeded) => kernel::Message::I2cBasicReply(succeeded),
|
||||
Err(_) => kernel::Message::I2cBasicReply(false),
|
||||
};
|
||||
control.borrow_mut().tx.async_send(reply).await;
|
||||
let _destination = (busno >> 16) as u8;
|
||||
#[cfg(has_drtio)]
|
||||
if _destination != 0 {
|
||||
let result = rtio_mgt::drtio::i2c_send_basic(&reply, busno).await;
|
||||
let reply = match result {
|
||||
Ok(succeeded) => kernel::Message::I2cBasicReply(succeeded),
|
||||
Err(_) => kernel::Message::I2cBasicReply(false),
|
||||
};
|
||||
control.borrow_mut().tx.async_send(reply).await;
|
||||
continue;
|
||||
}
|
||||
let mut succeeded = busno == 0;
|
||||
if succeeded {
|
||||
succeeded = match &reply {
|
||||
kernel::Message::I2cStartRequest(_) => i2c_bus.start().is_ok(),
|
||||
kernel::Message::I2cRestartRequest(_) => i2c_bus.restart().is_ok(),
|
||||
kernel::Message::I2cStopRequest(_) => i2c_bus.stop().is_ok(),
|
||||
kernel::Message::I2cSwitchSelectRequest { address, mask, .. } => {
|
||||
let ch = match mask {
|
||||
//decode from mainline, PCA9548-centric API
|
||||
0x00 => Some(None),
|
||||
0x01 => Some(Some(0)),
|
||||
0x02 => Some(Some(1)),
|
||||
0x04 => Some(Some(2)),
|
||||
0x08 => Some(Some(3)),
|
||||
0x10 => Some(Some(4)),
|
||||
0x20 => Some(Some(5)),
|
||||
0x40 => Some(Some(6)),
|
||||
0x80 => Some(Some(7)),
|
||||
_ => None,
|
||||
};
|
||||
ch.is_some_and(|c| i2c_bus.pca954x_select(*address as u8, c).is_ok())
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
control
|
||||
.borrow_mut()
|
||||
.tx
|
||||
.async_send(kernel::Message::I2cBasicReply(succeeded))
|
||||
.await;
|
||||
}
|
||||
#[cfg(has_drtio)]
|
||||
kernel::Message::I2cWriteRequest { busno, data } => {
|
||||
let result = rtio_mgt::drtio::i2c_send_write(routing_table, busno, data).await;
|
||||
let reply = match result {
|
||||
Ok((succeeded, ack)) => kernel::Message::I2cWriteReply { succeeded, ack },
|
||||
Err(_) => kernel::Message::I2cWriteReply {
|
||||
succeeded: false,
|
||||
ack: false,
|
||||
},
|
||||
};
|
||||
control.borrow_mut().tx.async_send(reply).await;
|
||||
let _destination = (busno >> 16) as u8;
|
||||
#[cfg(has_drtio)]
|
||||
if _destination != 0 {
|
||||
let result = rtio_mgt::drtio::i2c_send_write(busno, data).await;
|
||||
let reply = match result {
|
||||
Ok((succeeded, ack)) => kernel::Message::I2cWriteReply { succeeded, ack },
|
||||
Err(_) => kernel::Message::I2cWriteReply {
|
||||
succeeded: false,
|
||||
ack: false,
|
||||
},
|
||||
};
|
||||
control.borrow_mut().tx.async_send(reply).await;
|
||||
continue;
|
||||
}
|
||||
let mut succeeded = busno == 0;
|
||||
let mut ack = false;
|
||||
if succeeded {
|
||||
(succeeded, ack) = match i2c_bus.write(data as u8) {
|
||||
Ok(()) => (true, true),
|
||||
Err(I2cError::Nack) => (true, false),
|
||||
Err(_) => (false, false),
|
||||
}
|
||||
}
|
||||
control
|
||||
.borrow_mut()
|
||||
.tx
|
||||
.async_send(kernel::Message::I2cWriteReply { succeeded, ack })
|
||||
.await;
|
||||
}
|
||||
#[cfg(has_drtio)]
|
||||
kernel::Message::I2cReadRequest { busno, ack } => {
|
||||
let result = rtio_mgt::drtio::i2c_send_read(routing_table, busno, ack).await;
|
||||
let reply = match result {
|
||||
Ok((succeeded, data)) => kernel::Message::I2cReadReply { succeeded, data },
|
||||
Err(_) => kernel::Message::I2cReadReply {
|
||||
succeeded: false,
|
||||
data: 0xFF,
|
||||
},
|
||||
};
|
||||
control.borrow_mut().tx.async_send(reply).await;
|
||||
let _destination = (busno >> 16) as u8;
|
||||
#[cfg(has_drtio)]
|
||||
if _destination != 0 {
|
||||
let result = rtio_mgt::drtio::i2c_send_read(busno, ack).await;
|
||||
let reply = match result {
|
||||
Ok((succeeded, data)) => kernel::Message::I2cReadReply { succeeded, data },
|
||||
Err(_) => kernel::Message::I2cReadReply {
|
||||
succeeded: false,
|
||||
data: 0xFF,
|
||||
},
|
||||
};
|
||||
control.borrow_mut().tx.async_send(reply).await;
|
||||
continue;
|
||||
}
|
||||
let mut succeeded = busno == 0;
|
||||
let mut data = 0xFF;
|
||||
if succeeded {
|
||||
(succeeded, data) = match i2c_bus.read(ack) {
|
||||
Ok(r) => (true, r),
|
||||
Err(_) => (false, 0xFF),
|
||||
}
|
||||
}
|
||||
control
|
||||
.borrow_mut()
|
||||
.tx
|
||||
.async_send(kernel::Message::I2cReadReply { succeeded, data })
|
||||
.await;
|
||||
}
|
||||
#[cfg(has_drtio)]
|
||||
kernel::Message::SubkernelLoadRunRequest {
|
||||
@@ -443,7 +587,7 @@ async fn handle_run_kernel(
|
||||
run,
|
||||
timestamp,
|
||||
} => {
|
||||
let succeeded = match subkernel::load(routing_table, id, run, timestamp).await {
|
||||
let succeeded = match subkernel::load(id, run, timestamp).await {
|
||||
Ok(()) => true,
|
||||
Err(e) => {
|
||||
error!("Error loading subkernel: {:?}", e);
|
||||
@@ -458,7 +602,7 @@ async fn handle_run_kernel(
|
||||
}
|
||||
#[cfg(has_drtio)]
|
||||
kernel::Message::SubkernelAwaitFinishRequest { id, timeout } => {
|
||||
let res = subkernel::await_finish(routing_table, id, timeout).await;
|
||||
let res = subkernel::await_finish(id, timeout).await;
|
||||
let response = match res {
|
||||
Ok(res) => {
|
||||
if res.status == subkernel::FinishStatus::CommLost {
|
||||
@@ -479,7 +623,7 @@ async fn handle_run_kernel(
|
||||
}
|
||||
#[cfg(has_drtio)]
|
||||
kernel::Message::SubkernelMsgSend { id, destination, data } => {
|
||||
let res = subkernel::message_send(routing_table, id, destination.unwrap(), data).await;
|
||||
let res = subkernel::message_send(id, destination.unwrap(), data).await;
|
||||
match res {
|
||||
Ok(_) => (),
|
||||
Err(e) => {
|
||||
@@ -504,9 +648,7 @@ async fn handle_run_kernel(
|
||||
Err(SubkernelError::CommLost) => kernel::Message::SubkernelError(kernel::SubkernelStatus::CommLost),
|
||||
Err(SubkernelError::SubkernelException) => {
|
||||
// just retrieve the exception
|
||||
let status = subkernel::await_finish(routing_table, id as u32, timeout)
|
||||
.await
|
||||
.unwrap();
|
||||
let status = subkernel::await_finish(id as u32, timeout).await.unwrap();
|
||||
kernel::Message::SubkernelError(kernel::SubkernelStatus::Exception(status.exception.unwrap()))
|
||||
}
|
||||
Err(_) => kernel::Message::SubkernelError(kernel::SubkernelStatus::OtherError),
|
||||
@@ -562,7 +704,7 @@ async fn handle_run_kernel(
|
||||
}
|
||||
#[cfg(has_drtio)]
|
||||
kernel::Message::RtioInitRequest => {
|
||||
rtio_mgt::drtio::reset(routing_table).await;
|
||||
rtio_mgt::drtio::reset().await;
|
||||
control.borrow_mut().tx.async_send(kernel::Message::RtioInitReply).await;
|
||||
}
|
||||
#[cfg(has_drtio)]
|
||||
@@ -571,11 +713,10 @@ async fn handle_run_kernel(
|
||||
address,
|
||||
length,
|
||||
} => {
|
||||
let linkno = routing_table.0[destination as usize][0] - 1;
|
||||
let linkno = ROUTING_TABLE.get().unwrap().0[destination as usize][0] - 1;
|
||||
let reply = loop {
|
||||
let result = rtio_mgt::drtio::aux_transact(
|
||||
linkno,
|
||||
routing_table,
|
||||
&Packet::CXPReadRequest {
|
||||
destination,
|
||||
address,
|
||||
@@ -612,11 +753,10 @@ async fn handle_run_kernel(
|
||||
address,
|
||||
value,
|
||||
} => {
|
||||
let linkno = routing_table.0[destination as usize][0] - 1;
|
||||
let linkno = ROUTING_TABLE.get().unwrap().0[destination as usize][0] - 1;
|
||||
let reply = loop {
|
||||
let drtioaux_packet = rtio_mgt::drtio::aux_transact(
|
||||
linkno,
|
||||
routing_table,
|
||||
&Packet::CXPWrite32Request {
|
||||
destination,
|
||||
address,
|
||||
@@ -653,10 +793,9 @@ async fn handle_run_kernel(
|
||||
x1,
|
||||
y1,
|
||||
} => {
|
||||
let linkno = routing_table.0[destination as usize][0] - 1;
|
||||
let linkno = ROUTING_TABLE.get().unwrap().0[destination as usize][0] - 1;
|
||||
let drtioaux_packet = rtio_mgt::drtio::aux_transact(
|
||||
linkno,
|
||||
routing_table,
|
||||
&Packet::CXPROIViewerSetupRequest {
|
||||
destination,
|
||||
x0,
|
||||
@@ -682,14 +821,10 @@ async fn handle_run_kernel(
|
||||
}
|
||||
#[cfg(has_drtio)]
|
||||
kernel::Message::CXPROIViewerDataRequest { destination } => {
|
||||
let linkno = routing_table.0[destination as usize][0] - 1;
|
||||
let linkno = ROUTING_TABLE.get().unwrap().0[destination as usize][0] - 1;
|
||||
let reply = loop {
|
||||
let drtioaux_packet = rtio_mgt::drtio::aux_transact(
|
||||
linkno,
|
||||
routing_table,
|
||||
&Packet::CXPROIViewerDataRequest { destination },
|
||||
)
|
||||
.await;
|
||||
let drtioaux_packet =
|
||||
rtio_mgt::drtio::aux_transact(linkno, &Packet::CXPROIViewerDataRequest { destination }).await;
|
||||
|
||||
match drtioaux_packet {
|
||||
Ok(Packet::CXPWaitReply) => {}
|
||||
@@ -731,7 +866,6 @@ async fn handle_flash_kernel(
|
||||
buffer: &Vec<u8>,
|
||||
control: &Rc<RefCell<kernel::Control>>,
|
||||
_up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>,
|
||||
_routing_table: &drtio_routing::RoutingTable,
|
||||
) -> Result<()> {
|
||||
if buffer[0] == elf::ELFMAG0 && buffer[1] == elf::ELFMAG1 && buffer[2] == elf::ELFMAG2 && buffer[3] == elf::ELFMAG3
|
||||
{
|
||||
@@ -757,7 +891,7 @@ async fn handle_flash_kernel(
|
||||
if up {
|
||||
let subkernel_lib = entry.data().to_vec();
|
||||
subkernel::add_subkernel(sid, dest, subkernel_lib).await;
|
||||
match subkernel::upload(_routing_table, sid).await {
|
||||
match subkernel::upload(sid).await {
|
||||
Ok(_) => (),
|
||||
Err(_) => return Err(Error::UnexpectedPattern),
|
||||
}
|
||||
@@ -818,7 +952,6 @@ async fn handle_connection(
|
||||
stream: &mut TcpStream,
|
||||
control: Rc<RefCell<kernel::Control>>,
|
||||
up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>,
|
||||
routing_table: &drtio_routing::RoutingTable,
|
||||
) -> Result<()> {
|
||||
stream.set_ack_delay(None);
|
||||
|
||||
@@ -842,20 +975,20 @@ async fn handle_connection(
|
||||
stream.send_slice("ARZQ".as_bytes()).await?;
|
||||
}
|
||||
Request::LoadKernel => {
|
||||
let buffer = read_bytes(stream, 1024 * 1024).await?;
|
||||
let buffer = read_bytes(stream).await?;
|
||||
load_kernel(&buffer, &control, Some(stream)).await?;
|
||||
}
|
||||
Request::RunKernel => {
|
||||
handle_run_kernel(Some(stream), &control, &up_destinations, routing_table).await?;
|
||||
handle_run_kernel(Some(stream), &control, &up_destinations).await?;
|
||||
}
|
||||
Request::UploadSubkernel => {
|
||||
#[cfg(has_drtio)]
|
||||
{
|
||||
let id = read_i32(stream).await? as u32;
|
||||
let destination = read_i8(stream).await? as u8;
|
||||
let buffer = read_bytes(stream, 1024 * 1024).await?;
|
||||
let buffer = read_bytes(stream).await?;
|
||||
subkernel::add_subkernel(id, destination, buffer).await;
|
||||
match subkernel::upload(routing_table, id).await {
|
||||
match subkernel::upload(id).await {
|
||||
Ok(_) => write_header(stream, Reply::LoadCompleted).await?,
|
||||
Err(_) => {
|
||||
write_header(stream, Reply::LoadFailed).await?;
|
||||
@@ -921,33 +1054,35 @@ pub fn main() {
|
||||
Sockets::init(32);
|
||||
|
||||
#[cfg(has_drtio)]
|
||||
let drtio_routing_table = Rc::new(RefCell::new(drtio_routing::config_routing_table(pl::csr::DRTIO.len())));
|
||||
let res = ROUTING_TABLE.set(drtio_routing::config_routing_table(pl::csr::DRTIO.len()));
|
||||
#[cfg(not(has_drtio))]
|
||||
let drtio_routing_table = Rc::new(RefCell::new(drtio_routing::RoutingTable::default_empty()));
|
||||
let res = ROUTING_TABLE.set(drtio_routing::RoutingTable::default_empty());
|
||||
res.expect("routing_table can only be initialized once");
|
||||
|
||||
let up_destinations = Rc::new(RefCell::new([false; drtio_routing::DEST_COUNT]));
|
||||
#[cfg(has_drtio_routing)]
|
||||
drtio_routing::interconnect_disable_all();
|
||||
|
||||
rtio_mgt::startup(&drtio_routing_table, &up_destinations);
|
||||
ksupport::setup_device_map();
|
||||
task::spawn(report_async_rtio_errors());
|
||||
rtio_mgt::startup(&up_destinations);
|
||||
libboard_artiq::setup_device_map();
|
||||
|
||||
analyzer::start(&drtio_routing_table, &up_destinations);
|
||||
moninj::start(&drtio_routing_table);
|
||||
analyzer::start(&up_destinations);
|
||||
moninj::start();
|
||||
|
||||
let control: Rc<RefCell<kernel::Control>> = Rc::new(RefCell::new(kernel::Control::start()));
|
||||
if let Ok(buffer) = libconfig::read("startup_kernel") {
|
||||
info!("Loading startup kernel...");
|
||||
let routing_table = drtio_routing_table.borrow();
|
||||
if let Ok(()) = task::block_on(handle_flash_kernel(&buffer, &control, &up_destinations, &routing_table)) {
|
||||
if let Ok(()) = task::block_on(handle_flash_kernel(&buffer, &control, &up_destinations)) {
|
||||
info!("Starting startup kernel...");
|
||||
let _ = task::block_on(handle_run_kernel(None, &control, &up_destinations, &routing_table));
|
||||
let _ = task::block_on(handle_run_kernel(None, &control, &up_destinations));
|
||||
info!("Startup kernel finished!");
|
||||
} else {
|
||||
error!("Error loading startup kernel!");
|
||||
}
|
||||
}
|
||||
|
||||
mgmt::start(Some(drtio_routing_table.clone()));
|
||||
mgmt::start();
|
||||
|
||||
task::spawn(async move {
|
||||
let connection = Rc::new(Semaphore::new(1, 1));
|
||||
@@ -981,17 +1116,15 @@ pub fn main() {
|
||||
let terminate = terminate.clone();
|
||||
let can_restart_idle = can_restart_idle.clone();
|
||||
let up_destinations = up_destinations.clone();
|
||||
let routing_table = drtio_routing_table.clone();
|
||||
|
||||
// we make sure the value of terminate is 0 before we start
|
||||
let _ = terminate.try_wait();
|
||||
let _ = can_restart_idle.try_wait();
|
||||
task::spawn(async move {
|
||||
let routing_table = routing_table.borrow();
|
||||
select_biased! {
|
||||
_ = (async {
|
||||
if let Some(stream) = &mut maybe_stream {
|
||||
let _ = handle_connection(stream, control.clone(), &up_destinations, &routing_table)
|
||||
let _ = handle_connection(stream, control.clone(), &up_destinations)
|
||||
.await
|
||||
.map_err(|e| warn!("connection terminated: {}", e));
|
||||
}
|
||||
@@ -1000,10 +1133,10 @@ pub fn main() {
|
||||
Some(buffer) => {
|
||||
loop {
|
||||
info!("loading idle kernel");
|
||||
match handle_flash_kernel(&buffer, &control, &up_destinations, &routing_table).await {
|
||||
match handle_flash_kernel(&buffer, &control, &up_destinations).await {
|
||||
Ok(_) => {
|
||||
info!("running idle kernel");
|
||||
match handle_run_kernel(None, &control, &up_destinations, &routing_table).await {
|
||||
match handle_run_kernel(None, &control, &up_destinations).await {
|
||||
Ok(_) => info!("idle kernel finished"),
|
||||
Err(_) => warn!("idle kernel running error")
|
||||
}
|
||||
@@ -1086,7 +1219,7 @@ pub fn soft_panic_main() -> ! {
|
||||
|
||||
Sockets::init(32);
|
||||
|
||||
mgmt::start(None);
|
||||
mgmt::start();
|
||||
|
||||
// getting eth settings disables the LED as it resets GPIO
|
||||
// need to re-enable it here
|
||||
|
||||
@@ -20,12 +20,12 @@ use libboard_artiq::drtio_eem;
|
||||
use libboard_artiq::io_expander;
|
||||
#[cfg(has_cxp_grabber)]
|
||||
use libboard_artiq::{cxp_grabber, cxp_phys};
|
||||
use libboard_artiq::{identifier_read, logger, pl};
|
||||
use libboard_artiq::{i2c, identifier_read, logger, pl};
|
||||
use libboard_zynq::{gic, mpcore, timer};
|
||||
use libconfig;
|
||||
use libcortex_a9::l2c::enable_l2_cache;
|
||||
use libsupport_zynq::{exception_vectors, ram};
|
||||
use log::{info, warn};
|
||||
use log::{LevelFilter, info, warn};
|
||||
|
||||
mod analyzer;
|
||||
mod comms;
|
||||
@@ -78,6 +78,29 @@ mod grabber {
|
||||
}
|
||||
}
|
||||
|
||||
fn setup_log_levels() {
|
||||
if let Ok(level_string) = libconfig::read_str("log_level") {
|
||||
if let Ok(level) = level_string.parse::<LevelFilter>() {
|
||||
info!("log level set to {} by `log_level` config key", level);
|
||||
logger::BufferLogger::get_logger().set_buffer_log_level(level);
|
||||
} else {
|
||||
info!("log level set to INFO by default");
|
||||
}
|
||||
} else {
|
||||
info!("log level set to INFO by default");
|
||||
}
|
||||
if let Ok(level_string) = libconfig::read_str("uart_log_level") {
|
||||
if let Ok(level) = level_string.parse::<LevelFilter>() {
|
||||
info!("UART log level set to {} by `uart_log_level` config key", level);
|
||||
logger::BufferLogger::get_logger().set_uart_log_level(level);
|
||||
} else {
|
||||
info!("UART log level set to INFO by default");
|
||||
}
|
||||
} else {
|
||||
info!("UART log level set to INFO by default");
|
||||
}
|
||||
}
|
||||
|
||||
static mut LOG_BUFFER: [u8; 1 << 17] = [0; 1 << 17];
|
||||
|
||||
#[no_mangle]
|
||||
@@ -88,10 +111,9 @@ pub fn main_core0() {
|
||||
enable_l2_cache(0x8);
|
||||
timer::start();
|
||||
|
||||
let buffer_logger = unsafe { logger::BufferLogger::new(&mut LOG_BUFFER[..]) };
|
||||
buffer_logger.set_uart_log_level(log::LevelFilter::Info);
|
||||
let buffer_logger = unsafe { libboard_artiq::logger::BufferLogger::new(&mut LOG_BUFFER[..]) };
|
||||
buffer_logger.register();
|
||||
log::set_max_level(log::LevelFilter::Info);
|
||||
log::set_max_level(log::LevelFilter::Trace);
|
||||
|
||||
info!("NAR3/Zynq7000 starting...");
|
||||
|
||||
@@ -100,10 +122,10 @@ pub fn main_core0() {
|
||||
|
||||
info!("gateware ident: {}", identifier_read(&mut [0; 64]));
|
||||
|
||||
ksupport::kernel::i2c::init();
|
||||
i2c::init();
|
||||
#[cfg(feature = "target_kasli_soc")]
|
||||
{
|
||||
let i2c_bus = ksupport::kernel::i2c::get_bus();
|
||||
let i2c_bus = i2c::get_bus();
|
||||
let mut io_expander0 = io_expander::IoExpander::new(i2c_bus, 0).unwrap();
|
||||
let mut io_expander1 = io_expander::IoExpander::new(i2c_bus, 1).unwrap();
|
||||
io_expander0
|
||||
@@ -122,8 +144,14 @@ pub fn main_core0() {
|
||||
io_expander1.set(0, 1, false);
|
||||
io_expander0.set(1, 1, false);
|
||||
io_expander1.set(1, 1, false);
|
||||
|
||||
// Enable EEM power
|
||||
#[cfg(hw_rev = "v1.2")]
|
||||
io_expander1.set(0, 7, true);
|
||||
|
||||
io_expander0.service(i2c_bus).unwrap();
|
||||
io_expander1.service(i2c_bus).unwrap();
|
||||
|
||||
#[cfg(has_virtual_leds)]
|
||||
task::spawn(io_expanders_service(
|
||||
RefCell::new(i2c_bus),
|
||||
@@ -135,6 +163,9 @@ pub fn main_core0() {
|
||||
if let Err(err) = libconfig::init() {
|
||||
warn!("config initialization failed: {}", err);
|
||||
}
|
||||
|
||||
setup_log_levels();
|
||||
|
||||
rtio_clocking::init();
|
||||
|
||||
#[cfg(has_drtio_eem)]
|
||||
@@ -143,12 +174,10 @@ pub fn main_core0() {
|
||||
#[cfg(has_grabber)]
|
||||
task::spawn(grabber::grabber_thread());
|
||||
|
||||
task::spawn(ksupport::report_async_rtio_errors());
|
||||
|
||||
#[cfg(has_cxp_grabber)]
|
||||
{
|
||||
cxp_phys::setup();
|
||||
task::spawn(cxp_grabber::thread(ksupport::kernel::i2c::get_bus()));
|
||||
task::spawn(cxp_grabber::thread(i2c::get_bus()));
|
||||
}
|
||||
|
||||
comms::main();
|
||||
|
||||
@@ -1,26 +1,29 @@
|
||||
use alloc::{rc::Rc, string::String, vec::Vec};
|
||||
use core::cell::RefCell;
|
||||
use core::{cell::RefCell, str::Utf8Error};
|
||||
|
||||
use byteorder::{ByteOrder, NativeEndian};
|
||||
use crc::crc32;
|
||||
use futures::{future::poll_fn, task::Poll};
|
||||
use libasync::{smoltcp::TcpStream, task};
|
||||
use libboard_artiq::{drtio_routing::RoutingTable,
|
||||
logger::{BufferLogger, LogBufferRef}};
|
||||
#[cfg(has_drtio)]
|
||||
use libboard_artiq::drtio_routing;
|
||||
use libboard_artiq::logger::{BufferLogger, LogBufferRef};
|
||||
use libboard_zynq::smoltcp;
|
||||
use libconfig;
|
||||
use log::{self, debug, error, info, warn};
|
||||
use num_derive::FromPrimitive;
|
||||
use num_traits::FromPrimitive;
|
||||
|
||||
#[cfg(has_drtio)]
|
||||
use crate::rtio_mgt::drtio;
|
||||
use crate::{comms::RESTART_IDLE, proto_async::*};
|
||||
#[cfg(has_drtio)]
|
||||
use crate::{comms::ROUTING_TABLE, rtio_mgt::drtio};
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum Error {
|
||||
NetworkError(smoltcp::Error),
|
||||
UnknownLogLevel(u8),
|
||||
OvertakeError,
|
||||
UnknownLogLevel(),
|
||||
Utf8(Utf8Error),
|
||||
UnexpectedPattern,
|
||||
UnrecognizedPacket,
|
||||
#[cfg(has_drtio)]
|
||||
@@ -33,7 +36,9 @@ impl core::fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
|
||||
match self {
|
||||
&Error::NetworkError(error) => write!(f, "network error: {}", error),
|
||||
&Error::UnknownLogLevel(lvl) => write!(f, "unknown log level {}", lvl),
|
||||
&Error::OvertakeError => write!(f, "connection overtaken"),
|
||||
&Error::UnknownLogLevel() => write!(f, "unknown log level"),
|
||||
&Error::Utf8(error) => write!(f, "invalid UTF-8: {}", error),
|
||||
&Error::UnexpectedPattern => write!(f, "unexpected pattern"),
|
||||
&Error::UnrecognizedPacket => write!(f, "unrecognized packet"),
|
||||
#[cfg(has_drtio)]
|
||||
@@ -48,6 +53,12 @@ impl From<smoltcp::Error> for Error {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Utf8Error> for Error {
|
||||
fn from(error: Utf8Error) -> Self {
|
||||
Error::Utf8(error)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(has_drtio)]
|
||||
impl From<drtio::Error> for Error {
|
||||
fn from(error: drtio::Error) -> Self {
|
||||
@@ -60,9 +71,7 @@ pub enum Request {
|
||||
GetLog = 1,
|
||||
ClearLog = 2,
|
||||
PullLog = 7,
|
||||
SetLogFilter = 3,
|
||||
Reboot = 5,
|
||||
SetUartLogFilter = 6,
|
||||
|
||||
ConfigRead = 12,
|
||||
ConfigWrite = 13,
|
||||
@@ -83,18 +92,6 @@ pub enum Reply {
|
||||
ConfigData = 7,
|
||||
}
|
||||
|
||||
async fn read_log_level_filter(stream: &mut TcpStream) -> Result<log::LevelFilter> {
|
||||
Ok(match read_i8(stream).await? {
|
||||
0 => log::LevelFilter::Off,
|
||||
1 => log::LevelFilter::Error,
|
||||
2 => log::LevelFilter::Warn,
|
||||
3 => log::LevelFilter::Info,
|
||||
4 => log::LevelFilter::Debug,
|
||||
5 => log::LevelFilter::Trace,
|
||||
lv => return Err(Error::UnknownLogLevel(lv as u8)),
|
||||
})
|
||||
}
|
||||
|
||||
async fn get_logger_buffer_pred<F>(f: F) -> LogBufferRef<'static>
|
||||
where F: Fn(&LogBufferRef) -> bool {
|
||||
poll_fn(|ctx| {
|
||||
@@ -141,17 +138,11 @@ mod remote_coremgmt {
|
||||
|
||||
use super::*;
|
||||
|
||||
pub async fn get_log(
|
||||
stream: &mut TcpStream,
|
||||
routing_table: &RoutingTable,
|
||||
linkno: u8,
|
||||
destination: u8,
|
||||
) -> Result<()> {
|
||||
pub async fn get_log(stream: &mut TcpStream, linkno: u8, destination: u8) -> Result<()> {
|
||||
let mut buffer = Vec::new();
|
||||
loop {
|
||||
let reply = drtio::aux_transact(
|
||||
linkno,
|
||||
routing_table,
|
||||
&Packet::CoreMgmtGetLogRequest {
|
||||
destination,
|
||||
clear: false,
|
||||
@@ -182,13 +173,8 @@ mod remote_coremgmt {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn clear_log(
|
||||
stream: &mut TcpStream,
|
||||
routing_table: &RoutingTable,
|
||||
linkno: u8,
|
||||
destination: u8,
|
||||
) -> Result<()> {
|
||||
let reply = drtio::aux_transact(linkno, routing_table, &Packet::CoreMgmtClearLogRequest { destination }).await;
|
||||
pub async fn clear_log(stream: &mut TcpStream, linkno: u8, destination: u8) -> Result<()> {
|
||||
let reply = drtio::aux_transact(linkno, &Packet::CoreMgmtClearLogRequest { destination }).await;
|
||||
|
||||
match reply {
|
||||
Ok(Packet::CoreMgmtReply { succeeded: true }) => {
|
||||
@@ -208,13 +194,7 @@ mod remote_coremgmt {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn pull_log(
|
||||
stream: &mut TcpStream,
|
||||
routing_table: &RoutingTable,
|
||||
linkno: u8,
|
||||
destination: u8,
|
||||
pull_id: &Rc<RefCell<u32>>,
|
||||
) -> Result<()> {
|
||||
pub async fn pull_log(stream: &mut TcpStream, linkno: u8, destination: u8, pull_id: &RefCell<u32>) -> Result<()> {
|
||||
let id = {
|
||||
let mut guard = pull_id.borrow_mut();
|
||||
*guard += 1;
|
||||
@@ -226,12 +206,11 @@ mod remote_coremgmt {
|
||||
if id != *pull_id.borrow() {
|
||||
// another connection attempts to pull the log...
|
||||
// abort this connection...
|
||||
break;
|
||||
return Err(Error::OvertakeError);
|
||||
}
|
||||
|
||||
let reply = drtio::aux_transact(
|
||||
linkno,
|
||||
routing_table,
|
||||
&Packet::CoreMgmtGetLogRequest {
|
||||
destination,
|
||||
clear: true,
|
||||
@@ -258,94 +237,15 @@ mod remote_coremgmt {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn set_log_filter(
|
||||
stream: &mut TcpStream,
|
||||
routing_table: &RoutingTable,
|
||||
linkno: u8,
|
||||
destination: u8,
|
||||
level: log::LevelFilter,
|
||||
) -> Result<()> {
|
||||
let reply = drtio::aux_transact(
|
||||
linkno,
|
||||
routing_table,
|
||||
&Packet::CoreMgmtSetLogLevelRequest {
|
||||
destination,
|
||||
log_level: level as u8,
|
||||
},
|
||||
)
|
||||
.await;
|
||||
|
||||
match reply {
|
||||
Ok(Packet::CoreMgmtReply { succeeded: true }) => {
|
||||
write_i8(stream, Reply::Success as i8).await?;
|
||||
Ok(())
|
||||
}
|
||||
Ok(packet) => {
|
||||
error!("received unexpected aux packet: {:?}", packet);
|
||||
write_i8(stream, Reply::Error as i8).await?;
|
||||
Err(drtio::Error::UnexpectedReply.into())
|
||||
}
|
||||
Err(e) => {
|
||||
error!("aux packet error ({})", e);
|
||||
write_i8(stream, Reply::Error as i8).await?;
|
||||
Err(e.into())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn set_uart_log_filter(
|
||||
stream: &mut TcpStream,
|
||||
routing_table: &RoutingTable,
|
||||
linkno: u8,
|
||||
destination: u8,
|
||||
level: log::LevelFilter,
|
||||
) -> Result<()> {
|
||||
let reply = drtio::aux_transact(
|
||||
linkno,
|
||||
routing_table,
|
||||
&Packet::CoreMgmtSetUartLogLevelRequest {
|
||||
destination,
|
||||
log_level: level as u8,
|
||||
},
|
||||
)
|
||||
.await;
|
||||
|
||||
match reply {
|
||||
Ok(Packet::CoreMgmtReply { succeeded: true }) => {
|
||||
write_i8(stream, Reply::Success as i8).await?;
|
||||
Ok(())
|
||||
}
|
||||
Ok(packet) => {
|
||||
error!("received unexpected aux packet: {:?}", packet);
|
||||
write_i8(stream, Reply::Error as i8).await?;
|
||||
Err(drtio::Error::UnexpectedReply.into())
|
||||
}
|
||||
Err(e) => {
|
||||
error!("aux packet error ({})", e);
|
||||
write_i8(stream, Reply::Error as i8).await?;
|
||||
Err(e.into())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn config_read(
|
||||
stream: &mut TcpStream,
|
||||
routing_table: &RoutingTable,
|
||||
linkno: u8,
|
||||
destination: u8,
|
||||
key: &String,
|
||||
) -> Result<()> {
|
||||
pub async fn config_read(stream: &mut TcpStream, linkno: u8, destination: u8, key: &String) -> Result<()> {
|
||||
let mut config_key: [u8; MASTER_PAYLOAD_MAX_SIZE] = [0; MASTER_PAYLOAD_MAX_SIZE];
|
||||
let len = key.len();
|
||||
config_key[..len].clone_from_slice(key.as_bytes());
|
||||
|
||||
let mut reply = drtio::aux_transact(
|
||||
linkno,
|
||||
routing_table,
|
||||
&Packet::CoreMgmtConfigReadRequest {
|
||||
destination: destination,
|
||||
length: len as u16,
|
||||
@@ -368,7 +268,6 @@ mod remote_coremgmt {
|
||||
|
||||
reply = drtio::aux_transact(
|
||||
linkno,
|
||||
routing_table,
|
||||
&Packet::CoreMgmtConfigReadContinue {
|
||||
destination: destination,
|
||||
},
|
||||
@@ -391,7 +290,6 @@ mod remote_coremgmt {
|
||||
|
||||
pub async fn config_write(
|
||||
stream: &mut TcpStream,
|
||||
routing_table: &RoutingTable,
|
||||
linkno: u8,
|
||||
destination: u8,
|
||||
key: &String,
|
||||
@@ -403,7 +301,6 @@ mod remote_coremgmt {
|
||||
|
||||
match drtio::partition_data(
|
||||
linkno,
|
||||
routing_table,
|
||||
&message,
|
||||
|slice, status, len: usize| Packet::CoreMgmtConfigWriteRequest {
|
||||
destination: destination,
|
||||
@@ -433,20 +330,13 @@ mod remote_coremgmt {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn config_remove(
|
||||
stream: &mut TcpStream,
|
||||
routing_table: &RoutingTable,
|
||||
linkno: u8,
|
||||
destination: u8,
|
||||
key: &String,
|
||||
) -> Result<()> {
|
||||
pub async fn config_remove(stream: &mut TcpStream, linkno: u8, destination: u8, key: &String) -> Result<()> {
|
||||
let mut config_key: [u8; MASTER_PAYLOAD_MAX_SIZE] = [0; MASTER_PAYLOAD_MAX_SIZE];
|
||||
let len = key.len();
|
||||
config_key[..len].clone_from_slice(key.as_bytes());
|
||||
|
||||
let reply = drtio::aux_transact(
|
||||
linkno,
|
||||
routing_table,
|
||||
&Packet::CoreMgmtConfigRemoveRequest {
|
||||
destination: destination,
|
||||
length: len as u16,
|
||||
@@ -473,15 +363,9 @@ mod remote_coremgmt {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn config_erase(
|
||||
stream: &mut TcpStream,
|
||||
routing_table: &RoutingTable,
|
||||
linkno: u8,
|
||||
destination: u8,
|
||||
) -> Result<()> {
|
||||
pub async fn config_erase(stream: &mut TcpStream, linkno: u8, destination: u8) -> Result<()> {
|
||||
let reply = drtio::aux_transact(
|
||||
linkno,
|
||||
routing_table,
|
||||
&Packet::CoreMgmtConfigEraseRequest {
|
||||
destination: destination,
|
||||
},
|
||||
@@ -506,15 +390,9 @@ mod remote_coremgmt {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn reboot(
|
||||
stream: &mut TcpStream,
|
||||
routing_table: &RoutingTable,
|
||||
linkno: u8,
|
||||
destination: u8,
|
||||
) -> Result<()> {
|
||||
pub async fn reboot(stream: &mut TcpStream, linkno: u8, destination: u8) -> Result<()> {
|
||||
let reply = drtio::aux_transact(
|
||||
linkno,
|
||||
routing_table,
|
||||
&Packet::CoreMgmtRebootRequest {
|
||||
destination: destination,
|
||||
},
|
||||
@@ -539,15 +417,9 @@ mod remote_coremgmt {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn debug_allocator(
|
||||
stream: &mut TcpStream,
|
||||
routing_table: &RoutingTable,
|
||||
linkno: u8,
|
||||
destination: u8,
|
||||
) -> Result<()> {
|
||||
pub async fn debug_allocator(stream: &mut TcpStream, linkno: u8, destination: u8) -> Result<()> {
|
||||
let reply = drtio::aux_transact(
|
||||
linkno,
|
||||
routing_table,
|
||||
&Packet::CoreMgmtAllocatorDebugRequest {
|
||||
destination: destination,
|
||||
},
|
||||
@@ -570,18 +442,11 @@ mod remote_coremgmt {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn image_write(
|
||||
stream: &mut TcpStream,
|
||||
routing_table: &RoutingTable,
|
||||
linkno: u8,
|
||||
destination: u8,
|
||||
image: Vec<u8>,
|
||||
) -> Result<()> {
|
||||
pub async fn image_write(stream: &mut TcpStream, linkno: u8, destination: u8, image: Vec<u8>) -> Result<()> {
|
||||
let mut image = &image[..];
|
||||
|
||||
let alloc_reply = drtio::aux_transact(
|
||||
linkno,
|
||||
routing_table,
|
||||
&Packet::CoreMgmtFlashRequest {
|
||||
destination: destination,
|
||||
payload_length: image.len() as u32,
|
||||
@@ -610,7 +475,6 @@ mod remote_coremgmt {
|
||||
|
||||
let reply = drtio::aux_transact(
|
||||
linkno,
|
||||
routing_table,
|
||||
&Packet::CoreMgmtFlashAddDataRequest {
|
||||
destination: destination,
|
||||
last: last,
|
||||
@@ -667,7 +531,7 @@ mod local_coremgmt {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn pull_log(stream: &mut TcpStream, pull_id: &Rc<RefCell<u32>>) -> Result<()> {
|
||||
pub async fn pull_log(stream: &mut TcpStream, pull_id: &RefCell<u32>) -> Result<()> {
|
||||
let id = {
|
||||
let mut guard = pull_id.borrow_mut();
|
||||
*guard += 1;
|
||||
@@ -678,35 +542,19 @@ mod local_coremgmt {
|
||||
if id != *pull_id.borrow() {
|
||||
// another connection attempts to pull the log...
|
||||
// abort this connection...
|
||||
break;
|
||||
return Err(Error::OvertakeError);
|
||||
}
|
||||
let bytes = buffer.extract().as_bytes().to_vec();
|
||||
buffer.clear();
|
||||
core::mem::drop(buffer);
|
||||
write_chunk(stream, &bytes).await?;
|
||||
if log::max_level() == log::LevelFilter::Trace {
|
||||
// temporarily discard all trace level log
|
||||
if BufferLogger::get_logger().buffer_log_level() == log::LevelFilter::Trace {
|
||||
let logger = BufferLogger::get_logger();
|
||||
logger.set_buffer_log_level(log::LevelFilter::Debug);
|
||||
stream.flush().await?;
|
||||
logger.set_buffer_log_level(log::LevelFilter::Trace);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn set_log_filter(stream: &mut TcpStream, lvl: log::LevelFilter) -> Result<()> {
|
||||
info!("Changing log level to {}", lvl);
|
||||
log::set_max_level(lvl);
|
||||
write_i8(stream, Reply::Success as i8).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn set_uart_log_filter(stream: &mut TcpStream, lvl: log::LevelFilter) -> Result<()> {
|
||||
info!("Changing UART log level to {}", lvl);
|
||||
BufferLogger::get_logger().set_uart_log_level(lvl);
|
||||
write_i8(stream, Reply::Success as i8).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn config_read(stream: &mut TcpStream, key: &String) -> Result<()> {
|
||||
@@ -723,16 +571,33 @@ mod local_coremgmt {
|
||||
}
|
||||
|
||||
pub async fn config_write(stream: &mut TcpStream, key: &String, value: Vec<u8>) -> Result<()> {
|
||||
let value = libconfig::write(&key, value);
|
||||
if value.is_ok() {
|
||||
let res = libconfig::write(&key, value.clone());
|
||||
if res.is_ok() {
|
||||
debug!("write success");
|
||||
if key == "idle_kernel" {
|
||||
RESTART_IDLE.signal();
|
||||
match key.as_str() {
|
||||
"idle_kernel" => {
|
||||
RESTART_IDLE.signal();
|
||||
}
|
||||
"log_level" | "uart_log_level" => {
|
||||
let value_str = core::str::from_utf8(&value).map_err(Error::from)?;
|
||||
let max_level = value_str
|
||||
.parse::<log::LevelFilter>()
|
||||
.map_err(|_| Error::UnknownLogLevel())?;
|
||||
|
||||
if key == "log_level" {
|
||||
BufferLogger::get_logger().set_buffer_log_level(max_level);
|
||||
info!("changing log level to {}", max_level);
|
||||
} else {
|
||||
BufferLogger::get_logger().set_uart_log_level(max_level);
|
||||
info!("changing UART log level to {}", max_level);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
write_i8(stream, Reply::Success as i8).await?;
|
||||
} else {
|
||||
// this is an error because we do not expect write to fail
|
||||
error!("failed to write: {:?}", value);
|
||||
error!("failed to write: {:?}", res);
|
||||
write_i8(stream, Reply::Error as i8).await?;
|
||||
}
|
||||
Ok(())
|
||||
@@ -762,6 +627,7 @@ mod local_coremgmt {
|
||||
|
||||
pub async fn reboot(stream: &mut TcpStream) -> Result<()> {
|
||||
info!("rebooting");
|
||||
log::logger().flush();
|
||||
write_i8(stream, Reply::RebootImminent as i8).await?;
|
||||
stream.flush().await?;
|
||||
slcr::reboot();
|
||||
@@ -804,33 +670,25 @@ mod local_coremgmt {
|
||||
|
||||
#[cfg(has_drtio)]
|
||||
macro_rules! process {
|
||||
($stream: ident, $routing_table:ident, $destination:expr, $func:ident $(, $param:expr)*) => {{
|
||||
if $destination == 0 {
|
||||
($stream: ident, $destination:expr, $func:ident $(, $param:expr)*) => {{
|
||||
let hop = ROUTING_TABLE.get().unwrap().0[$destination as usize][0];
|
||||
let linkno = hop - 1 as u8;
|
||||
if hop == 0 {
|
||||
local_coremgmt::$func($stream, $($param, )*).await
|
||||
} else if let Some(ref routing_table) = $routing_table {
|
||||
let routing_table = routing_table.borrow();
|
||||
let linkno = routing_table.0[$destination as usize][0] - 1 as u8;
|
||||
remote_coremgmt::$func($stream, &routing_table, linkno, $destination, $($param, )*).await
|
||||
} else {
|
||||
error!("coremgmt-over-drtio not supported for panicked device, please reboot");
|
||||
write_i8($stream, Reply::Error as i8).await?;
|
||||
Err(drtio::Error::LinkDown.into())
|
||||
remote_coremgmt::$func($stream, linkno, $destination, $($param, )*).await
|
||||
}
|
||||
}}
|
||||
}
|
||||
|
||||
#[cfg(not(has_drtio))]
|
||||
macro_rules! process {
|
||||
($stream: ident, $routing_table:ident, $destination:expr, $func:ident $(, $param:expr)*) => {{
|
||||
($stream: ident, $destination:expr, $func:ident $(, $param:expr)*) => {{
|
||||
local_coremgmt::$func($stream, $($param, )*).await
|
||||
}}
|
||||
}
|
||||
|
||||
async fn handle_connection(
|
||||
stream: &mut TcpStream,
|
||||
pull_id: Rc<RefCell<u32>>,
|
||||
_routing_table: Option<Rc<RefCell<RoutingTable>>>,
|
||||
) -> Result<()> {
|
||||
async fn handle_connection(stream: &mut TcpStream, pull_ids: Rc<[RefCell<u32>]>) -> Result<()> {
|
||||
if !expect(&stream, b"ARTIQ management\n").await? {
|
||||
return Err(Error::UnexpectedPattern);
|
||||
}
|
||||
@@ -838,6 +696,8 @@ async fn handle_connection(
|
||||
let _destination: u8 = read_i8(stream).await? as u8;
|
||||
stream.send_slice("e".as_bytes()).await?;
|
||||
|
||||
let pull_id = &pull_ids[_destination as usize];
|
||||
|
||||
loop {
|
||||
let msg = read_i8(stream).await;
|
||||
if let Err(smoltcp::Error::Finished) = msg {
|
||||
@@ -845,20 +705,12 @@ async fn handle_connection(
|
||||
}
|
||||
let msg: Request = FromPrimitive::from_i8(msg?).ok_or(Error::UnrecognizedPacket)?;
|
||||
match msg {
|
||||
Request::GetLog => process!(stream, _routing_table, _destination, get_log),
|
||||
Request::ClearLog => process!(stream, _routing_table, _destination, clear_log),
|
||||
Request::PullLog => process!(stream, _routing_table, _destination, pull_log, &pull_id),
|
||||
Request::SetLogFilter => {
|
||||
let lvl = read_log_level_filter(stream).await?;
|
||||
process!(stream, _routing_table, _destination, set_log_filter, lvl)
|
||||
}
|
||||
Request::SetUartLogFilter => {
|
||||
let lvl = read_log_level_filter(stream).await?;
|
||||
process!(stream, _routing_table, _destination, set_uart_log_filter, lvl)
|
||||
}
|
||||
Request::GetLog => process!(stream, _destination, get_log),
|
||||
Request::ClearLog => process!(stream, _destination, clear_log),
|
||||
Request::PullLog => process!(stream, _destination, pull_log, pull_id),
|
||||
Request::ConfigRead => {
|
||||
let key = read_key(stream).await?;
|
||||
process!(stream, _routing_table, _destination, config_read, &key)
|
||||
process!(stream, _destination, config_read, &key)
|
||||
}
|
||||
Request::ConfigWrite => {
|
||||
let key = read_key(stream).await?;
|
||||
@@ -869,20 +721,20 @@ async fn handle_connection(
|
||||
buffer.set_len(len);
|
||||
}
|
||||
read_chunk(stream, &mut buffer).await?;
|
||||
process!(stream, _routing_table, _destination, config_write, &key, buffer)
|
||||
process!(stream, _destination, config_write, &key, buffer)
|
||||
}
|
||||
Request::ConfigRemove => {
|
||||
let key = read_key(stream).await?;
|
||||
process!(stream, _routing_table, _destination, config_remove, &key)
|
||||
process!(stream, _destination, config_remove, &key)
|
||||
}
|
||||
Request::Reboot => {
|
||||
process!(stream, _routing_table, _destination, reboot)
|
||||
process!(stream, _destination, reboot)
|
||||
}
|
||||
Request::ConfigErase => {
|
||||
process!(stream, _routing_table, _destination, config_erase)
|
||||
process!(stream, _destination, config_erase)
|
||||
}
|
||||
Request::DebugAllocator => {
|
||||
process!(stream, _routing_table, _destination, debug_allocator)
|
||||
process!(stream, _destination, debug_allocator)
|
||||
}
|
||||
Request::Flash => {
|
||||
let len = read_i32(stream).await?;
|
||||
@@ -895,22 +747,24 @@ async fn handle_connection(
|
||||
buffer.set_len(len as usize);
|
||||
}
|
||||
read_chunk(stream, &mut buffer).await?;
|
||||
process!(stream, _routing_table, _destination, image_write, buffer)
|
||||
process!(stream, _destination, image_write, buffer)
|
||||
}
|
||||
}?;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn start(routing_table: Option<Rc<RefCell<RoutingTable>>>) {
|
||||
pub fn start() {
|
||||
task::spawn(async move {
|
||||
let pull_id = Rc::new(RefCell::new(0u32));
|
||||
#[cfg(has_drtio)]
|
||||
let pull_ids = Rc::new([const { RefCell::new(0u32) }; drtio_routing::DEST_COUNT]);
|
||||
#[cfg(not(has_drtio))]
|
||||
let pull_ids = Rc::new([RefCell::new(0u32); 1]);
|
||||
loop {
|
||||
let mut stream = TcpStream::accept(1380, 2048, 2048).await.unwrap();
|
||||
let pull_id = pull_id.clone();
|
||||
let routing_table = routing_table.clone();
|
||||
let pull_ids = pull_ids.clone();
|
||||
task::spawn(async move {
|
||||
info!("received connection");
|
||||
let _ = handle_connection(&mut stream, pull_id, routing_table)
|
||||
let _ = handle_connection(&mut stream, pull_ids)
|
||||
.await
|
||||
.map_err(|e| warn!("connection terminated: {:?}", e));
|
||||
let _ = stream.flush().await;
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
use alloc::{collections::BTreeMap, rc::Rc};
|
||||
use core::{cell::RefCell, fmt};
|
||||
use alloc::collections::BTreeMap;
|
||||
use core::fmt;
|
||||
|
||||
use futures::{FutureExt, pin_mut, select_biased};
|
||||
use libasync::{smoltcp::TcpStream, task};
|
||||
use libboard_artiq::drtio_routing;
|
||||
use libboard_zynq::{smoltcp, timer};
|
||||
use log::{debug, info, warn};
|
||||
use num_derive::{FromPrimitive, ToPrimitive};
|
||||
use num_traits::{FromPrimitive, ToPrimitive};
|
||||
|
||||
#[cfg(has_drtio)]
|
||||
use crate::comms::ROUTING_TABLE;
|
||||
use crate::proto_async::*;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
@@ -56,19 +57,11 @@ mod remote_moninj {
|
||||
use log::error;
|
||||
|
||||
use super::*;
|
||||
use crate::rtio_mgt::{drtio,
|
||||
drtio::{AUX_MUTEX, Error as DrtioError}};
|
||||
use crate::rtio_mgt::drtio::{self, AUX_MUTEX, Error as DrtioError};
|
||||
|
||||
pub async fn read_probe(
|
||||
routing_table: &drtio_routing::RoutingTable,
|
||||
linkno: u8,
|
||||
destination: u8,
|
||||
channel: i32,
|
||||
probe: i8,
|
||||
) -> i64 {
|
||||
pub async fn read_probe(linkno: u8, destination: u8, channel: i32, probe: i8) -> i64 {
|
||||
let reply = drtio::aux_transact(
|
||||
linkno,
|
||||
routing_table,
|
||||
&drtioaux_async::Packet::MonitorRequest {
|
||||
destination: destination,
|
||||
channel: channel as _,
|
||||
@@ -87,14 +80,7 @@ mod remote_moninj {
|
||||
0
|
||||
}
|
||||
|
||||
pub async fn inject(
|
||||
_routing_table: &drtio_routing::RoutingTable,
|
||||
linkno: u8,
|
||||
destination: u8,
|
||||
channel: i32,
|
||||
overrd: i8,
|
||||
value: i8,
|
||||
) {
|
||||
pub async fn inject(linkno: u8, destination: u8, channel: i32, overrd: i8, value: i8) {
|
||||
let _lock = AUX_MUTEX.async_lock().await;
|
||||
drtioaux_async::send(
|
||||
linkno,
|
||||
@@ -109,16 +95,9 @@ mod remote_moninj {
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
pub async fn read_injection_status(
|
||||
routing_table: &drtio_routing::RoutingTable,
|
||||
linkno: u8,
|
||||
destination: u8,
|
||||
channel: i32,
|
||||
overrd: i8,
|
||||
) -> i8 {
|
||||
pub async fn read_injection_status(linkno: u8, destination: u8, channel: i32, overrd: i8) -> i8 {
|
||||
let reply = drtio::aux_transact(
|
||||
linkno,
|
||||
routing_table,
|
||||
&drtioaux_async::Packet::InjectionStatusRequest {
|
||||
destination: destination,
|
||||
channel: channel as _,
|
||||
@@ -169,28 +148,28 @@ mod local_moninj {
|
||||
|
||||
#[cfg(has_drtio)]
|
||||
macro_rules! dispatch {
|
||||
($routing_table:ident, $channel:expr, $func:ident $(, $param:expr)*) => {{
|
||||
($channel:expr, $func:ident $(, $param:expr)*) => {{
|
||||
let destination = ($channel >> 16) as u8;
|
||||
let channel = $channel;
|
||||
let hop = $routing_table.0[destination as usize][0];
|
||||
let hop = ROUTING_TABLE.get().unwrap().0[destination as usize][0];
|
||||
if hop == 0 {
|
||||
local_moninj::$func(channel.into(), $($param, )*)
|
||||
} else {
|
||||
let linkno = hop - 1 as u8;
|
||||
remote_moninj::$func($routing_table, linkno, destination, channel, $($param, )*).await
|
||||
remote_moninj::$func(linkno, destination, channel, $($param, )*).await
|
||||
}
|
||||
}}
|
||||
}
|
||||
|
||||
#[cfg(not(has_drtio))]
|
||||
macro_rules! dispatch {
|
||||
($routing_table:ident, $channel:expr, $func:ident $(, $param:expr)*) => {{
|
||||
($channel:expr, $func:ident $(, $param:expr)*) => {{
|
||||
let channel = $channel as u16;
|
||||
local_moninj::$func(channel.into(), $($param, )*)
|
||||
}}
|
||||
}
|
||||
|
||||
async fn handle_connection(stream: &TcpStream, _routing_table: &drtio_routing::RoutingTable) -> Result<()> {
|
||||
async fn handle_connection(stream: &TcpStream) -> Result<()> {
|
||||
if !expect(&stream, b"ARTIQ moninj\n").await? {
|
||||
return Err(Error::UnexpectedPattern);
|
||||
}
|
||||
@@ -238,13 +217,13 @@ async fn handle_connection(stream: &TcpStream, _routing_table: &drtio_routing::R
|
||||
let channel = read_i32(&stream).await?;
|
||||
let overrd = read_i8(&stream).await?;
|
||||
let value = read_i8(&stream).await?;
|
||||
dispatch!(_routing_table, channel, inject, overrd, value);
|
||||
dispatch!(channel, inject, overrd, value);
|
||||
debug!("INJECT channel {}, overrd {}, value {}", channel, overrd, value);
|
||||
},
|
||||
HostMessage::GetInjectionStatus => {
|
||||
let channel = read_i32(&stream).await?;
|
||||
let overrd = read_i8(&stream).await?;
|
||||
let value = dispatch!(_routing_table, channel, read_injection_status, overrd);
|
||||
let value = dispatch!(channel, read_injection_status, overrd);
|
||||
write_i8(&stream, DeviceMessage::InjectionStatus.to_i8().unwrap()).await?;
|
||||
write_i32(&stream, channel).await?;
|
||||
write_i8(&stream, overrd).await?;
|
||||
@@ -254,7 +233,7 @@ async fn handle_connection(stream: &TcpStream, _routing_table: &drtio_routing::R
|
||||
},
|
||||
_ = timeout_f => {
|
||||
for (&(channel, probe), previous) in probe_watch_list.iter_mut() {
|
||||
let current = dispatch!(_routing_table, channel, read_probe, probe);
|
||||
let current = dispatch!(channel, read_probe, probe);
|
||||
if previous.is_none() || previous.unwrap() != current {
|
||||
write_i8(&stream, DeviceMessage::MonitorStatus.to_i8().unwrap()).await?;
|
||||
write_i32(&stream, channel).await?;
|
||||
@@ -264,7 +243,7 @@ async fn handle_connection(stream: &TcpStream, _routing_table: &drtio_routing::R
|
||||
}
|
||||
}
|
||||
for (&(channel, overrd), previous) in inject_watch_list.iter_mut() {
|
||||
let current = dispatch!(_routing_table, channel, read_injection_status, overrd);
|
||||
let current = dispatch!(channel, read_injection_status, overrd);
|
||||
if previous.is_none() || previous.unwrap() != current {
|
||||
write_i8(&stream, DeviceMessage::InjectionStatus.to_i8().unwrap()).await?;
|
||||
write_i32(&stream, channel).await?;
|
||||
@@ -279,16 +258,13 @@ async fn handle_connection(stream: &TcpStream, _routing_table: &drtio_routing::R
|
||||
}
|
||||
}
|
||||
|
||||
pub fn start(routing_table: &Rc<RefCell<drtio_routing::RoutingTable>>) {
|
||||
let routing_table = routing_table.clone();
|
||||
pub fn start() {
|
||||
task::spawn(async move {
|
||||
loop {
|
||||
let routing_table = routing_table.clone();
|
||||
let stream = TcpStream::accept(1383, 2048, 2048).await.unwrap();
|
||||
task::spawn(async move {
|
||||
info!("received connection");
|
||||
let routing_table = routing_table.borrow();
|
||||
let result = handle_connection(&stream, &routing_table).await;
|
||||
let result = handle_connection(&stream).await;
|
||||
match result {
|
||||
Err(Error::NetworkError(smoltcp::Error::Finished)) => info!("peer closed connection"),
|
||||
Err(error) => warn!("connection terminated: {}", error),
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
#[cfg(has_si5324)]
|
||||
use ksupport::kernel::i2c;
|
||||
#[cfg(not(feature = "target_ebaz4205"))]
|
||||
use libboard_artiq::pl;
|
||||
#[cfg(has_si549)]
|
||||
use libboard_artiq::si549;
|
||||
#[cfg(has_si5324)]
|
||||
use libboard_artiq::si5324;
|
||||
use libboard_artiq::{i2c, si5324};
|
||||
#[cfg(has_si5324)]
|
||||
use libboard_zynq::i2c::I2c;
|
||||
use libboard_zynq::timer;
|
||||
|
||||
@@ -5,7 +5,6 @@ use core::mem;
|
||||
use ksupport::kernel::DmaRecorder;
|
||||
#[cfg(has_drtio)]
|
||||
use libasync::task;
|
||||
use libboard_artiq::drtio_routing::RoutingTable;
|
||||
use libcortex_a9::{cache::dcci_slice, mutex::Mutex};
|
||||
|
||||
const ALIGNMENT: usize = 16 * 8;
|
||||
@@ -105,11 +104,11 @@ pub mod remote_dma {
|
||||
Ok(playback_state)
|
||||
}
|
||||
|
||||
pub async fn upload_traces(&mut self, routing_table: &RoutingTable) {
|
||||
pub async fn upload_traces(&mut self) {
|
||||
let mut lock = self.traces.async_lock().await;
|
||||
let trace_iter = lock.iter_mut();
|
||||
for (destination, trace) in trace_iter {
|
||||
match drtio::ddma_upload_trace(routing_table, self.id, *destination, trace.get_trace()).await {
|
||||
match drtio::ddma_upload_trace(self.id, *destination, trace.get_trace()).await {
|
||||
Ok(_) => trace.state = RemoteState::Loaded,
|
||||
Err(e) => error!("Error adding DMA trace on destination {}: {}", destination, e),
|
||||
}
|
||||
@@ -117,11 +116,11 @@ pub mod remote_dma {
|
||||
*(self.done_count.async_lock().await) = 0;
|
||||
}
|
||||
|
||||
pub async fn erase(&mut self, routing_table: &RoutingTable) {
|
||||
pub async fn erase(&mut self) {
|
||||
let lock = self.traces.async_lock().await;
|
||||
let trace_iter = lock.keys();
|
||||
for destination in trace_iter {
|
||||
match drtio::ddma_send_erase(routing_table, self.id, *destination).await {
|
||||
match drtio::ddma_send_erase(self.id, *destination).await {
|
||||
Ok(_) => (),
|
||||
Err(e) => error!("Error adding DMA trace on destination {}: {}", destination, e),
|
||||
}
|
||||
@@ -139,7 +138,7 @@ pub mod remote_dma {
|
||||
*(self.done_count.async_lock().await) += 1;
|
||||
}
|
||||
|
||||
pub async fn playback(&self, routing_table: &RoutingTable, timestamp: u64) {
|
||||
pub async fn playback(&self, timestamp: u64) {
|
||||
let mut dest_list: Vec<u8> = Vec::new();
|
||||
{
|
||||
let lock = self.traces.async_lock().await;
|
||||
@@ -155,18 +154,18 @@ pub mod remote_dma {
|
||||
// mutex lock must be dropped before sending a playback request to avoid a deadlock,
|
||||
// if PlaybackStatus is sent from another satellite and the state must be updated.
|
||||
for destination in dest_list {
|
||||
match drtio::ddma_send_playback(routing_table, self.id, destination, timestamp).await {
|
||||
match drtio::ddma_send_playback(self.id, destination, timestamp).await {
|
||||
Ok(_) => (),
|
||||
Err(e) => error!("Error during remote DMA playback: {}", e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn destination_changed(&mut self, routing_table: &RoutingTable, destination: u8, up: bool) {
|
||||
pub async fn destination_changed(&mut self, destination: u8, up: bool) {
|
||||
// update state of the destination, resend traces if it's up
|
||||
if let Some(trace) = self.traces.async_lock().await.get_mut(&destination) {
|
||||
if up {
|
||||
match drtio::ddma_upload_trace(routing_table, self.id, destination, trace.get_trace()).await {
|
||||
match drtio::ddma_upload_trace(self.id, destination, trace.get_trace()).await {
|
||||
Ok(_) => trace.state = RemoteState::Loaded,
|
||||
Err(e) => error!("Error adding DMA trace on destination {}: {}", destination, e),
|
||||
}
|
||||
@@ -192,22 +191,22 @@ pub mod remote_dma {
|
||||
trace_set.await_done(timeout).await
|
||||
}
|
||||
|
||||
pub async fn erase(routing_table: &RoutingTable, id: u32) {
|
||||
pub async fn erase(id: u32) {
|
||||
let trace_set = unsafe { TRACES.get_mut(&id).unwrap() };
|
||||
trace_set.erase(routing_table).await;
|
||||
trace_set.erase().await;
|
||||
unsafe {
|
||||
TRACES.remove(&id);
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn upload_traces(routing_table: &RoutingTable, id: u32) {
|
||||
pub async fn upload_traces(id: u32) {
|
||||
let trace_set = unsafe { TRACES.get_mut(&id).unwrap() };
|
||||
trace_set.upload_traces(routing_table).await;
|
||||
trace_set.upload_traces().await;
|
||||
}
|
||||
|
||||
pub async fn playback(routing_table: &RoutingTable, id: u32, timestamp: u64) {
|
||||
pub async fn playback(id: u32, timestamp: u64) {
|
||||
let trace_set = unsafe { TRACES.get_mut(&id).unwrap() };
|
||||
trace_set.playback(routing_table, timestamp).await;
|
||||
trace_set.playback(timestamp).await;
|
||||
}
|
||||
|
||||
pub async fn playback_done(id: u32, destination: u8, error: u8, channel: u32, timestamp: u64) {
|
||||
@@ -215,10 +214,10 @@ pub mod remote_dma {
|
||||
trace_set.playback_done(destination, error, channel, timestamp).await;
|
||||
}
|
||||
|
||||
pub async fn destination_changed(routing_table: &RoutingTable, destination: u8, up: bool) {
|
||||
pub async fn destination_changed(destination: u8, up: bool) {
|
||||
let trace_iter = unsafe { TRACES.values_mut() };
|
||||
for trace_set in trace_iter {
|
||||
trace_set.destination_changed(routing_table, destination, up).await;
|
||||
trace_set.destination_changed(destination, up).await;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -228,7 +227,7 @@ pub mod remote_dma {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn put_record(_routing_table: &RoutingTable, mut recorder: DmaRecorder) -> u32 {
|
||||
pub async fn put_record(mut recorder: DmaRecorder) -> u32 {
|
||||
#[cfg(has_drtio)]
|
||||
let mut remote_traces: BTreeMap<u8, Vec<u8>> = BTreeMap::new();
|
||||
|
||||
@@ -277,7 +276,7 @@ pub async fn put_record(_routing_table: &RoutingTable, mut recorder: DmaRecorder
|
||||
#[cfg(has_drtio)]
|
||||
{
|
||||
if let Some((old_id, _v, _d)) = _old_record {
|
||||
remote_dma::erase(_routing_table, old_id).await;
|
||||
remote_dma::erase(old_id).await;
|
||||
}
|
||||
remote_dma::add_traces(ptr, remote_traces);
|
||||
}
|
||||
@@ -285,11 +284,11 @@ pub async fn put_record(_routing_table: &RoutingTable, mut recorder: DmaRecorder
|
||||
ptr
|
||||
}
|
||||
|
||||
pub async fn erase(name: String, _routing_table: &RoutingTable) {
|
||||
pub async fn erase(name: String) {
|
||||
let _entry = DMA_RECORD_STORE.lock().remove(&name);
|
||||
#[cfg(has_drtio)]
|
||||
if let Some((id, _v, _d)) = _entry {
|
||||
remote_dma::erase(_routing_table, id).await;
|
||||
remote_dma::erase(id).await;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
use alloc::rc::Rc;
|
||||
use core::cell::RefCell;
|
||||
|
||||
use libboard_artiq::{drtio_routing, drtio_routing::RoutingTable, pl::csr};
|
||||
use libboard_artiq::{drtio_routing, pl::csr};
|
||||
use libconfig;
|
||||
use libcortex_a9::mutex::Mutex;
|
||||
use log::{info, warn};
|
||||
|
||||
#[cfg(has_drtio)]
|
||||
@@ -11,20 +10,25 @@ pub mod drtio {
|
||||
use alloc::vec::Vec;
|
||||
use core::fmt;
|
||||
|
||||
use ksupport::{ASYNC_ERROR_BUSY, ASYNC_ERROR_COLLISION, ASYNC_ERROR_SEQUENCE_ERROR, SEEN_ASYNC_ERRORS,
|
||||
kernel::Message as KernelMessage, resolve_channel_name};
|
||||
use ksupport::kernel::Message as KernelMessage;
|
||||
use libasync::task;
|
||||
#[cfg(has_drtio_eem)]
|
||||
use libboard_artiq::drtio_eem;
|
||||
use libboard_artiq::{drtioaux::Error as DrtioError,
|
||||
drtioaux_async,
|
||||
drtioaux_async::Packet,
|
||||
drtioaux_proto::{MASTER_PAYLOAD_MAX_SIZE, PayloadStatus}};
|
||||
drtioaux_proto::{MASTER_PAYLOAD_MAX_SIZE, PayloadStatus},
|
||||
resolve_channel_name};
|
||||
use libboard_zynq::timer;
|
||||
use libcortex_a9::mutex::Mutex;
|
||||
use log::{error, info, warn};
|
||||
|
||||
use super::*;
|
||||
use crate::{analyzer::remote_analyzer::RemoteBuffer, rtio_dma::remote_dma, subkernel};
|
||||
use crate::{analyzer::remote_analyzer::RemoteBuffer,
|
||||
comms::{ASYNC_ERROR_BUSY, ASYNC_ERROR_COLLISION, ASYNC_ERROR_SEQUENCE_ERROR, ROUTING_TABLE,
|
||||
SEEN_ASYNC_ERRORS},
|
||||
rtio_dma::remote_dma,
|
||||
subkernel};
|
||||
|
||||
#[cfg(has_drtio_eem)]
|
||||
const DRTIO_EEM_LINKNOS: core::ops::Range<usize> =
|
||||
@@ -67,15 +71,10 @@ pub mod drtio {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn startup(
|
||||
routing_table: &Rc<RefCell<RoutingTable>>,
|
||||
up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>,
|
||||
) {
|
||||
let routing_table = routing_table.clone();
|
||||
pub fn startup(up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>) {
|
||||
let up_destinations = up_destinations.clone();
|
||||
task::spawn(async move {
|
||||
let routing_table = routing_table.borrow();
|
||||
link_task(&routing_table, &up_destinations).await;
|
||||
link_task(&up_destinations).await;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -94,9 +93,9 @@ pub mod drtio {
|
||||
unsafe { (csr::DRTIO[linkno].rx_up_read)() == 1 }
|
||||
}
|
||||
|
||||
fn get_master_destination(routing_table: &RoutingTable) -> u8 {
|
||||
fn get_master_destination() -> u8 {
|
||||
for i in 0..drtio_routing::DEST_COUNT {
|
||||
if routing_table.0[i][0] == 0 {
|
||||
if ROUTING_TABLE.get().unwrap().0[i][0] == 0 {
|
||||
return i as u8;
|
||||
}
|
||||
}
|
||||
@@ -104,8 +103,8 @@ pub mod drtio {
|
||||
0
|
||||
}
|
||||
|
||||
async fn route_packet(linkno: u8, routing_table: &RoutingTable, packet: Packet, destination: u8) {
|
||||
let dest_link = routing_table.0[destination as usize][0] - 1;
|
||||
async fn route_packet(linkno: u8, packet: Packet, destination: u8) {
|
||||
let dest_link = ROUTING_TABLE.get().unwrap().0[destination as usize][0] - 1;
|
||||
if dest_link == linkno {
|
||||
warn!(
|
||||
"[LINK#{}] Re-routed packet would return to the same link, dropping: {:?}",
|
||||
@@ -116,8 +115,8 @@ pub mod drtio {
|
||||
}
|
||||
}
|
||||
|
||||
async fn process_async_packets(linkno: u8, routing_table: &RoutingTable, packet: Packet) -> Option<Packet> {
|
||||
let master_destination = get_master_destination(routing_table);
|
||||
async fn process_async_packets(linkno: u8, packet: Packet) -> Option<Packet> {
|
||||
let master_destination = get_master_destination();
|
||||
match packet {
|
||||
Packet::DmaPlaybackStatus {
|
||||
id,
|
||||
@@ -130,7 +129,7 @@ pub mod drtio {
|
||||
if destination == master_destination {
|
||||
remote_dma::playback_done(id, source, error, channel, timestamp).await;
|
||||
} else {
|
||||
route_packet(linkno, routing_table, packet, destination).await;
|
||||
route_packet(linkno, packet, destination).await;
|
||||
}
|
||||
None
|
||||
}
|
||||
@@ -143,7 +142,7 @@ pub mod drtio {
|
||||
if destination == master_destination {
|
||||
subkernel::subkernel_finished(id, with_exception, exception_src).await;
|
||||
} else {
|
||||
route_packet(linkno, routing_table, packet, destination).await;
|
||||
route_packet(linkno, packet, destination).await;
|
||||
}
|
||||
None
|
||||
}
|
||||
@@ -162,7 +161,7 @@ pub mod drtio {
|
||||
.await
|
||||
.unwrap();
|
||||
} else {
|
||||
route_packet(linkno, routing_table, packet, destination).await;
|
||||
route_packet(linkno, packet, destination).await;
|
||||
}
|
||||
None
|
||||
}
|
||||
@@ -181,7 +180,7 @@ pub mod drtio {
|
||||
if destination == master_destination {
|
||||
Some(packet)
|
||||
} else {
|
||||
route_packet(linkno, routing_table, packet, destination).await;
|
||||
route_packet(linkno, packet, destination).await;
|
||||
None
|
||||
}
|
||||
}
|
||||
@@ -200,7 +199,7 @@ pub mod drtio {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn aux_transact(linkno: u8, routing_table: &RoutingTable, request: &Packet) -> Result<Packet, Error> {
|
||||
pub async fn aux_transact(linkno: u8, request: &Packet) -> Result<Packet, Error> {
|
||||
if !link_rx_up(linkno).await {
|
||||
return Err(Error::LinkDown);
|
||||
}
|
||||
@@ -208,7 +207,7 @@ pub mod drtio {
|
||||
drtioaux_async::send(linkno, request).await.unwrap();
|
||||
loop {
|
||||
let packet = recv_aux_timeout(linkno, 200).await?;
|
||||
if let Some(packet) = process_async_packets(linkno, routing_table, packet).await {
|
||||
if let Some(packet) = process_async_packets(linkno, packet).await {
|
||||
return Ok(packet);
|
||||
}
|
||||
}
|
||||
@@ -221,7 +220,7 @@ pub mod drtio {
|
||||
}
|
||||
}
|
||||
|
||||
async fn ping_remote(linkno: u8, routing_table: &RoutingTable) -> u32 {
|
||||
async fn ping_remote(linkno: u8) -> u32 {
|
||||
let mut count = 0;
|
||||
loop {
|
||||
if !link_rx_up(linkno).await {
|
||||
@@ -231,7 +230,7 @@ pub mod drtio {
|
||||
if count > 100 {
|
||||
return 0;
|
||||
}
|
||||
let reply = aux_transact(linkno, routing_table, &Packet::EchoRequest).await;
|
||||
let reply = aux_transact(linkno, &Packet::EchoRequest).await;
|
||||
match reply {
|
||||
Ok(Packet::EchoReply) => {
|
||||
// make sure receive buffer is drained
|
||||
@@ -260,14 +259,13 @@ pub mod drtio {
|
||||
}
|
||||
}
|
||||
|
||||
async fn load_routing_table(linkno: u8, routing_table: &RoutingTable) -> Result<(), Error> {
|
||||
async fn load_routing_table(linkno: u8) -> Result<(), Error> {
|
||||
for i in 0..drtio_routing::DEST_COUNT {
|
||||
let reply = aux_transact(
|
||||
linkno,
|
||||
routing_table,
|
||||
&Packet::RoutingSetPath {
|
||||
destination: i as u8,
|
||||
hops: routing_table.0[i],
|
||||
hops: ROUTING_TABLE.get().unwrap().0[i],
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
@@ -278,8 +276,8 @@ pub mod drtio {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn set_rank(linkno: u8, rank: u8, routing_table: &RoutingTable) -> Result<(), Error> {
|
||||
let reply = aux_transact(linkno, routing_table, &Packet::RoutingSetRank { rank: rank }).await?;
|
||||
async fn set_rank(linkno: u8, rank: u8) -> Result<(), Error> {
|
||||
let reply = aux_transact(linkno, &Packet::RoutingSetRank { rank: rank }).await?;
|
||||
match reply {
|
||||
Packet::RoutingAck => Ok(()),
|
||||
_ => Err(Error::UnexpectedReply),
|
||||
@@ -302,11 +300,11 @@ pub mod drtio {
|
||||
}
|
||||
}
|
||||
|
||||
async fn process_unsolicited_aux(linkno: u8, routing_table: &RoutingTable) {
|
||||
async fn process_unsolicited_aux(linkno: u8) {
|
||||
let _lock = AUX_MUTEX.async_lock().await;
|
||||
match drtioaux_async::recv(linkno).await {
|
||||
Ok(Some(packet)) => {
|
||||
if let Some(packet) = process_async_packets(linkno, routing_table, packet).await {
|
||||
if let Some(packet) = process_async_packets(linkno, packet).await {
|
||||
warn!("[LINK#{}] unsolicited aux packet: {:?}", linkno, packet);
|
||||
}
|
||||
}
|
||||
@@ -337,7 +335,6 @@ pub mod drtio {
|
||||
}
|
||||
|
||||
async fn destination_set_up(
|
||||
routing_table: &RoutingTable,
|
||||
up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>,
|
||||
destination: u8,
|
||||
up: bool,
|
||||