66 Commits

Author SHA1 Message Date
3c70203709 clean up example DDBs 2026-01-23 19:04:58 +08:00
9614c48e9d flake: update dependencies 2026-01-23 18:31:03 +08:00
1c4534637d rtio_acp: fix batch not remapping back for 0 events 2026-01-23 18:26:28 +08:00
5bd6fe0ad5 cargo fmt 2026-01-23 18:26:28 +08:00
a8cf7644a2 flake.lock: update 2026-01-23 18:26:28 +08:00
febc623c4b acp: reset batch state properly 2026-01-23 18:26:28 +08:00
ebdfff202a linker: make pages overlap in VMA 2026-01-23 18:26:28 +08:00
c4334a1d8c ksupport: use page linker symbols 2026-01-23 18:26:28 +08:00
35be9d5501 linker script: use proper page size 2026-01-23 18:26:28 +08:00
1309fe1c97 libksupport: map rtio output functions to aligned symbols 2026-01-23 18:26:28 +08:00
29bb0aba28 comms: remove self-imposed recv buffer size limit
On recv bytes through TCP conection, a heap buffer of dynamic size is allocated as the memory backing.
2026-01-23 09:48:59 +08:00
d877013a2a cxp_phys: add gtx equalizer config 2026-01-13 11:12:37 +08:00
30fc3ef2e8 flake: fix acpki tests 2026-01-09 13:14:45 +08:00
2fb3c7274d fix minor build errors after adding batching 2026-01-09 10:23:57 +08:00
8d01fe7a20 flake: add rtio batch driver to ddb for acpki hitl tests 2026-01-08 19:33:01 +08:00
b8c4184f8e cargo fmt 2026-01-08 19:33:01 +08:00
e2ce90f051 acpki: get rid of batch_len csr 2026-01-08 19:33:01 +08:00
5c8ea9b885 rtio_acp: get rid of batch_len csr, pass whole struct 2026-01-08 19:33:01 +08:00
963d4194b1 acp: use last target pointer for error display 2026-01-08 19:33:01 +08:00
be38a5d2ee acpki gateware fixes 2026-01-08 19:33:01 +08:00
ad340334fb gateware: add acpki_batch_size config variable 2026-01-08 19:33:01 +08:00
9a5e68af41 acpki: fix maximum burst length 2026-01-08 19:33:01 +08:00
f9255d0611 gateware/kasli_soc: obtain acpki flag from json description
this introduces a breaking change where the acpki flag cannot be passed through the constructor of the SoCCore classes anymore.
2026-01-08 19:33:01 +08:00
7350e6dff5 gateware/kasli_soc: removed unused imports
Signed-off-by: Leon Riesebos <tiny.water9944@fastmail.com>
2026-01-08 19:33:01 +08:00
5270fce5f5 rtio_acp batching: move to a static buffer 2026-01-08 19:33:01 +08:00
3a410e5414 acpki: store the target of an rtio error 2026-01-08 19:33:01 +08:00
01609cce59 acpki: support batched RTIO in KernelInitiator 2026-01-08 19:33:01 +08:00
ce48d430af rtio_acp: add batching 2026-01-08 19:33:01 +08:00
b83772baf5 flake: update dependencies 2026-01-08 19:27:17 +08:00
099c344cc4 flake: update dependencies 2025-12-23 19:42:26 +08:00
c65b130275 jsons: base -> drtio_role
"base" is deprecated.
2025-12-01 13:04:44 +08:00
efd45316e7 cargo fmt 2025-11-28 22:32:13 +08:00
1f8c9c3ee3 flake: add zc706 acpki hitl tests 2025-11-28 22:17:14 +08:00
4a1dc628d9 acpki: fix wait delay, rtio output waits only in gateware 2025-11-28 22:14:46 +08:00
72407a19a3 rtio_acp: decrease latency for rtio events
move the status clear to after the status is read, rather than beginning
this saves the time for slow volatile write
fixes test_exceptions RTIO underflow test
2025-11-28 22:14:45 +08:00
d9871ed0a7 libkernel: acp: refactor, shortening the functions 2025-11-28 22:14:45 +08:00
90db06a9e1 kasli soc: add phaser_drtio support
kasli soc: refactor and move drtio over eem peripheral into a list
kasli soc: raise error when using drito over eem in standalone
2025-11-24 12:10:51 +08:00
446384d787 flake: update dependencies 2025-11-22 10:39:40 +08:00
dly04
f3d4793fcb deal with setting uart filter level to trace, to prevent drtioaux timeout 2025-11-19 11:15:43 +08:00
dly04
00c4d48211 use coremgmt config to set runtime and stored log level 2025-11-19 10:58:20 +08:00
fd1b2453d7 flake: format 2025-11-18 18:19:45 +08:00
6ff895c0bf flake: update dependencies 2025-11-18 18:06:23 +08:00
dly04
b55f629486 fix format 2025-11-18 16:30:04 +08:00
dly
61dbb6a0f1 fix handling of the various log levels
Fix the global log level at TRACE, modifying only buffer log level when calling `artiq_coremgmt log set_level`.
By replacing `set_max_level` being called after `artiq_coremgmt log set_level` by `set_buffer_log_level`.
So that `artiq_coremgmt log set_level` won't affect UART log level.
Tested on Kasli-Soc.

Co-authored-by: dly04 <yliujc@connect.ust.hk>
Reviewed-on: M-Labs/artiq-zynq#429
Reviewed-by: mwojcik <mw@m-labs.hk>
Reviewed-by: srenblad <srenblad@m-labs.hk>
Co-authored-by: dly <dly@m-labs.hk>
Co-committed-by: dly <dly@m-labs.hk>
2025-11-18 12:24:36 +08:00
159987a64b remote_run: fix target host name 2025-11-14 10:50:27 +08:00
3be9250978 flake: use artiq-build (artiq with minimal dependencies) 2025-11-10 18:39:08 +08:00
b88bb90139 flake: update dependencies 2025-11-10 18:38:38 +08:00
3b0b52ef2c si549: clean up remaining GlobalTimer usage
Missing as it did not show up in testing / searching.
2025-11-10 14:10:11 +08:00
982828bde1 flake: update dependencies 2025-11-04 22:34:12 +08:00
db0231956e firmware: expose ldexp 2025-11-04 21:24:43 +08:00
d9bf878d03 flake: update dependencies 2025-10-09 17:12:06 +08:00
beb98b52fd flake: update artiq and dependencies for SoC v1.2
For including the system description JSON schema change in
https://github.com/m-labs/artiq/pull/2857, so that a hw_rev of v1.2 for
the Kasli-SoC could be specified for building.
2025-09-12 13:30:20 +08:00
d57f308765 Add minimal support for Kasli-SoC v1.2
- Update cfg directives to consider a hw_rev of 1.2.
- Turn on EEM power, without checking for faults for the time being.
2025-09-12 13:30:10 +08:00
d9f2f84480 update cargo lockfile 2025-08-22 14:57:48 +08:00
c317b3a0ac satman: async_errors is always 0 2025-08-22 14:57:26 +08:00
54ce700fde ksupport: move async error reporting to runtime 2025-08-22 14:57:26 +08:00
7f28167279 ksupport: move device map to core0 2025-08-22 12:00:47 +08:00
307ced4585 ksupport: move i2c to core0
In order for the firmware to interop with Kasli v2, all inter core comms
need to be through the message passing interface (sync_channel/mailbox).
2025-08-20 12:35:01 +08:00
3f497e08a4 runtime: cleanup imports 2025-08-19 16:24:53 +08:00
Harry Poon
9a816e1d5b coremgmt: fix formatting 2025-08-15 11:08:46 +08:00
7cceda9353 terminate old aqctl_corelog connections when receiving new ones
M-Labs/artiq-zynq#424
Co-authored-by: harryp <thpoonaa@connect.ust.hk>
Co-committed-by: harryp <thpoonaa@connect.ust.hk>
2025-08-14 19:01:26 +08:00
a325d5ce78 flake: update dependencies 2025-08-11 23:18:28 +08:00
40f1c94ecf satman: flush uart before reboot 2025-08-11 15:10:18 +08:00
92c586d266 runtime: flush uart before rebooting 2025-08-11 15:10:18 +08:00
96928b7d0d logger: implement flush for BufferLogger 2025-08-11 15:10:18 +08:00
59266fd141 runtime: make routing table static OnceLock 2025-08-04 12:55:40 +08:00
45 changed files with 1743 additions and 1660 deletions

View File

@@ -2,7 +2,7 @@
"target": "kasli_soc",
"variant": "demo",
"hw_rev": "v1.0",
"base": "standalone",
"drtio_role": "standalone",
"peripherals": [
{
"type": "coaxpress_sfp"

View File

@@ -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
View File

@@ -0,0 +1 @@
device_db_zc706.py

View 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
View File

@@ -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
View File

@@ -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;
};
}

View File

@@ -2,7 +2,7 @@
"target": "kasli_soc",
"variant": "master",
"hw_rev": "v1.0",
"base": "master",
"drtio_role": "master",
"peripherals": [
{
"type": "coaxpress_sfp"

View File

@@ -2,7 +2,7 @@
"target": "kasli_soc",
"variant": "satellite",
"hw_rev": "v1.0",
"base": "satellite",
"drtio_role": "satellite",
"peripherals": [
{
"type": "coaxpress_sfp"

View File

@@ -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"

View File

@@ -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
View File

@@ -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",

View File

@@ -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 += [

View File

@@ -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:

View File

@@ -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:

View File

@@ -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:

View File

@@ -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 {

View File

@@ -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)?;

View File

@@ -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)];

View File

@@ -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");
}

View File

@@ -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() {}
}
}

View File

@@ -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(())
}

View File

@@ -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.*)

View File

@@ -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 }

View File

@@ -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),
{

View File

@@ -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 {}
}

View File

@@ -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

View File

@@ -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() }
}

View File

@@ -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,

View File

@@ -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;
}
}

View File

@@ -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

View File

@@ -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");
}

View File

@@ -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"] }

View File

@@ -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;

View File

@@ -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

View File

@@ -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();

View File

@@ -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;

View File

@@ -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),

View File

@@ -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;

View File

@@ -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;
}
}

View File

@@ -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,