Compare commits

...

67 Commits

Author SHA1 Message Date
afd0389bf3 rtio: reset satellites on rtio_init as well 2025-04-10 15:01:46 +08:00
f5139ee140 i2c io expander: fix the write changes 2025-04-01 14:37:37 +08:00
761b7c99cd i2c io expander: stop the bus even after an error 2025-03-29 16:37:24 +08:00
5982937ee6 flake: update dependencies 2025-03-29 16:37:06 +08:00
32889c11f1 i2c: dispatch remote i2c requests from kernel 2025-03-24 11:32:00 +08:00
bc7925989b cxp syscall: use usual order of ROI coordinates 2025-03-20 15:47:18 +08:00
b2256800fe cxp syscall: error if roiviewer over height limit 2025-03-20 15:47:18 +08:00
637163bbca flake: update dependencies 2025-03-19 17:25:37 +08:00
50ead76c09 i2c: use error enum, nacks cannot be ignored 2025-03-19 16:36:56 +08:00
267a1222ed cxp_grabber: add ROIViewer syscalls
api: add start roi viewer to flush the fifo and set the ROI coordinate
api: add roi viewer frame download
2025-03-14 12:12:58 +08:00
fe09e8615e flake: update dependencies 2025-03-14 12:11:57 +08:00
cb8fa20beb remove/allow dead code
CxpRead/CxpWrite functions are unused
and unplanned, removing. DrtioContext emits warn
because Clone is ignored in dead code analysis.
2025-03-14 11:30:31 +08:00
0efa450537 update cargo lockfile 2025-03-14 11:29:43 +08:00
4c59ab933b cargo fmt 2025-03-12 17:36:34 +08:00
504d7a8d5b flake: update dependencies 2025-03-12 17:28:35 +08:00
a577238bae bump rustfmt 2025-03-12 13:56:26 +08:00
1c90228f84 silence static mut ref warn for RECORDER 2025-03-12 13:56:26 +08:00
8129b8163c update futures, num-derive, async-recursion
bunched together to avoid depending on two separate `syn`
versions
2025-03-12 13:56:26 +08:00
95175b7168 silence dead code warns 2025-03-12 13:56:26 +08:00
3172625ba6 allow internal features
Signed-off-by: Simon Renblad <srenblad@m-labs.hk>
2025-03-12 13:56:26 +08:00
9e51599195 remove unnecessary imports 2025-03-12 13:56:26 +08:00
5445a1268c remove unnecessary mut 2025-03-12 13:56:26 +08:00
48ed2f188e fix dropping references 2025-03-12 13:56:26 +08:00
64d79de6c5 bump compiler_builtins to 0.1.108 2025-03-12 13:56:26 +08:00
be8f618d95 renamed const_btree_new feature 2025-03-12 13:56:26 +08:00
dca808b2e4 remove stabilized nll, static_nobundle flags 2025-03-12 13:56:26 +08:00
e4b85bf51a bump llvm to 18 2025-03-12 13:56:26 +08:00
c2c5367572 kasli-soc: support shuttler as a peripheral of kasli-soc satellite 2025-03-11 11:45:45 +08:00
290134e07e libio: add endianness as generic type param
Based on the API of ReadBytesExt, WriteBytesExt
from byteorder without the std dependency.
2025-03-10 15:44:33 +08:00
e07dad71d5 libksupport: add cxp syscall support
cxp: add read/write 32 bit value
cxp: add xml file download
lib: gate cxp import
api: add cxp syscalls
2025-03-04 14:46:39 +08:00
d0c34671d7 artiq error: add cxp error for syscall 2025-03-04 14:46:39 +08:00
82a1b38a19 runtime main: add cxp grabber support
main: init cxp phys
main: start cxp grabber task
2025-03-04 14:46:39 +08:00
db76dfc209 cxp_grabber fw: add cxp grabber handler
cxp_grabber: add cxp grabber tick task
cxp_grabber: add camera_connected and with_tag helper fns for syscall
libboard_artiq: add cxp_grabber.rs
2025-03-04 14:46:39 +08:00
b0ceac0f3a cxp_camera_setup fw: initalize camera
camera_setup: add setup error and error message
camera_setup: add camera discovery
camera_setup: add camera setup sequence
camera_setup: add placeholder HOST_CONNECTION_ID
libboard_artiq: add cxp_camera_setup.rs
2025-03-04 14:46:39 +08:00
a0673f13a1 cxp_packet fw: add cxp packet handler
packet: add receiving/sending control packet (w/ or w/o tags) handling
packet: add sending test packet
packet: add read/write register interface
packet: add read bytes for xml file download
libboard_artiq: add cxp_packet.rs
2025-03-04 14:46:39 +08:00
6086b867c8 cxp_ctrl fw: add cxp control packet parser
ctrl: add control packet error and error message
ctrl: add CXPCRC32 calculation
ctrl: use byteoder crate to handle endianness
ctrl: add control packer reader and writer
ctrl: add error correction for reading 4x char
libboard_artiq: add cxp_ctrl.rs
2025-03-04 14:46:39 +08:00
17f59e2353 cxp_phys fw: add CXP TRX phys support
phys: add tx & rx setup
tx: add csr to change linerate between 20.83/41.6Mpbs
rx: add GTX and QPLL DRP to change linerate 1.25-12.5Gbps
libboard artiq: add cxp_phys.rs
2025-03-04 14:46:39 +08:00
f080bee029 libboard_artiq cargo: add byteorder 2025-03-04 14:46:39 +08:00
599442dc0d flake: add zc706 cxp_4r_fmc variant build options 2025-03-04 14:46:39 +08:00
622bca24d1 zc706: add CXP_4R_FMC variant
zc706 base: expose cdr_clk (gt_refclk) for CXPGrabber
grabber: add cxp_4r_fmc pads
grabber: add CXPGrabber module
grabber: add csr and memory group for CXPGrabber
grabber: add CXPGrabber and user led to rtio_channel
grabber: add constraint for cd_cxp_gt_rx
2025-03-04 14:46:39 +08:00
bcab64f1ff gateware: add cxp_4r_fmc pinout 2025-03-04 14:46:39 +08:00
dfc731a4c1 flake: update dependencies 2025-03-04 14:46:39 +08:00
58ecf62921 libksupport: inline _resolve_channel_name helper
Signed-off-by: Simon Renblad <srenblad@m-labs.hk>
2025-03-04 14:19:50 +08:00
11134cdfd6 use MaybeUninit for LOGGER 2025-02-27 13:18:23 +08:00
2e99b9cf0d use MaybeUninit for I2C_BUS, create get_bus helper 2025-02-27 13:18:23 +08:00
4f79ee962c fix cargo-xbuild dependency 2025-02-17 15:15:33 +08:00
d4105b79e7 flake: update dependencies 2025-02-17 15:15:22 +08:00
1beb6fd944 cargo fmt 2025-02-13 17:46:15 +08:00
ce1c430fdc upgrade rustfmt required version 2025-02-13 17:45:29 +08:00
cf99700299 update cargo lockfile 2025-02-13 17:31:43 +08:00
9f1f349b29 export rust_eh_personality manually 2025-02-13 17:31:43 +08:00
98255ec25a prevent vectorizing copy_work_buffer 2025-02-13 17:31:43 +08:00
421033ef98 remove unused asm feature flag 2025-02-13 17:31:43 +08:00
c603a4ba12 remove allow incomplete features 2025-02-13 17:31:43 +08:00
529d7819a9 fix missing asm macro 2025-02-13 17:31:43 +08:00
1a1a7112ca silence target-feature warns 2025-02-13 17:31:43 +08:00
e524317eb9 bump to llvm14 2025-02-13 17:31:43 +08:00
d545feddbd flake: update dependencies 2025-02-13 17:31:28 +08:00
0e6da19406 ksupport: remove redundant enable_fpu 2025-02-11 20:16:24 +08:00
d0e2404311 flake: update zynq-rs 2025-02-11 20:15:55 +08:00
cd9f8e6d7c flake: update dependencies 2025-02-11 20:11:53 +08:00
4a2b28dcc3 flake: update dependencies 2025-02-06 20:16:34 +08:00
21a4a0b5dd core1: use C repr in attribute writeback 2025-02-06 14:34:18 +08:00
a82d356f52 flake: update dependencies 2025-02-05 16:58:48 +08:00
8b9bb38331 Do not apply offsets to null pointers 2025-02-03 12:04:02 +00:00
63157588bb flake: update dependencies 2025-01-15 21:17:34 +08:00
11f8675ad6 drtio: fix RTIO channel name resolution for remote channels 2025-01-15 13:12:14 +08:00
54 changed files with 2334 additions and 556 deletions

42
flake.lock generated
View File

@ -11,11 +11,11 @@
"src-pythonparser": "src-pythonparser"
},
"locked": {
"lastModified": 1734418848,
"narHash": "sha256-FiK84edtdmpJ3FUA58XAUmDDp4oVPgupmf1CcgJ6rC0=",
"lastModified": 1743144117,
"narHash": "sha256-LOh3KwjcEKcLA2vva6awAnMLUEyq4d+LPLCu7FwMAhw=",
"ref": "refs/heads/master",
"rev": "366bb0fc59dbe4d5f544908b0f3e31f8eb19f7c1",
"revCount": 9121,
"rev": "4ddad5fd17bb07fc754d764d3ff157300d27e109",
"revCount": 9204,
"type": "git",
"url": "https://github.com/m-labs/artiq.git"
},
@ -37,11 +37,11 @@
]
},
"locked": {
"lastModified": 1720768567,
"narHash": "sha256-3VoK7o5MtHtbHLrc6Pv+eQWFtaz5Gd/YWyV5TD3c5Ss=",
"lastModified": 1734270714,
"narHash": "sha256-7bzGn/hXLIsLQHGQsvo+uoIFUrw9DjXSlMC449BY4ME=",
"owner": "m-labs",
"repo": "artiq-comtools",
"rev": "f93570d8f2ed5a3cfb3e1c16ab00f2540551e994",
"rev": "7e3152314af8f5987370e33b347b2ec2697567ed",
"type": "github"
},
"original": {
@ -70,11 +70,11 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1733940404,
"narHash": "sha256-Pj39hSoUA86ZePPF/UXiYHHM7hMIkios8TYG29kQT4g=",
"lastModified": 1741851582,
"narHash": "sha256-cPfs8qMccim2RBgtKGF+x9IBCduRvd/N5F4nYpU0TVE=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "5d67ea6b4b63378b9c13be21e2ec9d1afc921713",
"rev": "6607cf789e541e7873d40d3a8f7815ea92204f32",
"type": "github"
},
"original": {
@ -158,11 +158,11 @@
"src-migen": {
"flake": false,
"locked": {
"lastModified": 1727677091,
"narHash": "sha256-Zg3SQnTwMM/VkOGKogbPyuCC2NhLy8HB2SPEUWWNgCU=",
"lastModified": 1738906518,
"narHash": "sha256-GproDJowtcgbccsT+I0mObzFhE483shcS8MSszKXwlc=",
"owner": "m-labs",
"repo": "migen",
"rev": "c19ae9f8ae162ffe2d310a92bfce53ac2a821bc8",
"rev": "2828df54594673653a641ab551caf6c6b1bfeee5",
"type": "github"
},
"original": {
@ -174,11 +174,11 @@
"src-misoc": {
"flake": false,
"locked": {
"lastModified": 1729234629,
"narHash": "sha256-TLsTCXV5AC2xh+bS7EhBVBKqdqIU3eKrnlWcFF9LtAM=",
"lastModified": 1741001607,
"narHash": "sha256-05BGqWV4Zc9ArwaW0uuBYWjg4oTeP4vznPQQjEpQPEM=",
"ref": "refs/heads/master",
"rev": "6085a312bca26adeca6584e37d08c8ba2e1d6e38",
"revCount": 2460,
"rev": "fa73f42f3c163833f17fc99399bb41005970c503",
"revCount": 2495,
"submodules": true,
"type": "git",
"url": "https://github.com/m-labs/misoc.git"
@ -229,11 +229,11 @@
"rust-overlay": "rust-overlay_2"
},
"locked": {
"lastModified": 1734668221,
"narHash": "sha256-X0U2yPmlsD3VLBZQyfWv8qw04Qn0qFWIONJUPPigB0U=",
"lastModified": 1743144882,
"narHash": "sha256-B1J8Ou/T8EDNcPVAu+c5bRiRUjoCiWCh6WNo60sRyDc=",
"ref": "refs/heads/master",
"rev": "213529cf7a50aa1b2d9ffdf575e3e38202ff9bd6",
"revCount": 666,
"rev": "c98c30c6565f0aa35a2f4ab31e5174f167714841",
"revCount": 696,
"type": "git",
"url": "https://git.m-labs.hk/m-labs/zynq-rs"
},

View File

@ -134,14 +134,14 @@
nativeBuildInputs = [
pkgs.gnumake
(pkgs.python3.withPackages(ps: [ ps.jsonschema artiqpkgs.migen migen-axi artiqpkgs.misoc artiqpkgs.artiq ]))
zynqpkgs.cargo-xbuild
pkgs.llvmPackages_13.llvm
pkgs.llvmPackages_13.clang-unwrapped
pkgs.cargo-xbuild
pkgs.llvmPackages_18.llvm
pkgs.llvmPackages_18.clang-unwrapped
];
buildPhase = ''
export ZYNQ_REV=${zynqRev}
export XARGO_RUST_SRC="${rust}/lib/rustlib/src/rust/library"
export CLANG_EXTRA_INCLUDE_DIR="${pkgs.llvmPackages_13.clang-unwrapped.lib}/lib/clang/13.0.1/include"
export CLANG_EXTRA_INCLUDE_DIR="${pkgs.llvmPackages_18.clang-unwrapped.lib}/lib/clang/18/include"
export CARGO_HOME=$(mktemp -d cargo-home.XXX)
export ZYNQ_RS=${zynq-rs}
make TARGET=${target} GWARGS="${if json == null then "-V ${variant}" else json}" ${fwtype}
@ -345,6 +345,7 @@
{
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"; }) //
@ -376,11 +377,11 @@
name = "artiq-zynq-dev-shell";
buildInputs = with pkgs; [
rust
llvmPackages_13.llvm
llvmPackages_13.clang-unwrapped
llvmPackages_18.llvm
llvmPackages_18.clang-unwrapped
gnumake
cacert
zynqpkgs.cargo-xbuild
pkgs.cargo-xbuild
zynqpkgs.mkbootimage
openocd
openssh rsync
@ -392,7 +393,7 @@
];
ZYNQ_REV="${zynqRev}";
XARGO_RUST_SRC = "${rust}/lib/rustlib/src/rust/library";
CLANG_EXTRA_INCLUDE_DIR = "${pkgs.llvmPackages_13.clang-unwrapped.lib}/lib/clang/13.0.1/include";
CLANG_EXTRA_INCLUDE_DIR = "${pkgs.llvmPackages_18.clang-unwrapped.lib}/lib/clang/18/include";
ZYNQ_RS = "${zynq-rs}";
OPENOCD_ZYNQ = "${zynq-rs}/openocd";
SZL = "${zynqpkgs.szl}";

View File

@ -1,7 +1,6 @@
[target.armv7-none-eabihf]
rustflags = [
"-C", "link-arg=-Tlink.x",
"-C", "target-feature=a9,armv7-a,neon",
"-C", "target-cpu=cortex-a9",
]

64
src/Cargo.lock generated
View File

@ -1,6 +1,6 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
version = 4
[[package]]
name = "approx"
@ -19,9 +19,9 @@ checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711"
[[package]]
name = "async-recursion"
version = "0.3.2"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7d78656ba01f1b93024b7c3a0467f1608e4be67d725749fdcd7d2c7678fd7a2"
checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11"
dependencies = [
"proc-macro2",
"quote",
@ -82,9 +82,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "compiler_builtins"
version = "0.1.49"
version = "0.1.108"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "20b1438ef42c655665a8ab2c1c6d605a305f031d38d9be689ddfef41a20f3aa2"
checksum = "d68bc55329711cd719c2687bb147bc06211b0521f97ef398280108ccb23227e9"
[[package]]
name = "core_io"
@ -148,9 +148,9 @@ dependencies = [
[[package]]
name = "futures"
version = "0.3.25"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38390104763dc37a5145a53c29c63c1290b5d316d6086ec32c293f6736051bb0"
checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876"
dependencies = [
"futures-channel",
"futures-core",
@ -162,9 +162,9 @@ dependencies = [
[[package]]
name = "futures-channel"
version = "0.3.25"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52ba265a92256105f45b719605a571ffe2d1f0fea3807304b522c1d778f79eed"
checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10"
dependencies = [
"futures-core",
"futures-sink",
@ -172,21 +172,21 @@ dependencies = [
[[package]]
name = "futures-core"
version = "0.3.25"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04909a7a7e4633ae6c4a9ab280aeb86da1236243a77b694a49eacd659a4bd3ac"
checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e"
[[package]]
name = "futures-io"
version = "0.3.25"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00f5fb52a06bdcadeb54e8d3671f8888a39697dcb0b81b23b55174030427f4eb"
checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6"
[[package]]
name = "futures-macro"
version = "0.3.25"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bdfb8ce053d86b91919aad980c220b1fb8401a9394410e1c289ed7e66b61835d"
checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
dependencies = [
"proc-macro2",
"quote",
@ -195,21 +195,21 @@ dependencies = [
[[package]]
name = "futures-sink"
version = "0.3.25"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39c15cf1a4aa79df40f1bb462fb39676d0ad9e366c2a33b590d7c66f4f81fcf9"
checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7"
[[package]]
name = "futures-task"
version = "0.3.25"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2ffb393ac5d9a6eaa9d3fdf37ae2776656b706e200c8e16b1bdb227f5198e6ea"
checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988"
[[package]]
name = "futures-util"
version = "0.3.25"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "197676987abd2f9cadff84926f410af1c183608d36641465df73ae8211dc65d6"
checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81"
dependencies = [
"futures-core",
"futures-macro",
@ -264,7 +264,6 @@ dependencies = [
"embedded-hal",
"libcortex_a9",
"nb 1.0.0",
"pin-utils",
"smoltcp",
]
@ -273,6 +272,7 @@ name = "libboard_artiq"
version = "0.0.0"
dependencies = [
"build_zynq",
"byteorder",
"core_io",
"crc",
"embedded-hal",
@ -426,9 +426,9 @@ dependencies = [
[[package]]
name = "num-derive"
version = "0.3.3"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d"
checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202"
dependencies = [
"proc-macro2",
"quote",
@ -457,9 +457,9 @@ dependencies = [
[[package]]
name = "num-traits"
version = "0.2.15"
version = "0.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
dependencies = [
"autocfg",
"libm",
@ -485,18 +485,18 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]]
name = "proc-macro2"
version = "1.0.43"
version = "1.0.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab"
checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.21"
version = "1.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179"
checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc"
dependencies = [
"proc-macro2",
]
@ -590,9 +590,9 @@ dependencies = [
[[package]]
name = "syn"
version = "1.0.101"
version = "2.0.98"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e90cde112c4b9690b8cbe810cba9ddd8bc1d7472e2cae317b69e9438c1cba7d2"
checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1"
dependencies = [
"proc-macro2",
"quote",

View File

@ -4,7 +4,7 @@
"emit-debug-gdb-scripts": false,
"env": "",
"executables": true,
"features": "+v7,+vfp3,-d32,+thumb2,-neon",
"features": "+v7,+vfp3,-d32,+thumb2,+neon,+a9,+armv7-a",
"is-builtin": false,
"linker": "rust-lld",
"linker-flavor": "ld.lld",

View File

@ -0,0 +1,74 @@
from migen.build.generic_platform import *
fmc_adapter_io = [
# CoaXPress high speed link
("CXP_HS", 0,
Subsignal("rxp", Pins("HPC:DP0_M2C_P")),
Subsignal("rxn", Pins("HPC:DP0_M2C_N")),
),
("CXP_HS", 1,
Subsignal("rxp", Pins("HPC:DP1_M2C_P")),
Subsignal("rxn", Pins("HPC:DP1_M2C_N")),
),
("CXP_HS", 2,
Subsignal("rxp", Pins("HPC:DP2_M2C_P")),
Subsignal("rxn", Pins("HPC:DP2_M2C_N")),
),
("CXP_HS", 3,
Subsignal("rxp", Pins("HPC:DP3_M2C_P")),
Subsignal("rxn", Pins("HPC:DP3_M2C_N")),
),
# CoaXPress low speed link
("CXP_LS", 0, Pins("HPC:LA00_CC_P"), IOStandard("LVCMOS33")),
("CXP_LS", 1, Pins("HPC:LA01_CC_N"), IOStandard("LVCMOS33")),
("CXP_LS", 2, Pins("HPC:LA01_CC_P"), IOStandard("LVCMOS33")),
("CXP_LS", 3, Pins("HPC:LA02_N"), IOStandard("LVCMOS33")),
# CoaXPress green and red LED
("CXP_LED", 0,
Subsignal("green", Pins("HPC:LA11_P"), IOStandard("LVCMOS33")),
Subsignal("red", Pins("HPC:LA11_N"), IOStandard("LVCMOS33")),
),
("CXP_LED", 1,
Subsignal("green", Pins("HPC:LA12_P"), IOStandard("LVCMOS33")),
Subsignal("red", Pins("HPC:LA12_N"), IOStandard("LVCMOS33")),
),
("CXP_LED", 2,
Subsignal("green", Pins("HPC:LA13_P"), IOStandard("LVCMOS33")),
Subsignal("red", Pins("HPC:LA13_N"), IOStandard("LVCMOS33")),
),
("CXP_LED", 3,
Subsignal("green", Pins("HPC:LA14_P"), IOStandard("LVCMOS33")),
Subsignal("red", Pins("HPC:LA14_N"), IOStandard("LVCMOS33")),
),
# Power over CoaXPress
("PoCXP", 0,
Subsignal("enable", Pins("HPC:LA21_N"), IOStandard("LVCMOS33")),
Subsignal("alert", Pins("HPC:LA18_CC_P"), IOStandard("LVCMOS33")),
),
("PoCXP", 1,
Subsignal("enable", Pins("HPC:LA21_P"), IOStandard("LVCMOS33")),
Subsignal("alert", Pins("HPC:LA19_N"), IOStandard("LVCMOS33")),
),
("PoCXP", 2,
Subsignal("enable", Pins("HPC:LA22_N"), IOStandard("LVCMOS33")),
Subsignal("alert", Pins("HPC:LA19_P"), IOStandard("LVCMOS33")),
),
("PoCXP", 3,
Subsignal("enable", Pins("HPC:LA22_P"), IOStandard("LVCMOS33")),
Subsignal("alert", Pins("HPC:LA20_N"), IOStandard("LVCMOS33")),
),
("i2c", 0,
Subsignal("scl", Pins("HPC:IIC_SCL")),
Subsignal("sda", Pins("HPC:IIC_SDA")),
IOStandard("LVCMOS33")
),
# On board 125MHz reference
("clk125", 0,
Subsignal("p", Pins("HPC:GBTCLK0_M2C_P")),
Subsignal("n", Pins("HPC:GBTCLK0_M2C_N")),
),
]

View File

@ -432,6 +432,7 @@ class GenericSatellite(SoCCore):
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
platform = kasli_soc.Platform()
@ -480,6 +481,8 @@ class GenericSatellite(SoCCore):
self.rtio_channels = []
has_grabber = any(peripheral["type"] == "grabber" for peripheral in description["peripherals"])
if has_drtio_over_eem:
self.eem_drtio_channels = []
if has_grabber:
self.grabber_csr_group = []
eem_7series.add_peripherals(self, description["peripherals"], iostandard=eem_iostandard)
@ -494,15 +497,15 @@ class GenericSatellite(SoCCore):
self.submodules.rtio_tsc = rtio.TSC(glbl_fine_ts_width=3)
drtioaux_csr_group = []
drtioaux_memory_group = []
drtiorep_csr_group = []
self.drtioaux_csr_group = []
self.drtioaux_memory_group = []
self.drtiorep_csr_group = []
self.drtio_cri = []
for i in range(len(self.gt_drtio.channels)):
coreaux_name = "drtioaux" + str(i)
memory_name = "drtioaux" + str(i) + "_mem"
drtioaux_csr_group.append(coreaux_name)
drtioaux_memory_group.append(memory_name)
self.drtioaux_csr_group.append(coreaux_name)
self.drtioaux_memory_group.append(memory_name)
cdr = ClockDomainsRenamer({"rtio_rx": "rtio_rx" + str(i)})
@ -515,7 +518,7 @@ class GenericSatellite(SoCCore):
self.csr_devices.append("drtiosat")
else:
corerep_name = "drtiorep" + str(i-1)
drtiorep_csr_group.append(corerep_name)
self.drtiorep_csr_group.append(corerep_name)
core = cdr(DRTIORepeater(
self.rtio_tsc, self.gt_drtio.channels[i]))
@ -538,9 +541,9 @@ class GenericSatellite(SoCCore):
self.add_memory_region(memory_name, self.mem_map["csr"] + memory_address, mem_size * 2)
self.config["HAS_DRTIO"] = None
self.config["HAS_DRTIO_ROUTING"] = None
self.add_csr_group("drtioaux", drtioaux_csr_group)
self.add_memory_group("drtioaux_mem", drtioaux_memory_group)
self.add_csr_group("drtiorep", drtiorep_csr_group)
if has_drtio_over_eem:
self.add_eem_drtio(self.eem_drtio_channels)
self.add_drtio_cpuif_groups()
if self.acpki:
self.config["KI_IMPL"] = "acp"
@ -625,6 +628,50 @@ class GenericSatellite(SoCCore):
self.comb += [self.virtual_leds.get(i).eq(channel.rx_ready)
for i, channel in enumerate(self.gt_drtio.channels)]
def add_eem_drtio(self, eem_drtio_channels):
# Must be called before constructing CRIInterconnectShared
self.submodules.eem_transceiver = eem_serdes.EEMSerdes(self.platform, eem_drtio_channels)
self.csr_devices.append("eem_transceiver")
self.config["HAS_DRTIO_EEM"] = None
self.config["EEM_DRTIO_COUNT"] = len(eem_drtio_channels)
for i in range(len(self.eem_transceiver.channels)):
channel = i + len(self.gt_drtio.channels)
coreaux_name = "drtioaux" + str(channel)
memory_name = "drtioaux" + str(channel) + "_mem"
self.drtioaux_csr_group.append(coreaux_name)
self.drtioaux_memory_group.append(memory_name)
cdr = ClockDomainsRenamer({"rtio_rx": "sys"})
corerep_name = "drtiorep" + str(channel-1)
self.drtiorep_csr_group.append(corerep_name)
core = cdr(DRTIORepeater(
self.rtio_tsc, self.eem_transceiver.channels[i]))
setattr(self.submodules, corerep_name, core)
self.drtio_cri.append(core.cri)
self.csr_devices.append(corerep_name)
coreaux = cdr(drtio_aux_controller.DRTIOAuxControllerBare(core.link_layer))
setattr(self.submodules, coreaux_name, coreaux)
self.csr_devices.append(coreaux_name)
mem_size = coreaux.get_mem_size()
tx_port = coreaux.get_tx_port()
rx_port = coreaux.get_rx_port()
memory_address = self.axi2csr.register_port(tx_port, mem_size)
# rcv in upper half of the memory, thus added second
self.axi2csr.register_port(rx_port, mem_size)
# and registered in PS interface
# manually, because software refers to rx/tx by halves of entire memory block, not names
self.add_memory_region(memory_name, self.mem_map["csr"] + memory_address, mem_size * 2)
def add_drtio_cpuif_groups(self):
self.add_csr_group("drtiorep", self.drtiorep_csr_group)
self.add_csr_group("drtioaux", self.drtioaux_csr_group)
self.add_memory_group("drtioaux_mem", self.drtioaux_memory_group)
def main():
parser = argparse.ArgumentParser(
description="ARTIQ device binary builder for generic Kasli-SoC systems")

View File

@ -13,7 +13,7 @@ from misoc.interconnect.csr import *
from misoc.cores import gpio
from artiq.gateware import rtio, nist_clock, nist_qc2
from artiq.gateware.rtio.phy import ttl_simple, ttl_serdes_7series, dds, spi2, edge_counter
from artiq.gateware.rtio.phy import ttl_simple, ttl_serdes_7series, dds, spi2, edge_counter, cxp_grabber
from artiq.gateware.rtio.xilinx_clocking import fix_serdes_timing_path
from artiq.gateware.drtio.transceiver import gtx_7series
from artiq.gateware.drtio.siphaser import SiPhaser7Series
@ -25,6 +25,7 @@ import analyzer
import acpki
import drtio_aux_controller
import zynq_clocking
import cxp_4r_fmc
from config import generate_ident, write_csr_file, write_mem_file, write_rustc_cfg_file
class SMAClkinForward(Module):
@ -138,7 +139,7 @@ class ZC706(SoCCore):
platform.add_extension(si5324_fmc33)
self.comb += platform.request("si5324_33").rst_n.eq(1)
cdr_clk = Signal()
self.cdr_clk = Signal()
cdr_clk_buf = Signal()
si5324_out = platform.request("si5324_clkout")
platform.add_period_constraint(si5324_out.p, 8.0)
@ -146,11 +147,11 @@ class ZC706(SoCCore):
Instance("IBUFDS_GTE2",
i_CEB=0,
i_I=si5324_out.p, i_IB=si5324_out.n,
o_O=cdr_clk,
o_O=self.cdr_clk,
p_CLKCM_CFG="TRUE",
p_CLKRCV_TRST="TRUE",
p_CLKSWING_CFG=3),
Instance("BUFG", i_I=cdr_clk, o_O=cdr_clk_buf)
Instance("BUFG", i_I=self.cdr_clk, o_O=cdr_clk_buf)
]
self.config["HAS_SI5324"] = None
self.config["SI5324_AS_SYNTHESIZER"] = None
@ -652,6 +653,56 @@ class _NIST_QC2_RTIO:
self.add_rtio(rtio_channels)
class _CXP_4R_FMC_RTIO():
"""
CoaXpress host FMC card
"""
def __init__(self):
platform = self.platform
platform.add_extension(cxp_4r_fmc.fmc_adapter_io)
platform.add_extension(leds_fmc33)
rtio_channels = []
clk_freq = 125e6
self.submodules.cxp_grabber = cxp_grabber.CXPGrabber(
refclk=self.cdr_clk,
tx_pads=[platform.request("CXP_LS", 0)],
rx_pads=[platform.request("CXP_HS", 0)],
sys_clk_freq=clk_freq,
)
mem_size = self.cxp_grabber.core.get_mem_size()
# upper half is tx while lower half is rx
memory_address = self.axi2csr.register_port(self.cxp_grabber.core.get_tx_port(), mem_size)
self.axi2csr.register_port(self.cxp_grabber.core.get_rx_port(), mem_size)
self.add_memory_region("cxp_mem", self.mem_map["csr"] + memory_address, mem_size * 2)
self.csr_devices.append("cxp_grabber")
print("CoaXPress at RTIO channel 0x{:06x}".format(len(rtio_channels)))
rtio_channels += [
rtio.Channel(self.cxp_grabber.trigger),
rtio.Channel(self.cxp_grabber.config),
rtio.Channel(self.cxp_grabber.gate_data),
]
# max freq of cxp_gt_rx = linerate/internal_datawidth = 12.5Gbps/40 = 312.5MHz
# zc706 use speed grade 2 which only support up to 10.3125Gbps (~4ns)
# pushing to 12.5Gbps (3.2ns) will result in Pulse width violation but setup/hold times will still meet
rx = self.cxp_grabber.phy_rx.phys[0]
platform.add_period_constraint(rx.gtx.cd_cxp_gt_rx.clk, 3.2)
# constraint the clk path
platform.add_false_path_constraints(self.sys_crg.cd_sys.clk, rx.gtx.cd_cxp_gt_rx.clk)
# Add a user LED for rtio moninj
print("USER LED at RTIO channel 0x{:06x}".format(len(rtio_channels)))
phy = ttl_simple.Output(self.platform.request("user_led_33", 0))
self.submodules += phy
rtio_channels.append(rtio.Channel.from_phy(phy))
self.config["HAS_RTIO_LOG"] = None
rtio_channels.append(rtio.LogChannel())
self.config["RTIO_LOG_CHANNEL"] = len(rtio_channels)
self.add_rtio(rtio_channels)
class NIST_CLOCK(ZC706, _NIST_CLOCK_RTIO):
def __init__(self, acpki, drtio100mhz):
ZC706.__init__(self, acpki)
@ -684,8 +735,13 @@ class NIST_QC2_Satellite(_SatelliteBase, _NIST_QC2_RTIO):
_SatelliteBase.__init__(self, acpki, drtio100mhz)
_NIST_QC2_RTIO.__init__(self)
class CXP_4R_FMC(ZC706, _CXP_4R_FMC_RTIO):
def __init__(self, acpki, drtio100mhz):
ZC706.__init__(self, acpki)
_CXP_4R_FMC_RTIO.__init__(self)
VARIANTS = {cls.__name__.lower(): cls for cls in [NIST_CLOCK, NIST_CLOCK_Master, NIST_CLOCK_Satellite,
NIST_QC2, NIST_QC2_Master, NIST_QC2_Satellite]}
NIST_QC2, NIST_QC2_Master, NIST_QC2_Satellite, CXP_4R_FMC]}
def main():
parser = argparse.ArgumentParser(

View File

@ -24,6 +24,7 @@ core_io = { git = "https://git.m-labs.hk/M-Labs/rs-core_io.git", rev = "e9d3edf0
embedded-hal = "0.2"
nb = "1.0"
void = { version = "1", default-features = false }
byteorder = { version = "1.3", default-features = false }
io = { path = "../libio", features = ["byteorder"] }
libboard_zynq = { path = "@@ZYNQ_RS@@/libboard_zynq" }

View File

@ -0,0 +1,305 @@
use core::fmt;
use embedded_hal::blocking::delay::DelayMs;
use libboard_zynq::{time::Milliseconds, timer::GlobalTimer};
use log::debug;
use crate::{cxp_ctrl::Error as CtrlErr,
cxp_packet::{read_u32, read_u64, reset_tag, send_test_packet, write_bytes_no_ack, write_u32, write_u64},
cxp_phys::{rx, tx, CXPSpeed},
pl::csr};
// Bootstrap registers address
const REVISION: u32 = 0x0004;
const CONNECTION_RESET: u32 = 0x4000;
const DEVICE_CONNECTION_ID: u32 = 0x4004;
const MASTER_HOST_CONNECTION_ID: u32 = 0x4008;
const STREAM_PACKET_SIZE_MAX: u32 = 0x4010;
const CONNECTION_CFG: u32 = 0x4014;
const CONNECTION_CFG_DEFAULT: u32 = 0x4018;
const TESTMODE: u32 = 0x401C;
const TEST_ERROR_COUNT_SELECTOR: u32 = 0x4020;
const TEST_ERROR_COUNT: u32 = 0x4024;
const TEST_PACKET_COUNT_TX: u32 = 0x4028;
const TEST_PACKET_COUNT_RX: u32 = 0x4030;
const VERSION_SUPPORTED: u32 = 0x4044;
const VERSION_USED: u32 = 0x4048;
// Setup const
const CHANNEL_LEN: u8 = 1;
const HOST_CONNECTION_ID: u32 = 0x00006303; // TODO: rename to CXP grabber sinara number when it comes out
// The MAX_STREAM_PAK_SIZE should be set as large as possible - Section 9.5.2 (CXP-001-2021)
// Since the ROI pipeline just consume all pixel data without buffering, any big number will do.
const MAX_STREAM_PAK_SIZE: u32 = 16384; // 16 KiB
const TX_TEST_CNT: u8 = 10;
// From DS191 (v1.18.1), max CDR time lock is 37*10^6 UI,
// 37*10^6 UI at lowest CXP linerate of 1.25Gbps = 29.6 ms, double it to account for overhead
const MONITOR_TIMEOUT_MS: u64 = 60;
pub enum Error {
CameraNotDetected,
ConnectionLost,
UnstableRX,
UnstableTX,
UnsupportedSpeed(u32),
UnsupportedTopology,
UnsupportedVersion,
CtrlPacketError(CtrlErr),
}
impl From<CtrlErr> for Error {
fn from(value: CtrlErr) -> Error {
Error::CtrlPacketError(value)
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&Error::CameraNotDetected => write!(f, "CameraNotDetected"),
&Error::ConnectionLost => write!(f, "ConnectionLost - Channel #0 cannot be detected"),
&Error::UnstableRX => write!(f, "UnstableRX - RX connection test failed"),
&Error::UnstableTX => write!(f, "UnstableTX - TX connection test failed"),
&Error::UnsupportedSpeed(linerate_code) => write!(
f,
"UnsupportedSpeed - {:#X} linerate code is not supported",
linerate_code
),
&Error::UnsupportedTopology => {
write!(
f,
"UnsupportedTopology - Channel #0 should be connected to the master channel"
)
}
&Error::UnsupportedVersion => write!(
f,
"UnsupportedVersion - Cannot find a compatible protocol version between the cxp grabber & camera"
),
&Error::CtrlPacketError(ref err) => write!(f, "{}", err),
}
}
}
pub fn master_channel_ready() -> bool {
unsafe { csr::cxp_grabber::core_rx_ready_read() == 1 }
}
fn monitor_channel_status_timeout(timer: GlobalTimer) -> Result<(), Error> {
let limit = timer.get_time() + Milliseconds(MONITOR_TIMEOUT_MS);
while timer.get_time() < limit {
if master_channel_ready() {
return Ok(());
}
}
Err(Error::ConnectionLost)
}
pub fn discover_camera(mut timer: GlobalTimer) -> Result<(), Error> {
// Section 7.6 (CXP-001-2021)
// 1.25Gbps (CXP_1) and 3.125Gbps (CXP_3) are the discovery rate
// both linerate need to be checked as camera only support ONE of discovery rates
for speed in [CXPSpeed::CXP1, CXPSpeed::CXP3].iter() {
// Section 12.1.2 (CXP-001-2021)
// set tx linerate -> send ConnectionReset -> wait 200ms -> set rx linerate -> monitor connection status with a timeout
tx::change_linerate(*speed);
write_bytes_no_ack(CONNECTION_RESET, &1_u32.to_be_bytes(), false)?;
timer.delay_ms(200);
rx::change_linerate(*speed);
if monitor_channel_status_timeout(timer).is_ok() {
debug!("camera detected at linerate {:}", speed);
return Ok(());
}
}
Err(Error::CameraNotDetected)
}
fn check_master_channel() -> Result<(), Error> {
if read_u32(DEVICE_CONNECTION_ID, false)? == 0 {
Ok(())
} else {
Err(Error::UnsupportedTopology)
}
}
fn disable_excess_channels(timer: GlobalTimer) -> Result<(), Error> {
let current_cfg = read_u32(CONNECTION_CFG, false)?;
let active_camera_chs = current_cfg >> 16;
// After camera receive ConnectionReset, only the master connection should be active while
// the extension connections shall not be active - Section 12.3.33 (CXP-001-2021)
// In case some camera didn't follow the spec properly (e.g. Basler boA2448-250cm),
// the grabber need to manually disable the excess channels
if active_camera_chs > CHANNEL_LEN as u32 {
debug!(
"only {} channel(s) is available on cxp grabber, disabling excess channels on camera",
CHANNEL_LEN
);
// disable excess channels and preserve the discovery linerate
write_u32(CONNECTION_CFG, current_cfg & 0xFFFF | (CHANNEL_LEN as u32) << 16, false)?;
// check if the master channel is down after the cfg change
monitor_channel_status_timeout(timer)
} else {
Ok(())
}
}
fn set_host_connection_id() -> Result<(), Error> {
debug!("set host connection id to = {:#X}", HOST_CONNECTION_ID);
write_u32(MASTER_HOST_CONNECTION_ID, HOST_CONNECTION_ID, false)?;
Ok(())
}
fn negotiate_cxp_version() -> Result<bool, Error> {
let rev = read_u32(REVISION, false)?;
let mut major_rev: u32 = rev >> 16;
let mut minor_rev: u32 = rev & 0xFF;
debug!("camera's CoaXPress revision is {}.{}", major_rev, minor_rev);
// Section 12.1.4 (CXP-001-2021)
// For CXP 2.0 and onward, Host need to check the VersionSupported register to determine
// the highest common version that supported by both device & host
if major_rev >= 2 {
let reg = read_u32(VERSION_SUPPORTED, false)?;
// grabber support CXP 2.1, 2.0 and 1.1 only
if ((reg >> 3) & 1) == 1 {
major_rev = 2;
minor_rev = 1;
} else if ((reg >> 2) & 1) == 1 {
major_rev = 2;
minor_rev = 0;
} else if ((reg >> 1) & 1) == 1 {
major_rev = 1;
minor_rev = 1;
} else {
return Err(Error::UnsupportedVersion);
}
write_u32(VERSION_USED, major_rev << 16 | minor_rev, false)?;
}
debug!(
"both camera and cxp grabber support CoaXPress {}.{}, switch to CoaXPress {}.{} protocol now",
major_rev, minor_rev, major_rev, minor_rev
);
Ok(major_rev >= 2)
}
fn negotiate_pak_max_size(with_tag: bool) -> Result<(), Error> {
write_u32(STREAM_PACKET_SIZE_MAX, MAX_STREAM_PAK_SIZE, with_tag)?;
Ok(())
}
fn decode_cxp_speed(linerate_code: u32) -> Option<CXPSpeed> {
match linerate_code {
0x28 => Some(CXPSpeed::CXP1),
0x30 => Some(CXPSpeed::CXP2),
0x38 => Some(CXPSpeed::CXP3),
0x40 => Some(CXPSpeed::CXP5),
0x48 => Some(CXPSpeed::CXP6),
0x50 => Some(CXPSpeed::CXP10),
0x58 => Some(CXPSpeed::CXP12),
_ => None,
}
}
fn set_operation_linerate(with_tag: bool, timer: GlobalTimer) -> Result<(), Error> {
let recommended_linerate_code = read_u32(CONNECTION_CFG_DEFAULT, with_tag)? & 0xFFFF;
if let Some(speed) = decode_cxp_speed(recommended_linerate_code) {
debug!("changing linerate to {}", speed);
// preserve the number of active channels
let current_cfg = read_u32(CONNECTION_CFG, with_tag)?;
write_u32(
CONNECTION_CFG,
current_cfg & 0xFFFF0000 | recommended_linerate_code,
with_tag,
)?;
tx::change_linerate(speed);
rx::change_linerate(speed);
monitor_channel_status_timeout(timer)
} else {
Err(Error::UnsupportedSpeed(recommended_linerate_code))
}
}
fn test_counter_reset(with_tag: bool) -> Result<(), Error> {
unsafe { csr::cxp_grabber::core_rx_test_counts_reset_write(1) };
write_u32(TEST_ERROR_COUNT_SELECTOR, 0, with_tag)?;
write_u32(TEST_ERROR_COUNT, 0, with_tag)?;
write_u64(TEST_PACKET_COUNT_TX, 0, with_tag)?;
write_u64(TEST_PACKET_COUNT_RX, 0, with_tag)?;
Ok(())
}
fn verify_test_result(with_tag: bool) -> Result<(), Error> {
write_u32(TEST_ERROR_COUNT_SELECTOR, 0, with_tag)?;
// Section 9.9.3 (CXP-001-2021)
// verify grabber -> camera connection test result
if read_u64(TEST_PACKET_COUNT_RX, with_tag)? != TX_TEST_CNT as u64 {
return Err(Error::UnstableTX);
};
if read_u32(TEST_ERROR_COUNT, with_tag)? > 0 {
return Err(Error::UnstableTX);
};
// Section 9.9.4 (CXP-001-2021)
// verify camera -> grabber connection test result
let camera_test_pak_cnt = read_u64(TEST_PACKET_COUNT_TX, true)?;
unsafe {
if csr::cxp_grabber::core_rx_test_packet_counter_read() != camera_test_pak_cnt as u16 {
return Err(Error::UnstableRX);
};
if csr::cxp_grabber::core_rx_test_error_counter_read() > 0 {
return Err(Error::UnstableRX);
};
};
debug!("channel #0 passed connection test");
Ok(())
}
fn test_channel_stability(with_tag: bool, mut timer: GlobalTimer) -> Result<(), Error> {
test_counter_reset(with_tag)?;
// cxp grabber -> camera connection test
for _ in 0..TX_TEST_CNT {
send_test_packet()?;
// sending the whole test sequence @ 20.833Mbps will take a minimum of 1.972ms
// and leave some room to send IDLE word
timer.delay_ms(2);
}
// camera -> grabber connection test
// enabling the TESTMODE on master channel will send test packets on all channels
// and ctrl packet write overhead is used as a delay
write_u32(TESTMODE, 1, with_tag)?;
write_u32(TESTMODE, 0, with_tag)?;
verify_test_result(with_tag)?;
Ok(())
}
pub fn camera_setup(timer: GlobalTimer) -> Result<bool, Error> {
reset_tag();
check_master_channel()?;
disable_excess_channels(timer)?;
set_host_connection_id()?;
let with_tag = negotiate_cxp_version()?;
negotiate_pak_max_size(with_tag)?;
set_operation_linerate(with_tag, timer)?;
test_channel_stability(with_tag, timer)?;
Ok(with_tag)
}

View File

@ -0,0 +1,250 @@
use core::fmt;
use byteorder::{ByteOrder, NetworkEndian};
use core_io::{Error as IoError, Read, Write};
use crc::crc32::checksum_ieee;
use io::{Cursor, ProtoRead, ProtoWrite};
pub const CTRL_PACKET_MAXSIZE: usize = 128; // for compatibility with version1.x compliant Devices - Section 12.1.6 (CXP-001-2021)
pub const DATA_MAXSIZE: usize =
CTRL_PACKET_MAXSIZE - /*packet start KCodes, data packet types, CMD, Tag, Addr, CRC, packet end KCode*/4*7;
pub enum Error {
CorruptedPacket,
CtrlAckError(u8),
Io(IoError),
LengthOutOfRange(u32),
TagMismatch,
TimedOut,
UnexpectedReply,
UnknownPacket(u8),
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&Error::CorruptedPacket => write!(f, "CorruptedPacket - Received packet fail CRC test"),
&Error::CtrlAckError(ref ack_code) => match ack_code {
0x40 => write!(f, "CtrlAckError - Invalid Address"),
0x41 => write!(f, "CtrlAckError - Invalid data for the address"),
0x42 => write!(f, "CtrlAckError - Invalid operation code"),
0x43 => write!(f, "CtrlAckError - Write attempted to a read-only address"),
0x44 => write!(f, "CtrlAckError - Read attempted from a write-only address"),
0x45 => write!(f, "CtrlAckError - Size field too large, exceed packet size limit"),
0x46 => write!(f, "CtrlAckError - Message size is inconsistent with size field"),
0x47 => write!(f, "CtrlAckError - Malformed packet"),
0x80 => write!(f, "CtrlAckError - Failed CRC test in last received command"),
_ => write!(f, "CtrlAckError - Unknown ack code {:#X}", ack_code),
},
&Error::Io(ref err) => write!(f, "IoError - {:?}", err),
&Error::LengthOutOfRange(length) => write!(
f,
"LengthOutOfRange - Message length {} is not between 1 and {}",
length, DATA_MAXSIZE
),
&Error::TagMismatch => write!(f, "TagMismatch - Received tag is different from the transmitted tag"),
&Error::TimedOut => write!(f, "MessageTimedOut"),
&Error::UnexpectedReply => write!(f, "UnexpectedReply"),
&Error::UnknownPacket(packet_type) => {
write!(f, "UnknownPacket - Unknown packet type id {:#X} ", packet_type)
}
}
}
}
impl From<IoError> for Error {
fn from(value: IoError) -> Error {
Error::Io(value)
}
}
fn get_cxp_crc(bytes: &[u8]) -> u32 {
// Section 9.2.2.2 (CXP-001-2021)
// Only Control packet need CRC32 appended in the end of the packet
// CoaXpress use the polynomial of IEEE-802.3 (Ethernet) CRC but the checksum calculation is different
(!checksum_ieee(bytes)).swap_bytes()
}
trait CxpRead: Read {
fn read_exact_4x(&mut self, buf: &mut [u8]) -> Result<(), Error> {
let mut temp = [0u8; 4];
for byte in buf {
// Section 9.2.2.1 (CXP-001-2021)
// decoder should immune to single bit errors when handling 4x duplicated characters
self.read_exact(&mut temp)?;
let [a, b, c, d] = temp;
// vote and return majority
*byte = a & b & c | a & b & d | a & c & d | b & c & d;
}
Ok(())
}
fn read_4x_u8(&mut self) -> Result<u8, Error> {
let mut bytes = [0; 1];
self.read_exact_4x(&mut bytes)?;
Ok(bytes[0])
}
}
impl<T: Read> CxpRead for T {}
impl<T: Write> CxpWrite for T {}
#[derive(Debug)]
pub enum RXCTRLPacket {
CtrlReply {
tag: Option<u8>,
length: u32,
data: [u8; DATA_MAXSIZE],
},
CtrlDelay {
tag: Option<u8>,
time: u32,
},
CtrlAck {
tag: Option<u8>,
},
}
impl RXCTRLPacket {
pub fn read_from(reader: &mut Cursor<&[u8]>) -> Result<Self, Error> {
match reader.read_4x_u8()? {
0x03 => RXCTRLPacket::get_ctrl_packet(reader, false),
0x06 => RXCTRLPacket::get_ctrl_packet(reader, true),
ty => Err(Error::UnknownPacket(ty)),
}
}
fn get_ctrl_packet(reader: &mut Cursor<&[u8]>, with_tag: bool) -> Result<Self, Error> {
let mut tag: Option<u8> = None;
if with_tag {
tag = Some(reader.read_4x_u8()?);
}
let ackcode = reader.read_4x_u8()?;
match ackcode {
0x00 | 0x04 => {
let length = reader.read_u32::<NetworkEndian>()?;
let mut data: [u8; DATA_MAXSIZE] = [0; DATA_MAXSIZE];
reader.read(&mut data[0..length as usize])?;
// Section 9.6.3 (CXP-001-2021)
// when length is not multiple of 4, dummy bits are padded to align to the word boundary
// set position to next word boundary for CRC calculation
let padding = (4 - (reader.position() % 4)) % 4;
reader.set_position(reader.position() + padding);
// Section 9.6.3 (CXP-001-2021)
// only bytes after the first 4 are used in calculating the checksum
let checksum = get_cxp_crc(&reader.get_ref()[4..reader.position()]);
if reader.read_u32::<NetworkEndian>()? != checksum {
return Err(Error::CorruptedPacket);
}
if ackcode == 0x00 {
return Ok(RXCTRLPacket::CtrlReply { tag, length, data });
} else {
return Ok(RXCTRLPacket::CtrlDelay {
tag,
time: NetworkEndian::read_u32(&data[..4]),
});
}
}
0x01 => return Ok(RXCTRLPacket::CtrlAck { tag }),
_ => return Err(Error::CtrlAckError(ackcode)),
}
}
}
trait CxpWrite: Write {
fn write_all_4x(&mut self, buf: &[u8]) -> Result<(), Error> {
for byte in buf {
self.write_all(&[*byte; 4])?;
}
Ok(())
}
fn write_4x_u8(&mut self, value: u8) -> Result<(), Error> {
self.write_all_4x(&[value])
}
}
#[derive(Debug)]
pub enum TXCTRLPacket {
CtrlRead {
tag: Option<u8>,
addr: u32,
length: u32,
},
CtrlWrite {
tag: Option<u8>,
addr: u32,
length: u32,
data: [u8; DATA_MAXSIZE],
},
}
impl TXCTRLPacket {
pub fn write_to(&self, writer: &mut Cursor<&mut [u8]>) -> Result<(), Error> {
match *self {
TXCTRLPacket::CtrlRead { tag, addr, length } => {
match tag {
Some(t) => {
writer.write_4x_u8(0x05)?;
writer.write_4x_u8(t)?;
}
None => {
writer.write_4x_u8(0x02)?;
}
}
let mut bytes = [0; 3];
NetworkEndian::write_u24(&mut bytes, length);
writer.write_all(&[0x00, bytes[0], bytes[1], bytes[2]])?;
writer.write_u32::<NetworkEndian>(addr)?;
// Section 9.6.2 (CXP-001-2021)
// only bytes after the first 4 are used in calculating the checksum
let checksum = get_cxp_crc(&writer.get_ref()[4..writer.position()]);
writer.write_u32::<NetworkEndian>(checksum)?;
}
TXCTRLPacket::CtrlWrite {
tag,
addr,
length,
data,
} => {
match tag {
Some(t) => {
writer.write_4x_u8(0x05)?;
writer.write_4x_u8(t)?;
}
None => {
writer.write_4x_u8(0x02)?;
}
}
let mut bytes = [0; 3];
NetworkEndian::write_u24(&mut bytes, length);
writer.write_all(&[0x01, bytes[0], bytes[1], bytes[2]])?;
writer.write_u32::<NetworkEndian>(addr)?;
writer.write_all(&data[0..length as usize])?;
// Section 9.6.2 (CXP-001-2021)
// when length is not multiple of 4, dummy bites are padded to align to the word boundary
let padding = (4 - (writer.position() % 4)) % 4;
for _ in 0..padding {
writer.write_u8(0)?;
}
// Section 9.6.2 (CXP-001-2021)
// only bytes after the first 4 are used in calculating the checksum
let checksum = get_cxp_crc(&writer.get_ref()[4..writer.position()]);
writer.write_u32::<NetworkEndian>(checksum)?;
}
}
Ok(())
}
}

View File

@ -0,0 +1,90 @@
use libboard_zynq::timer::GlobalTimer;
use libcortex_a9::mutex::Mutex;
use log::{error, info};
use crate::{cxp_camera_setup::{camera_setup, discover_camera, master_channel_ready},
pl::csr};
#[derive(Clone, Copy, Debug, PartialEq)]
enum State {
Connected,
Detected,
Disconnected,
}
// Mutex as they are needed by core1 cxp api calls
static mut STATE: Mutex<State> = Mutex::new(State::Disconnected);
static mut WITH_TAG: Mutex<bool> = Mutex::new(false);
pub fn camera_connected() -> bool {
unsafe { *STATE.lock() == State::Connected }
}
pub fn with_tag() -> bool {
unsafe { *WITH_TAG.lock() }
}
pub fn tick(timer: GlobalTimer) {
let mut state_guard = unsafe { STATE.lock() };
let mut with_tag_guard = unsafe { WITH_TAG.lock() };
*state_guard = match *state_guard {
State::Disconnected => match discover_camera(timer) {
Ok(_) => {
info!("camera detected, setting up camera...");
State::Detected
}
Err(_) => State::Disconnected,
},
State::Detected => match camera_setup(timer) {
Ok(with_tag) => {
info!("camera setup complete");
*with_tag_guard = with_tag;
State::Connected
}
Err(e) => {
error!("camera setup failure: {}", e);
*with_tag_guard = false;
State::Disconnected
}
},
State::Connected => {
if master_channel_ready() {
unsafe {
if csr::cxp_grabber::stream_decoder_crc_error_read() == 1 {
error!("frame packet has CRC error");
csr::cxp_grabber::stream_decoder_crc_error_write(1);
};
if csr::cxp_grabber::stream_decoder_stream_type_error_read() == 1 {
error!("Non CoaXPress stream type detected, the CXP grabber doesn't support GenDC stream type");
csr::cxp_grabber::stream_decoder_stream_type_error_write(1);
};
if csr::cxp_grabber::core_rx_trigger_ack_read() == 1 {
info!("received CXP linktrigger ack");
csr::cxp_grabber::core_rx_trigger_ack_write(1);
};
if csr::cxp_grabber::stream_decoder_new_frame_read() == 1 {
let width = csr::cxp_grabber::stream_decoder_x_size_read();
let height = csr::cxp_grabber::stream_decoder_y_size_read();
match csr::cxp_grabber::stream_decoder_pixel_format_code_read() {
0x0101 => info!("received frame: {}x{} with MONO8 format", width, height),
0x0102 => info!("received frame: {}x{} with MONO10 format", width, height),
0x0103 => info!("received frame: {}x{} with MONO12 format", width, height),
0x0104 => info!("received frame: {}x{} with MONO14 format", width, height),
0x0105 => info!("received frame: {}x{} with MONO16 format", width, height),
_ => info!("received frame: {}x{} with Unsupported pixel format", width, height),
};
csr::cxp_grabber::stream_decoder_new_frame_write(1);
};
}
State::Connected
} else {
*with_tag_guard = false;
info!("camera disconnected");
State::Disconnected
}
}
};
}

View File

@ -0,0 +1,192 @@
use core::slice;
use byteorder::{ByteOrder, NetworkEndian};
use io::Cursor;
use libboard_zynq::{time::Milliseconds, timer::GlobalTimer};
use crate::{cxp_ctrl::{Error, RXCTRLPacket, TXCTRLPacket, CTRL_PACKET_MAXSIZE, DATA_MAXSIZE},
mem::mem,
pl::csr};
const TRANSMISSION_TIMEOUT: u64 = 200;
// Section 9.6.1.2 (CXP-001-2021)
// CTRL packet need to be tagged for CXP 2.0 or greater
static mut TAG: u8 = 0;
pub fn reset_tag() {
unsafe { TAG = 0 };
}
fn increment_tag() {
unsafe { TAG = TAG.wrapping_add(1) };
}
fn check_tag(tag: Option<u8>) -> Result<(), Error> {
unsafe {
if tag.is_some() && tag != Some(TAG) {
Err(Error::TagMismatch)
} else {
Ok(())
}
}
}
fn receive_ctrl_packet() -> Result<Option<RXCTRLPacket>, Error> {
if unsafe { csr::cxp_grabber::core_rx_pending_packet_read() == 1 } {
unsafe {
let read_buffer_ptr = csr::cxp_grabber::core_rx_read_ptr_read() as usize;
let ptr = (mem::CXP_MEM_BASE + mem::CXP_MEM_SIZE / 2 + read_buffer_ptr * CTRL_PACKET_MAXSIZE) as *mut u32;
let mut reader = Cursor::new(slice::from_raw_parts(ptr as *const u8, CTRL_PACKET_MAXSIZE));
let packet = RXCTRLPacket::read_from(&mut reader);
csr::cxp_grabber::core_rx_pending_packet_write(1);
Ok(Some(packet?))
}
} else {
Ok(None)
}
}
fn receive_ctrl_packet_timeout(timeout_ms: u64) -> Result<RXCTRLPacket, Error> {
// assume timer was initialized successfully
let timer = unsafe { GlobalTimer::get() };
let limit = timer.get_time() + Milliseconds(timeout_ms);
while timer.get_time() < limit {
match receive_ctrl_packet()? {
None => (),
Some(packet) => return Ok(packet),
}
}
Err(Error::TimedOut)
}
fn send_ctrl_packet(packet: &TXCTRLPacket) -> Result<(), Error> {
unsafe {
while csr::cxp_grabber::core_tx_writer_busy_read() == 1 {}
let ptr = mem::CXP_MEM_BASE as *mut u32;
let mut writer = Cursor::new(slice::from_raw_parts_mut(ptr as *mut u8, CTRL_PACKET_MAXSIZE));
packet.write_to(&mut writer)?;
csr::cxp_grabber::core_tx_writer_word_len_write((writer.position() / 4) as u8);
csr::cxp_grabber::core_tx_writer_stb_write(1);
}
Ok(())
}
pub fn send_test_packet() -> Result<(), Error> {
unsafe {
while csr::cxp_grabber::core_tx_writer_busy_read() == 1 {}
csr::cxp_grabber::core_tx_writer_stb_testseq_write(1);
}
Ok(())
}
fn get_ctrl_ack(timeout: u64) -> Result<(), Error> {
match receive_ctrl_packet_timeout(timeout) {
Ok(RXCTRLPacket::CtrlAck { tag }) => {
check_tag(tag)?;
Ok(())
}
Ok(RXCTRLPacket::CtrlDelay { tag, time }) => {
check_tag(tag)?;
get_ctrl_ack(time as u64)
}
Ok(_) => Err(Error::UnexpectedReply),
Err(e) => Err(e),
}
}
fn get_ctrl_reply(timeout: u64, expected_length: u32) -> Result<[u8; DATA_MAXSIZE], Error> {
match receive_ctrl_packet_timeout(timeout) {
Ok(RXCTRLPacket::CtrlReply { tag, length, data }) => {
check_tag(tag)?;
if length != expected_length {
return Err(Error::UnexpectedReply);
};
Ok(data)
}
Ok(RXCTRLPacket::CtrlDelay { tag, time }) => {
check_tag(tag)?;
get_ctrl_reply(time as u64, expected_length)
}
Ok(_) => Err(Error::UnexpectedReply),
Err(e) => Err(e),
}
}
fn check_length(length: u32) -> Result<(), Error> {
if length > DATA_MAXSIZE as u32 || length == 0 {
Err(Error::LengthOutOfRange(length))
} else {
Ok(())
}
}
pub fn write_bytes_no_ack(addr: u32, val: &[u8], with_tag: bool) -> Result<(), Error> {
let length = val.len() as u32;
check_length(length)?;
let mut data: [u8; DATA_MAXSIZE] = [0; DATA_MAXSIZE];
data[..length as usize].clone_from_slice(val);
let tag: Option<u8> = if with_tag { Some(unsafe { TAG }) } else { None };
send_ctrl_packet(&TXCTRLPacket::CtrlWrite {
tag,
addr,
length,
data,
})
}
pub fn write_bytes(addr: u32, val: &[u8], with_tag: bool) -> Result<(), Error> {
write_bytes_no_ack(addr, val, with_tag)?;
get_ctrl_ack(TRANSMISSION_TIMEOUT)?;
if with_tag {
increment_tag();
};
Ok(())
}
pub fn write_u32(addr: u32, val: u32, with_tag: bool) -> Result<(), Error> {
write_bytes(addr, &val.to_be_bytes(), with_tag)
}
pub fn write_u64(addr: u32, val: u64, with_tag: bool) -> Result<(), Error> {
write_bytes(addr, &val.to_be_bytes(), with_tag)
}
pub fn read_bytes(addr: u32, bytes: &mut [u8], with_tag: bool) -> Result<(), Error> {
let length = bytes.len() as u32;
check_length(length)?;
let tag: Option<u8> = if with_tag { Some(unsafe { TAG }) } else { None };
send_ctrl_packet(&TXCTRLPacket::CtrlRead { tag, addr, length })?;
let data = get_ctrl_reply(TRANSMISSION_TIMEOUT, length)?;
bytes.clone_from_slice(&data[..length as usize]);
if with_tag {
increment_tag();
};
Ok(())
}
pub fn read_u32(addr: u32, with_tag: bool) -> Result<u32, Error> {
let mut bytes: [u8; 4] = [0; 4];
read_bytes(addr, &mut bytes, with_tag)?;
let val = NetworkEndian::read_u32(&bytes);
Ok(val)
}
pub fn read_u64(addr: u32, with_tag: bool) -> Result<u64, Error> {
let mut bytes: [u8; 8] = [0; 8];
read_bytes(addr, &mut bytes, with_tag)?;
let val = NetworkEndian::read_u64(&bytes);
Ok(val)
}

View File

@ -0,0 +1,193 @@
use core::fmt;
use crate::pl::csr;
#[derive(Clone, Copy)]
pub enum CXPSpeed {
CXP1,
CXP2,
CXP3,
CXP5,
CXP6,
CXP10,
CXP12,
}
impl fmt::Display for CXPSpeed {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&CXPSpeed::CXP1 => write!(f, "1.25 Gbps"),
&CXPSpeed::CXP2 => write!(f, "2.5 Gbps"),
&CXPSpeed::CXP3 => write!(f, "3.125 Gbps"),
&CXPSpeed::CXP5 => write!(f, "5 Gbps"),
&CXPSpeed::CXP6 => write!(f, "6.25 Gbps"),
&CXPSpeed::CXP10 => write!(f, "10 Gbps"),
&CXPSpeed::CXP12 => write!(f, "12.5 Gbps"),
}
}
}
pub fn setup() {
let init_speed = CXPSpeed::CXP1;
tx::setup();
tx::change_linerate(init_speed);
rx::setup();
rx::change_linerate(init_speed);
}
pub mod tx {
use super::*;
pub fn setup() {
unsafe {
csr::cxp_grabber::phy_tx_enable_write(1);
}
}
pub fn change_linerate(speed: CXPSpeed) {
unsafe {
match speed {
CXPSpeed::CXP1 | CXPSpeed::CXP2 | CXPSpeed::CXP3 | CXPSpeed::CXP5 | CXPSpeed::CXP6 => {
csr::cxp_grabber::phy_tx_bitrate2x_enable_write(0);
}
CXPSpeed::CXP10 | CXPSpeed::CXP12 => {
csr::cxp_grabber::phy_tx_bitrate2x_enable_write(1);
}
};
csr::cxp_grabber::phy_tx_clk_reset_write(1);
}
}
}
pub mod rx {
use super::*;
pub fn setup() {
unsafe {
csr::cxp_grabber::phy_rx_gtx_refclk_stable_write(1);
}
}
pub fn change_linerate(speed: CXPSpeed) {
change_qpll_fb_divider(speed);
change_gtx_divider(speed);
change_cdr_cfg(speed);
unsafe {
csr::cxp_grabber::phy_rx_qpll_reset_write(1);
while csr::cxp_grabber::phy_rx_qpll_locked_read() != 1 {}
// Changing RXOUT_DIV via DRP requires a manual reset
// https://adaptivesupport.amd.com/s/question/0D52E00006hplwnSAA/re-gtx-line-rate-change
csr::cxp_grabber::phy_rx_gtx_restart_write(1);
}
}
fn change_qpll_fb_divider(speed: CXPSpeed) {
let qpll_div_reg = match speed {
CXPSpeed::CXP1 | CXPSpeed::CXP2 | CXPSpeed::CXP5 | CXPSpeed::CXP10 => 0x0120, // FB_Divider = 80, QPLL VCO @ 10GHz
CXPSpeed::CXP3 | CXPSpeed::CXP6 | CXPSpeed::CXP12 => 0x0170, // FB_Divider = 100, QPLL VCO @ 12.5GHz
};
qpll_write(0x36, qpll_div_reg);
}
fn change_gtx_divider(speed: CXPSpeed) {
let div_reg = match speed {
CXPSpeed::CXP1 => 0x33, // RXOUT_DIV = 8
CXPSpeed::CXP2 | CXPSpeed::CXP3 => 0x22, // RXOUT_DIV = 4
CXPSpeed::CXP5 | CXPSpeed::CXP6 => 0x11, // RXOUT_DIV = 2
CXPSpeed::CXP10 | CXPSpeed::CXP12 => 0x00, // RXOUT_DIV = 1
};
gtx_write(0x88, div_reg);
}
fn change_cdr_cfg(speed: CXPSpeed) {
struct CdrConfig {
pub cfg_reg0: u16, // addr = 0xA8
pub cfg_reg1: u16, // addr = 0xA9
pub cfg_reg2: u16, // addr = 0xAA
pub cfg_reg3: u16, // addr = 0xAB
pub cfg_reg4: u16, // addr = 0xAC
}
let cdr_cfg = match speed {
// when RXOUT_DIV = 8
CXPSpeed::CXP1 => CdrConfig {
cfg_reg0: 0x0020,
cfg_reg1: 0x1008,
cfg_reg2: 0x23FF,
cfg_reg3: 0x0000,
cfg_reg4: 0x0003,
},
// when RXOUT_DIV = 4
CXPSpeed::CXP2 | CXPSpeed::CXP5 => CdrConfig {
cfg_reg0: 0x0020,
cfg_reg1: 0x1010,
cfg_reg2: 0x23FF,
cfg_reg3: 0x0000,
cfg_reg4: 0x0003,
},
// when RXOUT_DIV= 2
CXPSpeed::CXP3 | CXPSpeed::CXP6 => CdrConfig {
cfg_reg0: 0x0020,
cfg_reg1: 0x1020,
cfg_reg2: 0x23FF,
cfg_reg3: 0x0000,
cfg_reg4: 0x0003,
},
// when RXOUT_DIV= 1
CXPSpeed::CXP10 | CXPSpeed::CXP12 => CdrConfig {
cfg_reg0: 0x0020,
cfg_reg1: 0x1040,
cfg_reg2: 0x23FF,
cfg_reg3: 0x0000,
cfg_reg4: 0x000B,
},
};
gtx_write(0x0A8, cdr_cfg.cfg_reg0);
gtx_write(0x0A9, cdr_cfg.cfg_reg1);
gtx_write(0x0AA, cdr_cfg.cfg_reg2);
gtx_write(0x0AB, cdr_cfg.cfg_reg3);
gtx_write(0x0AC, cdr_cfg.cfg_reg4);
}
#[allow(dead_code)]
fn gtx_read(address: u16) -> u16 {
unsafe {
csr::cxp_grabber::phy_rx_gtx_daddr_write(address);
csr::cxp_grabber::phy_rx_gtx_dread_write(1);
while csr::cxp_grabber::phy_rx_gtx_dready_read() != 1 {}
csr::cxp_grabber::phy_rx_gtx_dout_read()
}
}
fn gtx_write(address: u16, value: u16) {
unsafe {
csr::cxp_grabber::phy_rx_gtx_daddr_write(address);
csr::cxp_grabber::phy_rx_gtx_din_write(value);
csr::cxp_grabber::phy_rx_gtx_din_stb_write(1);
while csr::cxp_grabber::phy_rx_gtx_dready_read() != 1 {}
}
}
#[allow(dead_code)]
fn qpll_read(address: u8) -> u16 {
unsafe {
csr::cxp_grabber::phy_rx_qpll_daddr_write(address);
csr::cxp_grabber::phy_rx_qpll_dread_write(1);
while csr::cxp_grabber::phy_rx_qpll_dready_read() != 1 {}
csr::cxp_grabber::phy_rx_qpll_dout_read()
}
}
fn qpll_write(address: u8, value: u16) {
unsafe {
csr::cxp_grabber::phy_rx_qpll_daddr_write(address);
csr::cxp_grabber::phy_rx_qpll_din_write(value);
csr::cxp_grabber::phy_rx_qpll_din_stb_write(1);
while csr::cxp_grabber::phy_rx_qpll_dready_read() != 1 {}
}
}
}

View File

@ -1,7 +1,7 @@
use core::slice;
use core::{arch::asm, slice};
use byteorder::NativeEndian;
use core_io::{Error as IoError, ErrorKind as IoErrorKind};
use crc;
use io::{proto::{ProtoRead, ProtoWrite},
Cursor};
use libboard_zynq::{time::Milliseconds, timer::GlobalTimer};
@ -39,6 +39,7 @@ pub fn copy_work_buffer(src: *mut u32, dst: *mut u32, len: isize) {
// fix for artiq-zynq#344
unsafe {
for i in 0..(len / 4) {
asm!("", options(preserves_flags, nostack, readonly));
*dst.offset(i) = *src.offset(i);
}
}
@ -99,7 +100,7 @@ pub fn recv(linkno: u8) -> Result<Option<Packet>, Error> {
let checksum_at = reader.position() + padding;
let checksum = crc::crc32::checksum_ieee(&reader.get_ref()[0..checksum_at]);
reader.set_position(checksum_at);
if reader.read_u32()? != checksum {
if reader.read_u32::<NativeEndian>()? != checksum {
return Err(Error::CorruptedPacket);
}
Ok(packet)
@ -146,7 +147,7 @@ pub fn send(linkno: u8, packet: &Packet) -> Result<(), Error> {
}
let checksum = crc::crc32::checksum_ieee(&writer.get_ref()[0..writer.position()]);
writer.write_u32(checksum)?;
writer.write_u32::<NativeEndian>(checksum)?;
Ok(writer.position())
})

View File

@ -1,12 +1,11 @@
use core::slice;
use byteorder::NativeEndian;
use core_io::{Error as IoError, ErrorKind as IoErrorKind};
use crc;
use io::{proto::{ProtoRead, ProtoWrite},
Cursor};
use libasync::{block_async, task};
use libboard_zynq::{time::Milliseconds, timer::GlobalTimer};
use nb;
use void::Void;
pub use crate::drtioaux_proto::{Packet, MAX_PACKET};
@ -68,7 +67,7 @@ pub async fn recv(linkno: u8) -> Result<Option<Packet>, Error> {
let checksum_at = reader.position() + padding;
let checksum = crc::crc32::checksum_ieee(&reader.get_ref()[0..checksum_at]);
reader.set_position(checksum_at);
if reader.read_u32()? != checksum {
if reader.read_u32::<NativeEndian>()? != checksum {
return Err(Error::CorruptedPacket);
}
Ok(packet)
@ -124,7 +123,7 @@ pub async fn send(linkno: u8, packet: &Packet) -> Result<(), Error> {
}
let checksum = crc::crc32::checksum_ieee(&writer.get_ref()[0..writer.position()]);
writer.write_u32(checksum)?;
writer.write_u32::<NativeEndian>(checksum)?;
Ok(writer.position())
})

View File

@ -1,4 +1,5 @@
use core_io::{Error as IoError, Read, Write};
use byteorder::NativeEndian;
use core_io::Error as IoError;
use io::proto::{ProtoRead, ProtoWrite};
pub const MAX_PACKET: usize = 1024;
@ -363,8 +364,7 @@ pub enum Packet {
}
impl Packet {
pub fn read_from<R>(reader: &mut R) -> Result<Self, Error>
where R: Read + ?Sized {
pub fn read_from<R: ProtoRead>(reader: &mut R) -> Result<Self, Error> {
Ok(match reader.read_u8()? {
0x00 => Packet::EchoRequest,
0x01 => Packet::EchoReply,
@ -378,13 +378,13 @@ impl Packet {
0x21 => Packet::DestinationDownReply,
0x22 => Packet::DestinationOkReply,
0x23 => Packet::DestinationSequenceErrorReply {
channel: reader.read_u16()?,
channel: reader.read_u16::<NativeEndian>()?,
},
0x24 => Packet::DestinationCollisionReply {
channel: reader.read_u16()?,
channel: reader.read_u16::<NativeEndian>()?,
},
0x25 => Packet::DestinationBusyReply {
channel: reader.read_u16()?,
channel: reader.read_u16::<NativeEndian>()?,
},
0x30 => {
@ -403,21 +403,21 @@ impl Packet {
0x40 => Packet::MonitorRequest {
destination: reader.read_u8()?,
channel: reader.read_u16()?,
channel: reader.read_u16::<NativeEndian>()?,
probe: reader.read_u8()?,
},
0x41 => Packet::MonitorReply {
value: reader.read_u64()?,
value: reader.read_u64::<NativeEndian>()?,
},
0x50 => Packet::InjectionRequest {
destination: reader.read_u8()?,
channel: reader.read_u16()?,
channel: reader.read_u16::<NativeEndian>()?,
overrd: reader.read_u8()?,
value: reader.read_u8()?,
},
0x51 => Packet::InjectionStatusRequest {
destination: reader.read_u8()?,
channel: reader.read_u16()?,
channel: reader.read_u16::<NativeEndian>()?,
overrd: reader.read_u8()?,
},
0x52 => Packet::InjectionStatusReply {
@ -476,7 +476,7 @@ impl Packet {
0x92 => Packet::SpiWriteRequest {
destination: reader.read_u8()?,
busno: reader.read_u8()?,
data: reader.read_u32()?,
data: reader.read_u32::<NativeEndian>()?,
},
0x93 => Packet::SpiReadRequest {
destination: reader.read_u8()?,
@ -484,7 +484,7 @@ impl Packet {
},
0x94 => Packet::SpiReadReply {
succeeded: reader.read_bool()?,
data: reader.read_u32()?,
data: reader.read_u32::<NativeEndian>()?,
},
0x95 => Packet::SpiBasicReply {
succeeded: reader.read_bool()?,
@ -494,8 +494,8 @@ impl Packet {
destination: reader.read_u8()?,
},
0xa1 => Packet::AnalyzerHeader {
sent_bytes: reader.read_u32()?,
total_byte_count: reader.read_u64()?,
sent_bytes: reader.read_u32::<NativeEndian>()?,
total_byte_count: reader.read_u64::<NativeEndian>()?,
overflow_occurred: reader.read_bool()?,
},
0xa2 => Packet::AnalyzerDataRequest {
@ -503,7 +503,7 @@ impl Packet {
},
0xa3 => {
let last = reader.read_bool()?;
let length = reader.read_u16()?;
let length = reader.read_u16::<NativeEndian>()?;
let mut data: [u8; SAT_PAYLOAD_MAX_SIZE] = [0; SAT_PAYLOAD_MAX_SIZE];
reader.read_exact(&mut data[0..length as usize])?;
Packet::AnalyzerData {
@ -516,9 +516,9 @@ impl Packet {
0xb0 => {
let source = reader.read_u8()?;
let destination = reader.read_u8()?;
let id = reader.read_u32()?;
let id = reader.read_u32::<NativeEndian>()?;
let status = reader.read_u8()?;
let length = reader.read_u16()?;
let length = reader.read_u16::<NativeEndian>()?;
let mut trace: [u8; MASTER_PAYLOAD_MAX_SIZE] = [0; MASTER_PAYLOAD_MAX_SIZE];
reader.read_exact(&mut trace[0..length as usize])?;
Packet::DmaAddTraceRequest {
@ -533,13 +533,13 @@ impl Packet {
0xb1 => Packet::DmaAddTraceReply {
source: reader.read_u8()?,
destination: reader.read_u8()?,
id: reader.read_u32()?,
id: reader.read_u32::<NativeEndian>()?,
succeeded: reader.read_bool()?,
},
0xb2 => Packet::DmaRemoveTraceRequest {
source: reader.read_u8()?,
destination: reader.read_u8()?,
id: reader.read_u32()?,
id: reader.read_u32::<NativeEndian>()?,
},
0xb3 => Packet::DmaRemoveTraceReply {
destination: reader.read_u8()?,
@ -548,8 +548,8 @@ impl Packet {
0xb4 => Packet::DmaPlaybackRequest {
source: reader.read_u8()?,
destination: reader.read_u8()?,
id: reader.read_u32()?,
timestamp: reader.read_u64()?,
id: reader.read_u32::<NativeEndian>()?,
timestamp: reader.read_u64::<NativeEndian>()?,
},
0xb5 => Packet::DmaPlaybackReply {
destination: reader.read_u8()?,
@ -558,17 +558,17 @@ impl Packet {
0xb6 => Packet::DmaPlaybackStatus {
source: reader.read_u8()?,
destination: reader.read_u8()?,
id: reader.read_u32()?,
id: reader.read_u32::<NativeEndian>()?,
error: reader.read_u8()?,
channel: reader.read_u32()?,
timestamp: reader.read_u64()?,
channel: reader.read_u32::<NativeEndian>()?,
timestamp: reader.read_u64::<NativeEndian>()?,
},
0xc0 => {
let destination = reader.read_u8()?;
let id = reader.read_u32()?;
let id = reader.read_u32::<NativeEndian>()?;
let status = PayloadStatus::from(reader.read_u8()?);
let length = reader.read_u16()?;
let length = reader.read_u16::<NativeEndian>()?;
let mut data: [u8; MASTER_PAYLOAD_MAX_SIZE] = [0; MASTER_PAYLOAD_MAX_SIZE];
reader.read_exact(&mut data[0..length as usize])?;
Packet::SubkernelAddDataRequest {
@ -585,9 +585,9 @@ impl Packet {
0xc4 => Packet::SubkernelLoadRunRequest {
source: reader.read_u8()?,
destination: reader.read_u8()?,
id: reader.read_u32()?,
id: reader.read_u32::<NativeEndian>()?,
run: reader.read_bool()?,
timestamp: reader.read_u64()?,
timestamp: reader.read_u64::<NativeEndian>()?,
},
0xc5 => Packet::SubkernelLoadRunReply {
destination: reader.read_u8()?,
@ -595,7 +595,7 @@ impl Packet {
},
0xc8 => Packet::SubkernelFinished {
destination: reader.read_u8()?,
id: reader.read_u32()?,
id: reader.read_u32::<NativeEndian>()?,
with_exception: reader.read_bool()?,
exception_src: reader.read_u8()?,
},
@ -606,7 +606,7 @@ impl Packet {
0xca => {
let destination = reader.read_u8()?;
let last = reader.read_bool()?;
let length = reader.read_u16()?;
let length = reader.read_u16::<NativeEndian>()?;
let mut data: [u8; MASTER_PAYLOAD_MAX_SIZE] = [0; MASTER_PAYLOAD_MAX_SIZE];
reader.read_exact(&mut data[0..length as usize])?;
Packet::SubkernelException {
@ -619,9 +619,9 @@ impl Packet {
0xcb => {
let source = reader.read_u8()?;
let destination = reader.read_u8()?;
let id = reader.read_u32()?;
let id = reader.read_u32::<NativeEndian>()?;
let status = reader.read_u8()?;
let length = reader.read_u16()?;
let length = reader.read_u16::<NativeEndian>()?;
let mut data: [u8; MASTER_PAYLOAD_MAX_SIZE] = [0; MASTER_PAYLOAD_MAX_SIZE];
reader.read_exact(&mut data[0..length as usize])?;
Packet::SubkernelMessage {
@ -654,7 +654,7 @@ impl Packet {
},
0xd4 => {
let destination = reader.read_u8()?;
let length = reader.read_u16()?;
let length = reader.read_u16::<NativeEndian>()?;
let mut key: [u8; MASTER_PAYLOAD_MAX_SIZE] = [0; MASTER_PAYLOAD_MAX_SIZE];
reader.read_exact(&mut key[0..length as usize])?;
Packet::CoreMgmtConfigReadRequest {
@ -669,7 +669,7 @@ impl Packet {
0xd6 => {
let destination = reader.read_u8()?;
let last = reader.read_bool()?;
let length = reader.read_u16()?;
let length = reader.read_u16::<NativeEndian>()?;
let mut data: [u8; MASTER_PAYLOAD_MAX_SIZE] = [0; MASTER_PAYLOAD_MAX_SIZE];
reader.read_exact(&mut data[0..length as usize])?;
Packet::CoreMgmtConfigWriteRequest {
@ -681,7 +681,7 @@ impl Packet {
}
0xd7 => {
let destination = reader.read_u8()?;
let length = reader.read_u16()?;
let length = reader.read_u16::<NativeEndian>()?;
let mut key: [u8; MASTER_PAYLOAD_MAX_SIZE] = [0; MASTER_PAYLOAD_MAX_SIZE];
reader.read_exact(&mut key[0..length as usize])?;
Packet::CoreMgmtConfigRemoveRequest {
@ -701,12 +701,12 @@ impl Packet {
},
0xdb => Packet::CoreMgmtFlashRequest {
destination: reader.read_u8()?,
payload_length: reader.read_u32()?,
payload_length: reader.read_u32::<NativeEndian>()?,
},
0xdc => {
let destination = reader.read_u8()?;
let last = reader.read_bool()?;
let length = reader.read_u16()?;
let length = reader.read_u16::<NativeEndian>()?;
let mut data: [u8; MASTER_PAYLOAD_MAX_SIZE] = [0; MASTER_PAYLOAD_MAX_SIZE];
reader.read_exact(&mut data[0..length as usize])?;
Packet::CoreMgmtFlashAddDataRequest {
@ -722,7 +722,7 @@ impl Packet {
0xde => Packet::CoreMgmtDropLink,
0xdf => {
let last = reader.read_bool()?;
let length = reader.read_u16()?;
let length = reader.read_u16::<NativeEndian>()?;
let mut data: [u8; SAT_PAYLOAD_MAX_SIZE] = [0; SAT_PAYLOAD_MAX_SIZE];
reader.read_exact(&mut data[0..length as usize])?;
Packet::CoreMgmtGetLogReply {
@ -733,7 +733,7 @@ impl Packet {
}
0xe0 => {
let last = reader.read_bool()?;
let length = reader.read_u16()?;
let length = reader.read_u16::<NativeEndian>()?;
let mut value: [u8; SAT_PAYLOAD_MAX_SIZE] = [0; SAT_PAYLOAD_MAX_SIZE];
reader.read_exact(&mut value[0..length as usize])?;
Packet::CoreMgmtConfigReadReply {
@ -750,8 +750,7 @@ impl Packet {
})
}
pub fn write_to<W>(&self, writer: &mut W) -> Result<(), IoError>
where W: Write + ?Sized {
pub fn write_to<W: ProtoWrite>(&self, writer: &mut W) -> Result<(), IoError> {
match *self {
Packet::EchoRequest => writer.write_u8(0x00)?,
Packet::EchoReply => writer.write_u8(0x01)?,
@ -767,15 +766,15 @@ impl Packet {
Packet::DestinationOkReply => writer.write_u8(0x22)?,
Packet::DestinationSequenceErrorReply { channel } => {
writer.write_u8(0x23)?;
writer.write_u16(channel)?;
writer.write_u16::<NativeEndian>(channel)?;
}
Packet::DestinationCollisionReply { channel } => {
writer.write_u8(0x24)?;
writer.write_u16(channel)?;
writer.write_u16::<NativeEndian>(channel)?;
}
Packet::DestinationBusyReply { channel } => {
writer.write_u8(0x25)?;
writer.write_u16(channel)?;
writer.write_u16::<NativeEndian>(channel)?;
}
Packet::RoutingSetPath { destination, hops } => {
@ -796,12 +795,12 @@ impl Packet {
} => {
writer.write_u8(0x40)?;
writer.write_u8(destination)?;
writer.write_u16(channel)?;
writer.write_u16::<NativeEndian>(channel)?;
writer.write_u8(probe)?;
}
Packet::MonitorReply { value } => {
writer.write_u8(0x41)?;
writer.write_u64(value)?;
writer.write_u64::<NativeEndian>(value)?;
}
Packet::InjectionRequest {
destination,
@ -811,7 +810,7 @@ impl Packet {
} => {
writer.write_u8(0x50)?;
writer.write_u8(destination)?;
writer.write_u16(channel)?;
writer.write_u16::<NativeEndian>(channel)?;
writer.write_u8(overrd)?;
writer.write_u8(value)?;
}
@ -822,7 +821,7 @@ impl Packet {
} => {
writer.write_u8(0x51)?;
writer.write_u8(destination)?;
writer.write_u16(channel)?;
writer.write_u16::<NativeEndian>(channel)?;
writer.write_u8(overrd)?;
}
Packet::InjectionStatusReply { value } => {
@ -916,7 +915,7 @@ impl Packet {
writer.write_u8(0x92)?;
writer.write_u8(destination)?;
writer.write_u8(busno)?;
writer.write_u32(data)?;
writer.write_u32::<NativeEndian>(data)?;
}
Packet::SpiReadRequest { destination, busno } => {
writer.write_u8(0x93)?;
@ -926,7 +925,7 @@ impl Packet {
Packet::SpiReadReply { succeeded, data } => {
writer.write_u8(0x94)?;
writer.write_bool(succeeded)?;
writer.write_u32(data)?;
writer.write_u32::<NativeEndian>(data)?;
}
Packet::SpiBasicReply { succeeded } => {
writer.write_u8(0x95)?;
@ -943,8 +942,8 @@ impl Packet {
overflow_occurred,
} => {
writer.write_u8(0xa1)?;
writer.write_u32(sent_bytes)?;
writer.write_u64(total_byte_count)?;
writer.write_u32::<NativeEndian>(sent_bytes)?;
writer.write_u64::<NativeEndian>(total_byte_count)?;
writer.write_bool(overflow_occurred)?;
}
Packet::AnalyzerDataRequest { destination } => {
@ -954,7 +953,7 @@ impl Packet {
Packet::AnalyzerData { last, length, data } => {
writer.write_u8(0xa3)?;
writer.write_bool(last)?;
writer.write_u16(length)?;
writer.write_u16::<NativeEndian>(length)?;
writer.write_all(&data[0..length as usize])?;
}
@ -969,11 +968,11 @@ impl Packet {
writer.write_u8(0xb0)?;
writer.write_u8(source)?;
writer.write_u8(destination)?;
writer.write_u32(id)?;
writer.write_u32::<NativeEndian>(id)?;
writer.write_u8(status as u8)?;
// trace may be broken down to fit within drtio aux memory limit
// will be reconstructed by satellite
writer.write_u16(length)?;
writer.write_u16::<NativeEndian>(length)?;
writer.write_all(&trace[0..length as usize])?;
}
Packet::DmaAddTraceReply {
@ -985,7 +984,7 @@ impl Packet {
writer.write_u8(0xb1)?;
writer.write_u8(source)?;
writer.write_u8(destination)?;
writer.write_u32(id)?;
writer.write_u32::<NativeEndian>(id)?;
writer.write_bool(succeeded)?;
}
Packet::DmaRemoveTraceRequest {
@ -996,7 +995,7 @@ impl Packet {
writer.write_u8(0xb2)?;
writer.write_u8(source)?;
writer.write_u8(destination)?;
writer.write_u32(id)?;
writer.write_u32::<NativeEndian>(id)?;
}
Packet::DmaRemoveTraceReply { destination, succeeded } => {
writer.write_u8(0xb3)?;
@ -1012,8 +1011,8 @@ impl Packet {
writer.write_u8(0xb4)?;
writer.write_u8(source)?;
writer.write_u8(destination)?;
writer.write_u32(id)?;
writer.write_u64(timestamp)?;
writer.write_u32::<NativeEndian>(id)?;
writer.write_u64::<NativeEndian>(timestamp)?;
}
Packet::DmaPlaybackReply { destination, succeeded } => {
writer.write_u8(0xb5)?;
@ -1031,10 +1030,10 @@ impl Packet {
writer.write_u8(0xb6)?;
writer.write_u8(source)?;
writer.write_u8(destination)?;
writer.write_u32(id)?;
writer.write_u32::<NativeEndian>(id)?;
writer.write_u8(error)?;
writer.write_u32(channel)?;
writer.write_u64(timestamp)?;
writer.write_u32::<NativeEndian>(channel)?;
writer.write_u64::<NativeEndian>(timestamp)?;
}
Packet::SubkernelAddDataRequest {
@ -1046,9 +1045,9 @@ impl Packet {
} => {
writer.write_u8(0xc0)?;
writer.write_u8(destination)?;
writer.write_u32(id)?;
writer.write_u32::<NativeEndian>(id)?;
writer.write_u8(status as u8)?;
writer.write_u16(length)?;
writer.write_u16::<NativeEndian>(length)?;
writer.write_all(&data[0..length as usize])?;
}
Packet::SubkernelAddDataReply { succeeded } => {
@ -1065,9 +1064,9 @@ impl Packet {
writer.write_u8(0xc4)?;
writer.write_u8(source)?;
writer.write_u8(destination)?;
writer.write_u32(id)?;
writer.write_u32::<NativeEndian>(id)?;
writer.write_bool(run)?;
writer.write_u64(timestamp)?;
writer.write_u64::<NativeEndian>(timestamp)?;
}
Packet::SubkernelLoadRunReply { destination, succeeded } => {
writer.write_u8(0xc5)?;
@ -1082,7 +1081,7 @@ impl Packet {
} => {
writer.write_u8(0xc8)?;
writer.write_u8(destination)?;
writer.write_u32(id)?;
writer.write_u32::<NativeEndian>(id)?;
writer.write_bool(with_exception)?;
writer.write_u8(exception_src)?;
}
@ -1100,7 +1099,7 @@ impl Packet {
writer.write_u8(0xca)?;
writer.write_u8(destination)?;
writer.write_bool(last)?;
writer.write_u16(length)?;
writer.write_u16::<NativeEndian>(length)?;
writer.write_all(&data[0..length as usize])?;
}
Packet::SubkernelMessage {
@ -1114,9 +1113,9 @@ impl Packet {
writer.write_u8(0xcb)?;
writer.write_u8(source)?;
writer.write_u8(destination)?;
writer.write_u32(id)?;
writer.write_u32::<NativeEndian>(id)?;
writer.write_u8(status as u8)?;
writer.write_u16(length)?;
writer.write_u16::<NativeEndian>(length)?;
writer.write_all(&data[0..length as usize])?;
}
Packet::SubkernelMessageAck { destination } => {
@ -1150,7 +1149,7 @@ impl Packet {
} => {
writer.write_u8(0xd4)?;
writer.write_u8(destination)?;
writer.write_u16(length)?;
writer.write_u16::<NativeEndian>(length)?;
writer.write_all(&key[0..length as usize])?;
}
Packet::CoreMgmtConfigReadContinue { destination } => {
@ -1166,7 +1165,7 @@ impl Packet {
writer.write_u8(0xd6)?;
writer.write_u8(destination)?;
writer.write_bool(last)?;
writer.write_u16(length)?;
writer.write_u16::<NativeEndian>(length)?;
writer.write_all(&data[0..length as usize])?;
}
Packet::CoreMgmtConfigRemoveRequest {
@ -1176,7 +1175,7 @@ impl Packet {
} => {
writer.write_u8(0xd7)?;
writer.write_u8(destination)?;
writer.write_u16(length)?;
writer.write_u16::<NativeEndian>(length)?;
writer.write_all(&key[0..length as usize])?;
}
Packet::CoreMgmtConfigEraseRequest { destination } => {
@ -1197,7 +1196,7 @@ impl Packet {
} => {
writer.write_u8(0xdb)?;
writer.write_u8(destination)?;
writer.write_u32(payload_length)?;
writer.write_u32::<NativeEndian>(payload_length)?;
}
Packet::CoreMgmtFlashAddDataRequest {
destination,
@ -1208,7 +1207,7 @@ impl Packet {
writer.write_u8(0xdc)?;
writer.write_u8(destination)?;
writer.write_bool(last)?;
writer.write_u16(length)?;
writer.write_u16::<NativeEndian>(length)?;
writer.write_all(&data[..length as usize])?;
}
Packet::CoreMgmtDropLinkAck { destination } => {
@ -1219,13 +1218,13 @@ impl Packet {
Packet::CoreMgmtGetLogReply { last, length, data } => {
writer.write_u8(0xdf)?;
writer.write_bool(last)?;
writer.write_u16(length)?;
writer.write_u16::<NativeEndian>(length)?;
writer.write_all(&data[0..length as usize])?;
}
Packet::CoreMgmtConfigReadReply { last, length, value } => {
writer.write_u8(0xe0)?;
writer.write_bool(last)?;
writer.write_u16(length)?;
writer.write_u16::<NativeEndian>(length)?;
writer.write_all(&value[0..length as usize])?;
}
Packet::CoreMgmtReply { succeeded } => {

View File

@ -1,3 +1,5 @@
use core::arch::asm;
use libboard_zynq::{println, stdio};
use libcortex_a9::{interrupt_handler, regs::MPIDR};
use libregister::RegisterR;

View File

@ -111,18 +111,23 @@ impl IoExpander {
fn write(&self, i2c: &mut i2c::I2c, addr: u8, value: u8) -> Result<(), &'static str> {
i2c.start()?;
i2c.write(self.address)?;
i2c.write(addr)?;
i2c.write(value)?;
i2c.stop()?;
Ok(())
let write_res = i2c
.write(self.address)
.and_then(|_| i2c.write(addr))
.and_then(|_| i2c.write(value));
let stop_res = i2c.stop();
write_res.and(stop_res).map_err(|e| e.into())
}
fn check_ack(&self, i2c: &mut i2c::I2c) -> Result<bool, &'static str> {
// Check for ack from io expander
self.select(i2c)?;
i2c.start()?;
let ack = i2c.write(self.address)?;
let ack = match i2c.write(self.address) {
Ok(()) => true,
Err(i2c::Error::Nack) => false,
Err(e) => return Err(e.into()),
};
i2c.stop()?;
Ok(ack)
}

View File

@ -1,7 +1,6 @@
#![no_std]
#![feature(never_type)]
#![feature(naked_functions)]
#![feature(asm)]
extern crate core_io;
extern crate crc;
@ -25,7 +24,7 @@ pub mod fiq;
#[cfg(feature = "target_kasli_soc")]
pub mod io_expander;
pub mod logger;
#[cfg(has_drtio)]
#[cfg(any(has_drtio, has_cxp_grabber))]
#[rustfmt::skip]
#[path = "../../../build/mem.rs"]
pub mod mem;
@ -42,6 +41,17 @@ pub mod si5324;
pub mod si549;
use core::{cmp, str};
#[cfg(has_cxp_grabber)]
pub mod cxp_camera_setup;
#[cfg(has_cxp_grabber)]
pub mod cxp_ctrl;
#[cfg(has_cxp_grabber)]
pub mod cxp_grabber;
#[cfg(has_cxp_grabber)]
pub mod cxp_packet;
#[cfg(has_cxp_grabber)]
pub mod cxp_phys;
pub fn identifier_read(buf: &mut [u8]) -> &str {
unsafe {
pl::csr::identifier::address_write(0);

View File

@ -1,4 +1,4 @@
use core::{cell::Cell, fmt::Write};
use core::{cell::Cell, fmt::Write, mem::MaybeUninit};
use libboard_zynq::{println, timer::GlobalTimer};
use libcortex_a9::mutex::{Mutex, MutexGuard};
@ -42,7 +42,7 @@ pub struct BufferLogger {
buffer_filter: Cell<LevelFilter>,
}
static mut LOGGER: Option<BufferLogger> = None;
static mut LOGGER: MaybeUninit<BufferLogger> = MaybeUninit::uninit();
impl BufferLogger {
pub fn new(buffer: &'static mut [u8]) -> BufferLogger {
@ -55,13 +55,13 @@ impl BufferLogger {
pub fn register(self) {
unsafe {
LOGGER = Some(self);
log::set_logger(LOGGER.as_ref().unwrap()).expect("global logger can only be initialized once");
LOGGER.write(self);
log::set_logger(LOGGER.assume_init_ref()).expect("global logger can only be initialized once");
}
}
pub unsafe fn get_logger() -> &'static mut Option<BufferLogger> {
&mut LOGGER
pub fn get_logger() -> &'static mut BufferLogger {
unsafe { LOGGER.assume_init_mut() }
}
pub fn buffer<'a>(&'a self) -> Option<LogBufferRef<'a>> {

View File

@ -1,7 +1,9 @@
use core::result;
use embedded_hal::blocking::delay::DelayUs;
use libboard_zynq::{i2c::I2c, time::Milliseconds, timer::GlobalTimer};
use libboard_zynq::{i2c::{Error as I2cError, I2c},
time::Milliseconds,
timer::GlobalTimer};
use log::info;
#[cfg(not(si5324_soft_reset))]
@ -97,15 +99,18 @@ fn map_frequency_settings(settings: &FrequencySettings) -> Result<FrequencySetti
fn write(i2c: &mut I2c, reg: u8, val: u8) -> Result<()> {
i2c.start().unwrap();
if !i2c.write(ADDRESS << 1).unwrap() {
return Err("Si5324 failed to ack write address");
}
if !i2c.write(reg).unwrap() {
return Err("Si5324 failed to ack register");
}
if !i2c.write(val).unwrap() {
return Err("Si5324 failed to ack value");
}
i2c.write(ADDRESS << 1).map_err(|err| match err {
I2cError::Nack => "Si5324 failed to ack write address",
err => err.into(),
})?;
i2c.write(reg).map_err(|err| match err {
I2cError::Nack => "Si5324 failed to ack register",
err => err.into(),
})?;
i2c.write(val).map_err(|err| match err {
I2cError::Nack => "Si5324 failed to ack value",
err => err.into(),
})?;
i2c.stop().unwrap();
Ok(())
}
@ -113,29 +118,37 @@ fn write(i2c: &mut I2c, reg: u8, val: u8) -> Result<()> {
#[allow(dead_code)]
fn write_no_ack_value(i2c: &mut I2c, reg: u8, val: u8) -> Result<()> {
i2c.start().unwrap();
if !i2c.write(ADDRESS << 1).unwrap() {
return Err("Si5324 failed to ack write address");
i2c.write(ADDRESS << 1).map_err(|err| match err {
I2cError::Nack => "Si5324 failed to ack write address",
err => err.into(),
})?;
i2c.write(reg).map_err(|err| match err {
I2cError::Nack => "Si5324 failed to ack register",
err => err.into(),
})?;
match i2c.write(val) {
Ok(()) | Err(I2cError::Nack) => (),
Err(e) => return Err(e.into()),
}
if !i2c.write(reg).unwrap() {
return Err("Si5324 failed to ack register");
}
i2c.write(val).unwrap();
i2c.stop().unwrap();
Ok(())
}
fn read(i2c: &mut I2c, reg: u8) -> Result<u8> {
i2c.start().unwrap();
if !i2c.write(ADDRESS << 1).unwrap() {
return Err("Si5324 failed to ack write address");
}
if !i2c.write(reg).unwrap() {
return Err("Si5324 failed to ack register");
}
i2c.write(ADDRESS << 1).map_err(|err| match err {
I2cError::Nack => "Si5324 failed to ack write address",
err => err.into(),
})?;
i2c.write(reg).map_err(|err| match err {
I2cError::Nack => "Si5324 failed to ack register",
err => err.into(),
})?;
i2c.restart().unwrap();
if !i2c.write((ADDRESS << 1) | 1).unwrap() {
return Err("Si5324 failed to ack read address");
}
i2c.write((ADDRESS << 1) | 1).map_err(|err| match err {
I2cError::Nack => "Si5324 failed to ack read address",
err => err.into(),
})?;
let val = i2c.read(false).unwrap();
i2c.stop().unwrap();
Ok(val)

View File

@ -85,7 +85,7 @@ unsafe fn get_ttype_entry(
encoding | DW_EH_PE_pcrel,
ttype_base,
)
.map(|v| (v != ttype_base).then(|| v as *const u8))
.map(|v| (v != 0).then(|| v as *const u8))
}
pub unsafe fn find_eh_action(
@ -275,6 +275,11 @@ unsafe fn read_encoded_pointer_with_base(reader: &mut DwarfReader, encoding: u8,
_ => return Err(()),
};
if result == 0 {
// null is just encoded as 0, even if a relative encoding is used for the table.
return Ok(0);
}
result += if (encoding & 0x70) == DW_EH_PE_pcrel {
original_ptr as usize
} else {

View File

@ -1,6 +1,5 @@
#![no_std]
#![feature(never_type)]
#![feature(asm)]
#[cfg(feature = "alloc")]
extern crate alloc;

View File

@ -2,58 +2,54 @@
use alloc::{string::String, vec};
use core::str::Utf8Error;
use byteorder::{ByteOrder, NativeEndian};
use core_io::{Error as IoError, Read, Write};
use byteorder::ByteOrder;
use core_io::{Error, Read, Write};
#[allow(dead_code)]
#[cfg(feature = "alloc")]
#[derive(Debug, Clone, PartialEq)]
pub enum ReadStringError<T> {
Utf8(Utf8Error),
Other(T),
}
pub trait ProtoRead {
type ReadError;
fn read_exact(&mut self, buf: &mut [u8]) -> Result<(), Self::ReadError>;
pub trait ProtoRead: Read {
#[inline]
fn read_u8(&mut self) -> Result<u8, Self::ReadError> {
fn read_u8(&mut self) -> Result<u8, Error> {
let mut bytes = [0; 1];
self.read_exact(&mut bytes)?;
Ok(bytes[0])
}
#[inline]
fn read_u16(&mut self) -> Result<u16, Self::ReadError> {
fn read_u16<T: ByteOrder>(&mut self) -> Result<u16, Error> {
let mut bytes = [0; 2];
self.read_exact(&mut bytes)?;
Ok(NativeEndian::read_u16(&bytes))
Ok(T::read_u16(&bytes))
}
#[inline]
fn read_u32(&mut self) -> Result<u32, Self::ReadError> {
fn read_u32<T: ByteOrder>(&mut self) -> Result<u32, Error> {
let mut bytes = [0; 4];
self.read_exact(&mut bytes)?;
Ok(NativeEndian::read_u32(&bytes))
Ok(T::read_u32(&bytes))
}
#[inline]
fn read_u64(&mut self) -> Result<u64, Self::ReadError> {
fn read_u64<T: ByteOrder>(&mut self) -> Result<u64, Error> {
let mut bytes = [0; 8];
self.read_exact(&mut bytes)?;
Ok(NativeEndian::read_u64(&bytes))
Ok(T::read_u64(&bytes))
}
#[inline]
fn read_bool(&mut self) -> Result<bool, Self::ReadError> {
fn read_bool(&mut self) -> Result<bool, Error> {
Ok(self.read_u8()? != 0)
}
#[inline]
#[cfg(feature = "alloc")]
fn read_bytes(&mut self) -> Result<vec::Vec<u8>, Self::ReadError> {
let length = self.read_u32()?;
fn read_bytes<T: ByteOrder>(&mut self) -> Result<vec::Vec<u8>, Error> {
let length = self.read_u32::<T>()?;
let mut value = vec![0; length as usize];
self.read_exact(&mut value)?;
Ok(value)
@ -61,105 +57,85 @@ pub trait ProtoRead {
#[inline]
#[cfg(feature = "alloc")]
fn read_string(&mut self) -> Result<String, ReadStringError<Self::ReadError>> {
let bytes = self.read_bytes().map_err(ReadStringError::Other)?;
fn read_string<T: ByteOrder>(&mut self) -> Result<String, ReadStringError<Error>> {
let bytes = self.read_bytes::<T>().map_err(ReadStringError::Other)?;
String::from_utf8(bytes).map_err(|err| ReadStringError::Utf8(err.utf8_error()))
}
}
pub trait ProtoWrite {
type WriteError;
fn write_all(&mut self, buf: &[u8]) -> Result<(), Self::WriteError>;
pub trait ProtoWrite: Write {
#[inline]
fn write_u8(&mut self, value: u8) -> Result<(), Self::WriteError> {
fn write_u8(&mut self, value: u8) -> Result<(), Error> {
let bytes = [value; 1];
self.write_all(&bytes)
}
#[inline]
fn write_i8(&mut self, value: i8) -> Result<(), Self::WriteError> {
fn write_i8(&mut self, value: i8) -> Result<(), Error> {
let bytes = [value as u8; 1];
self.write_all(&bytes)
}
#[inline]
fn write_u16(&mut self, value: u16) -> Result<(), Self::WriteError> {
fn write_u16<T: ByteOrder>(&mut self, value: u16) -> Result<(), Error> {
let mut bytes = [0; 2];
NativeEndian::write_u16(&mut bytes, value);
T::write_u16(&mut bytes, value);
self.write_all(&bytes)
}
#[inline]
fn write_i16(&mut self, value: i16) -> Result<(), Self::WriteError> {
fn write_i16<T: ByteOrder>(&mut self, value: i16) -> Result<(), Error> {
let mut bytes = [0; 2];
NativeEndian::write_i16(&mut bytes, value);
T::write_i16(&mut bytes, value);
self.write_all(&bytes)
}
#[inline]
fn write_u32(&mut self, value: u32) -> Result<(), Self::WriteError> {
fn write_u32<T: ByteOrder>(&mut self, value: u32) -> Result<(), Error> {
let mut bytes = [0; 4];
NativeEndian::write_u32(&mut bytes, value);
T::write_u32(&mut bytes, value);
self.write_all(&bytes)
}
#[inline]
fn write_i32(&mut self, value: i32) -> Result<(), Self::WriteError> {
fn write_i32<T: ByteOrder>(&mut self, value: i32) -> Result<(), Error> {
let mut bytes = [0; 4];
NativeEndian::write_i32(&mut bytes, value);
T::write_i32(&mut bytes, value);
self.write_all(&bytes)
}
#[inline]
fn write_u64(&mut self, value: u64) -> Result<(), Self::WriteError> {
fn write_u64<T: ByteOrder>(&mut self, value: u64) -> Result<(), Error> {
let mut bytes = [0; 8];
NativeEndian::write_u64(&mut bytes, value);
T::write_u64(&mut bytes, value);
self.write_all(&bytes)
}
#[inline]
fn write_i64(&mut self, value: i64) -> Result<(), Self::WriteError> {
fn write_i64<T: ByteOrder>(&mut self, value: i64) -> Result<(), Error> {
let mut bytes = [0; 8];
NativeEndian::write_i64(&mut bytes, value);
T::write_i64(&mut bytes, value);
self.write_all(&bytes)
}
#[inline]
fn write_bool(&mut self, value: bool) -> Result<(), Self::WriteError> {
fn write_bool(&mut self, value: bool) -> Result<(), Error> {
self.write_u8(value as u8)
}
#[inline]
fn write_bytes(&mut self, value: &[u8]) -> Result<(), Self::WriteError> {
self.write_u32(value.len() as u32)?;
fn write_bytes<T: ByteOrder>(&mut self, value: &[u8]) -> Result<(), Error> {
self.write_u32::<T>(value.len() as u32)?;
self.write_all(value)
}
#[inline]
#[cfg(feature = "alloc")]
fn write_string(&mut self, value: &str) -> Result<(), Self::WriteError> {
self.write_bytes(value.as_bytes())
fn write_string<T: ByteOrder>(&mut self, value: &str) -> Result<(), Error> {
self.write_bytes::<T>(value.as_bytes())
}
}
impl<T> ProtoRead for T
where T: Read + ?Sized
{
type ReadError = IoError;
impl<T: Read> ProtoRead for T {}
fn read_exact(&mut self, buf: &mut [u8]) -> Result<(), Self::ReadError> {
T::read_exact(self, buf)
}
}
impl<T> ProtoWrite for T
where T: Write + ?Sized
{
type WriteError = IoError;
fn write_all(&mut self, buf: &[u8]) -> Result<(), Self::WriteError> {
T::write_all(self, buf)
}
}
impl<T: Write> ProtoWrite for T {}

228
src/libksupport/src/cxp.rs Normal file
View File

@ -0,0 +1,228 @@
use alloc::{string::{String, ToString},
vec::Vec};
use core::fmt;
use byteorder::{ByteOrder, NetworkEndian};
use cslice::CMutSlice;
use libboard_artiq::{cxp_ctrl::{Error as CtrlErr, DATA_MAXSIZE},
cxp_grabber::{camera_connected, with_tag},
cxp_packet::{read_bytes, read_u32, write_u32}};
use log::info;
use crate::{artiq_raise, pl::csr::cxp_grabber};
const ROI_MAX_SIZE: usize = 4096;
#[repr(C)]
pub struct ROIViewerFrame {
width: i32,
height: i32,
pixel_width: i32,
}
enum Error {
BufferSizeTooSmall(usize, usize),
ROISizeTooBig(usize, usize),
InvalidLocalUrl(String),
CtrlPacketError(CtrlErr),
}
impl From<CtrlErr> for Error {
fn from(value: CtrlErr) -> Error {
Error::CtrlPacketError(value)
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&Error::BufferSizeTooSmall(required_size, buffer_size) => {
write!(
f,
"BufferSizeTooSmall - The required size is {} bytes but the buffer size is {} bytes",
required_size, buffer_size
)
}
&Error::ROISizeTooBig(width, height) => {
write!(
f,
"ROISizeTooBig - The maximum ROIViewer height and total size are {} and {} pixels respectively \
but the ROI is set to {} ({}x{}) pixels",
ROI_MAX_SIZE / 4,
ROI_MAX_SIZE,
width * height,
width,
height
)
}
&Error::InvalidLocalUrl(ref s) => {
write!(f, "InvalidLocalUrl - Cannot download xml file locally from {}", s)
}
&Error::CtrlPacketError(ref err) => write!(f, "{}", err),
}
}
}
fn read_xml_url(with_tag: bool) -> Result<String, Error> {
let mut addr = read_u32(0x0018, with_tag)?;
let mut buffer = Vec::new();
// Strings stored in the bootstrap and manufacturer-specific registers space shall be NULL-terminated, encoded ASCII - Section 12.3.1 (CXP-001-2021)
// String length is not known during runtime, grabber must read 4 bytes at a time until NULL-terminated
loop {
let mut bytes: [u8; 4] = [0; 4];
read_bytes(addr, &mut bytes, with_tag)?;
addr += 4;
for b in bytes {
if b == 0 {
// UTF-8 is compatible with ASCII encoding
// use U+FFFD REPLACEMENT_CHARACTER to represent decoding error
return Ok(String::from_utf8_lossy(&buffer).to_string());
} else {
buffer.push(b);
}
}
}
}
fn read_xml_location(with_tag: bool) -> Result<(String, u32, u32), Error> {
let url = read_xml_url(with_tag)?;
// url example - Section 13.2.3 (CXP-001-2021)
// Available on camera - "Local:MyFilename.zip;B8000;33A?SchemaVersion=1.0.0"
// => ZIP file starting at address 0xB8000 in the Device with a length of 0x33A bytes
//
// Available online - "Web:http://www.example.com/xml/MyFilename.xml"
// => xml is available at http://www.example.com/xml/MyFilename.xml
let mut splitter = url.split(|c| c == ':' || c == ';' || c == '?');
let scheme = splitter.next().unwrap();
if scheme.eq_ignore_ascii_case("local") {
if let (Some(file_name), Some(addr_str), Some(size_str)) = (splitter.next(), splitter.next(), splitter.next()) {
let addr = u32::from_str_radix(addr_str, 16).map_err(|_| Error::InvalidLocalUrl(url.to_string()))?;
let size = u32::from_str_radix(size_str, 16).map_err(|_| Error::InvalidLocalUrl(url.to_string()))?;
return Ok((file_name.to_string(), addr, size));
}
}
Err(Error::InvalidLocalUrl(url.to_string()))
}
fn read_xml_file(buffer: &mut [i32], with_tag: bool) -> Result<u32, Error> {
let (file_name, base_addr, size) = read_xml_location(with_tag)?;
if buffer.len() * 4 < size as usize {
return Err(Error::BufferSizeTooSmall(size as usize, buffer.len() * 4));
};
info!("downloading xml file {} with {} bytes...", file_name, size);
let mut v: Vec<u8> = Vec::new();
let mut addr = base_addr;
let mut bytesleft = size;
let mut bytes: [u8; DATA_MAXSIZE] = [0; DATA_MAXSIZE];
while bytesleft > 0 {
let read_len = DATA_MAXSIZE.min(bytesleft as usize);
read_bytes(addr, &mut bytes[..read_len], with_tag)?;
v.extend(&bytes[..read_len]);
addr += read_len as u32;
bytesleft -= read_len as u32;
}
info!("download successful");
// pad to 32 bit boundary
let padding = (4 - (size % 4)) % 4;
for _ in 0..padding {
v.push(0);
}
NetworkEndian::read_i32_into(&v, &mut buffer[..((size + padding) / 4) as usize]);
Ok((size + padding) / 4)
}
pub extern "C" fn download_xml_file(buffer: &mut CMutSlice<i32>) -> i32 {
if camera_connected() {
match read_xml_file(buffer.as_mut_slice(), with_tag()) {
Ok(size_read) => size_read as i32,
Err(e) => artiq_raise!("CXPError", format!("{}", e)),
}
} else {
artiq_raise!("CXPError", "Camera is not connected");
}
}
pub extern "C" fn read32(addr: i32) -> i32 {
if camera_connected() {
match read_u32(addr as u32, with_tag()) {
Ok(result) => result as i32,
Err(e) => artiq_raise!("CXPError", format!("{}", e)),
}
} else {
artiq_raise!("CXPError", "Camera is not connected");
}
}
pub extern "C" fn write32(addr: i32, val: i32) {
if camera_connected() {
match write_u32(addr as u32, val as u32, with_tag()) {
Ok(_) => {}
Err(e) => artiq_raise!("CXPError", format!("{}", e)),
}
} else {
artiq_raise!("CXPError", "Camera is not connected");
}
}
pub extern "C" fn start_roi_viewer(x0: i32, y0: i32, x1: i32, y1: i32) {
let (width, height) = ((x1 - x0) as usize, (y1 - y0) as usize);
if width * height > ROI_MAX_SIZE || height > ROI_MAX_SIZE / 4 {
artiq_raise!("CXPError", format!("{}", Error::ROISizeTooBig(width, height)));
} else {
unsafe {
// flush the fifo before arming
while cxp_grabber::roi_viewer_fifo_stb_read() == 1 {
cxp_grabber::roi_viewer_fifo_ack_write(1);
}
cxp_grabber::roi_viewer_x0_write(x0 as u16);
cxp_grabber::roi_viewer_x1_write(x1 as u16);
cxp_grabber::roi_viewer_y0_write(y0 as u16);
cxp_grabber::roi_viewer_y1_write(y1 as u16);
cxp_grabber::roi_viewer_arm_write(1);
}
}
}
pub extern "C" fn download_roi_viewer_frame(buffer: &mut CMutSlice<i64>) -> ROIViewerFrame {
if buffer.len() * 4 < ROI_MAX_SIZE {
// each pixel is 16 bits
artiq_raise!(
"CXPError",
format!("{}", Error::BufferSizeTooSmall(ROI_MAX_SIZE * 2, buffer.len() * 8))
);
};
let buf = buffer.as_mut_slice();
unsafe {
while cxp_grabber::roi_viewer_ready_read() == 0 {}
let mut i = 0;
while cxp_grabber::roi_viewer_fifo_stb_read() == 1 {
buf[i] = cxp_grabber::roi_viewer_fifo_data_read() as i64;
i += 1;
cxp_grabber::roi_viewer_fifo_ack_write(1);
}
let width = (cxp_grabber::roi_viewer_x1_read() - cxp_grabber::roi_viewer_x0_read()) as i32;
let height = (cxp_grabber::roi_viewer_y1_read() - cxp_grabber::roi_viewer_y0_read()) as i32;
let pixel_width = match cxp_grabber::stream_decoder_pixel_format_code_read() {
0x0101 => 8,
0x0102 => 10,
0x0103 => 12,
0x0104 => 14,
0x0105 => 16,
_ => artiq_raise!("CXPError", "UnsupportedPixelFormat"),
};
ROIViewerFrame {
width,
height,
pixel_width,
}
}
}

View File

@ -14,6 +14,7 @@
use core::mem;
use byteorder::NativeEndian;
use core_io::Error as ReadError;
use cslice::{AsCSlice, CSlice};
use dwarf::eh::{self, EHAction, EHContext};
@ -302,9 +303,9 @@ pub unsafe extern "C" fn raise(exception: *const Exception) -> ! {
}
fn read_exception_string<'a>(reader: &mut Cursor<&[u8]>) -> Result<CSlice<'a, u8>, ReadError> {
let len = reader.read_u32()? as usize;
let len = reader.read_u32::<NativeEndian>()? as usize;
if len == usize::MAX {
let data = reader.read_u32()?;
let data = reader.read_u32::<NativeEndian>()?;
Ok(unsafe { CSlice::new(data as *const u8, len) })
} else {
let pos = reader.position();
@ -329,19 +330,19 @@ fn read_exception(raw_exception: &[u8]) -> Result<Exception, ReadError> {
while byte != 0x09 {
byte = reader.read_u8()?;
}
let _len = reader.read_u32()?;
let _len = reader.read_u32::<NativeEndian>()?;
// ignore the remaining exceptions, stack traces etc. - unwinding from another device would be unwise anyway
Ok(Exception {
id: reader.read_u32()?,
id: reader.read_u32::<NativeEndian>()?,
message: read_exception_string(&mut reader)?,
param: [
reader.read_u64()? as i64,
reader.read_u64()? as i64,
reader.read_u64()? as i64,
reader.read_u64::<NativeEndian>()? as i64,
reader.read_u64::<NativeEndian>()? as i64,
reader.read_u64::<NativeEndian>()? as i64,
],
file: read_exception_string(&mut reader)?,
line: reader.read_u32()?,
column: reader.read_u32()?,
line: reader.read_u32::<NativeEndian>()?,
column: reader.read_u32::<NativeEndian>()?,
function: read_exception_string(&mut reader)?,
})
}
@ -482,7 +483,7 @@ extern "C" fn stop_fn(
}
// Must be kept in sync with preallocate_runtime_exception_names() in `artiq.compiler.embedding`
static EXCEPTION_ID_LOOKUP: [(&str, u32); 22] = [
static EXCEPTION_ID_LOOKUP: [(&str, u32); 23] = [
("RTIOUnderflow", 0),
("RTIOOverflow", 1),
("RTIODestinationUnreachable", 2),
@ -505,6 +506,7 @@ static EXCEPTION_ID_LOOKUP: [(&str, u32); 22] = [
("ZeroDivisionError", 19),
("LinAlgError", 20),
("UnwrapNoneError", 21),
("CXPError", 22),
];
pub fn get_exception_id(name: &str) -> u32 {

View File

@ -1,97 +0,0 @@
use libboard_zynq;
use crate::artiq_raise;
pub static mut I2C_BUS: Option<libboard_zynq::i2c::I2c> = None;
pub extern "C" fn start(busno: i32) {
if busno > 0 {
artiq_raise!("I2CError", "I2C bus could not be accessed");
}
unsafe {
if (&mut I2C_BUS).as_mut().unwrap().start().is_err() {
artiq_raise!("I2CError", "I2C start failed");
}
}
}
pub extern "C" fn restart(busno: i32) {
if busno > 0 {
artiq_raise!("I2CError", "I2C bus could not be accessed");
}
unsafe {
if (&mut I2C_BUS).as_mut().unwrap().restart().is_err() {
artiq_raise!("I2CError", "I2C restart failed");
}
}
}
pub extern "C" fn stop(busno: i32) {
if busno > 0 {
artiq_raise!("I2CError", "I2C bus could not be accessed");
}
unsafe {
if (&mut I2C_BUS).as_mut().unwrap().stop().is_err() {
artiq_raise!("I2CError", "I2C stop failed");
}
}
}
pub extern "C" fn write(busno: i32, data: i32) -> bool {
if busno > 0 {
artiq_raise!("I2CError", "I2C bus could not be accessed");
}
unsafe {
match (&mut I2C_BUS).as_mut().unwrap().write(data as u8) {
Ok(r) => r,
Err(_) => artiq_raise!("I2CError", "I2C write failed"),
}
}
}
pub extern "C" fn read(busno: i32, ack: bool) -> i32 {
if busno > 0 {
artiq_raise!("I2CError", "I2C bus could not be accessed");
}
unsafe {
match (&mut I2C_BUS).as_mut().unwrap().read(ack) {
Ok(r) => r as i32,
Err(_) => artiq_raise!("I2CError", "I2C read failed"),
}
}
}
pub extern "C" fn switch_select(busno: i32, address: i32, mask: i32) {
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"),
};
unsafe {
if (&mut I2C_BUS)
.as_mut()
.unwrap()
.pca954x_select(address as u8, ch)
.is_err()
{
artiq_raise!("I2CError", "switch select failed");
}
}
}
pub fn init() {
let mut i2c = libboard_zynq::i2c::I2c::i2c0();
i2c.init().expect("I2C bus initialization failed");
unsafe { I2C_BUS = Some(i2c) };
}

View File

@ -1,4 +1,5 @@
use core::sync::atomic::{AtomicBool, Ordering};
use core::{arch::asm,
sync::atomic::{AtomicBool, Ordering}};
use libboard_zynq::{gic, mpcore, println, stdio};
use libcortex_a9::{asm, interrupt_handler, notify_spin_lock, regs::MPIDR, spin_lock_yield};

View File

@ -2,16 +2,18 @@ use alloc::vec;
use core::{ffi::VaList, ptr, str};
use libc::{c_char, c_int, size_t};
use libm;
use log::{info, warn};
#[cfg(has_drtio)]
use super::subkernel;
use super::{cache,
core1::rtio_get_destination_status,
dma, linalg,
rpc::{rpc_recv, rpc_send, rpc_send_async}};
use crate::{eh_artiq, i2c, rtio};
dma, i2c, linalg,
rpc::{rpc_recv, rpc_send, rpc_send_async},
rtio};
#[cfg(has_cxp_grabber)]
use crate::cxp;
use crate::eh_artiq;
extern "C" {
fn vsnprintf_(buffer: *mut c_char, count: size_t, format: *const c_char, va: VaList) -> c_int;
@ -126,6 +128,18 @@ pub fn resolve(required: &[u8]) -> Option<u32> {
#[cfg(has_drtio)]
api!(subkernel_await_message = subkernel::await_message),
// cxp grabber
#[cfg(has_cxp_grabber)]
api!(cxp_download_xml_file = cxp::download_xml_file),
#[cfg(has_cxp_grabber)]
api!(cxp_read32 = cxp::read32),
#[cfg(has_cxp_grabber)]
api!(cxp_write32 = cxp::write32),
#[cfg(has_cxp_grabber)]
api!(cxp_start_roi_viewer = cxp::start_roi_viewer),
#[cfg(has_cxp_grabber)]
api!(cxp_download_roi_viewer_frame = cxp::download_roi_viewer_frame),
// Double-precision floating-point arithmetic helper functions
// RTABI chapter 4.1.2, Table 2
api!(__aeabi_dadd),

View File

@ -4,17 +4,17 @@ use alloc::borrow::ToOwned;
use core::{cell::UnsafeCell, mem, ptr};
use cslice::CSlice;
use dyld::{self, elf::EXIDX_Entry, Library};
use dyld::{elf::EXIDX_Entry, Library};
use libboard_zynq::{gic, mpcore};
use libcortex_a9::{asm::{dsb, isb},
cache::{bpiall, dcci_slice, iciallu},
enable_fpu, sync_channel};
sync_channel};
use libsupport_zynq::ram;
use log::{debug, error, info};
use super::{api::resolve, dma, rpc::rpc_send_async, Message, CHANNEL_0TO1, CHANNEL_1TO0, CHANNEL_SEM, INIT_LOCK,
use super::{api::resolve, dma, rpc::rpc_send_async, rtio, Message, CHANNEL_0TO1, CHANNEL_1TO0, CHANNEL_SEM, INIT_LOCK,
KERNEL_CHANNEL_0TO1, KERNEL_CHANNEL_1TO0, KERNEL_IMAGE};
use crate::{eh_artiq, get_async_errors, rtio};
use crate::{eh_artiq, get_async_errors};
// linker symbols
extern "C" {
@ -25,12 +25,14 @@ extern "C" {
}
unsafe fn attribute_writeback(typeinfo: *const ()) {
#[repr(C)]
struct Attr {
offset: usize,
tag: CSlice<'static, u8>,
name: CSlice<'static, u8>,
}
#[repr(C)]
struct Type {
attributes: *const *const Attr,
objects: *const *const (),
@ -126,7 +128,6 @@ impl KernelImage {
#[no_mangle]
pub extern "C" fn main_core1() {
enable_fpu();
debug!("Core1 started");
ram::init_alloc_core1();

View File

@ -1,10 +1,10 @@
use alloc::{string::String, vec::Vec};
use core::mem;
use core::{mem, ptr};
use cslice::CSlice;
use super::{Message, KERNEL_CHANNEL_0TO1, KERNEL_CHANNEL_1TO0, KERNEL_IMAGE};
use crate::{artiq_raise, pl::csr, rtio};
use super::{rtio, Message, KERNEL_CHANNEL_0TO1, KERNEL_CHANNEL_1TO0, KERNEL_IMAGE};
use crate::{artiq_raise, pl::csr};
#[repr(C)]
pub struct DmaTrace {
@ -26,7 +26,7 @@ static mut RECORDER: Option<DmaRecorder> = None;
pub unsafe fn init_dma_recorder() {
// as static would remain after restart, we have to reset it,
// without running its destructor.
mem::forget(mem::replace(&mut RECORDER, None));
mem::forget(ptr::replace(&raw mut RECORDER, None));
}
pub extern "C" fn dma_record_start(name: CSlice<u8>) {

View File

@ -0,0 +1,192 @@
use core::mem::MaybeUninit;
use libboard_zynq::i2c::{Error, I2c};
#[cfg(has_drtio)]
use super::{Message, KERNEL_CHANNEL_0TO1, KERNEL_CHANNEL_1TO0};
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");
}
}
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");
}
}
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");
}
}
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"),
}
}
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"),
}
}
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"),
};
if get_bus().pca954x_select(address as u8, ch).is_err() {
artiq_raise!("I2CError", "switch select failed");
}
}
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

@ -10,7 +10,14 @@ pub use control::Control;
mod api;
pub mod core1;
mod dma;
pub mod i2c;
mod rpc;
#[cfg(ki_impl = "csr")]
#[path = "rtio_csr.rs"]
pub mod rtio;
#[cfg(ki_impl = "acp")]
#[path = "rtio_acp.rs"]
pub mod rtio;
pub use dma::DmaRecorder;
mod cache;
mod linalg;
@ -41,6 +48,10 @@ pub enum Message {
&'static [(usize, usize)],
u8,
),
#[cfg(has_drtio)]
RtioInitRequest,
RpcSend {
is_async: bool,
data: Vec<u8>,
@ -76,6 +87,41 @@ 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,
mask: u8,
},
#[cfg(has_drtio)]
SubkernelLoadRunRequest {
id: u32,

View File

@ -4,6 +4,8 @@ use cslice::CSlice;
use libcortex_a9::asm;
use vcell::VolatileCell;
#[cfg(has_drtio)]
use super::{Message, KERNEL_CHANNEL_1TO0};
use crate::{artiq_raise, pl::csr, resolve_channel_name, rtio_core};
pub const RTIO_O_STATUS_WAIT: i32 = 1;
@ -56,6 +58,10 @@ pub extern "C" fn init() {
csr::rtio::engine_addr_base_write(&TRANSACTION_BUFFER as *const Transaction as u32);
csr::rtio::enable_write(1);
}
#[cfg(has_drtio)]
unsafe {
KERNEL_CHANNEL_1TO0.as_mut().unwrap().send(Message::RtioInitRequest);
}
}
pub extern "C" fn get_counter() -> i64 {

View File

@ -2,6 +2,8 @@ use core::ptr::{read_volatile, write_volatile};
use cslice::CSlice;
#[cfg(has_drtio)]
use super::{Message, KERNEL_CHANNEL_1TO0};
use crate::{artiq_raise, pl::csr, resolve_channel_name, rtio_core};
pub const RTIO_O_STATUS_WAIT: u8 = 1;
@ -22,6 +24,10 @@ pub extern "C" fn init() {
unsafe {
rtio_core::reset_write(1);
}
#[cfg(has_drtio)]
unsafe {
KERNEL_CHANNEL_1TO0.as_mut().unwrap().send(Message::RtioInitRequest);
}
}
pub extern "C" fn get_counter() -> i64 {

View File

@ -2,8 +2,8 @@ use alloc::vec::Vec;
use cslice::CSlice;
use super::{Message, SubkernelStatus, KERNEL_CHANNEL_0TO1, KERNEL_CHANNEL_1TO0};
use crate::{artiq_raise, eh_artiq, rpc::send_args, rtio::now_mu};
use super::{rtio::now_mu, Message, SubkernelStatus, KERNEL_CHANNEL_0TO1, KERNEL_CHANNEL_1TO0};
use crate::{artiq_raise, eh_artiq, rpc::send_args};
pub extern "C" fn load_run(id: u32, destination: u8, run: bool) {
unsafe {

View File

@ -1,16 +1,16 @@
#![no_std]
#![allow(incomplete_features)]
#![feature(c_variadic)]
#![feature(const_btree_new)]
#![feature(const_btree_len)]
#![feature(inline_const)]
#![feature(naked_functions)]
#![feature(asm)]
#![feature(raw_ref_op)]
#[macro_use]
extern crate alloc;
use alloc::{collections::BTreeMap, string::String};
use byteorder::NativeEndian;
use io::{Cursor, ProtoRead};
use libasync::block_async;
use libconfig::Config;
@ -22,20 +22,15 @@ pub use pl::csr::rtio_core;
use void::Void;
pub mod eh_artiq;
pub mod i2c;
pub mod irq;
pub mod kernel;
pub mod rpc;
#[cfg(ki_impl = "csr")]
#[path = "rtio_csr.rs"]
pub mod rtio;
#[cfg(ki_impl = "acp")]
#[path = "rtio_acp.rs"]
pub mod rtio;
#[rustfmt::skip]
#[path = "../../../build/pl.rs"]
pub mod pl;
#[cfg(has_cxp_grabber)]
pub mod cxp;
#[derive(Debug, Clone)]
pub struct RPCException {
@ -123,10 +118,10 @@ fn read_device_map(cfg: &Config) -> BTreeMap<u32, String> {
.read("device_map")
.and_then(|raw_bytes| {
let mut bytes_cr = Cursor::new(raw_bytes);
let size = bytes_cr.read_u32().unwrap();
let size = bytes_cr.read_u32::<NativeEndian>().unwrap();
for _ in 0..size {
let channel = bytes_cr.read_u32().unwrap();
let device_name = bytes_cr.read_string().unwrap();
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 '{}'",
@ -146,15 +141,13 @@ fn read_device_map(cfg: &Config) -> BTreeMap<u32, String> {
device_map
}
fn _resolve_channel_name(channel: u32, device_map: &BTreeMap<u32, String>) -> String {
match device_map.get(&channel) {
pub fn resolve_channel_name(channel: u32) -> String {
unsafe {
match RTIO_DEVICE_MAP.get(&channel) {
Some(val) => val.clone(),
None => String::from("unknown"),
}
}
pub fn resolve_channel_name(channel: u32) -> String {
_resolve_channel_name(channel, unsafe { &RTIO_DEVICE_MAP })
}
}
pub fn setup_device_map(cfg: &Config) {

View File

@ -1,7 +1,7 @@
use core::str;
use byteorder::{ByteOrder, NativeEndian};
use core_io::{Error, Read, Write};
use core_io::Error;
use cslice::{CMutSlice, CSlice};
use io::{ProtoRead, ProtoWrite};
use log::trace;
@ -37,7 +37,7 @@ pub unsafe fn align_ptr_mut<T>(ptr: *mut ()) -> *mut T {
// versions for reader rather than TcpStream
// they will be made into sync for satellite subkernels later
unsafe fn recv_elements<F, R>(
unsafe fn recv_elements<F, R: ProtoRead>(
reader: &mut R,
elt_tag: Tag,
length: usize,
@ -46,7 +46,6 @@ unsafe fn recv_elements<F, R>(
) -> Result<(), Error>
where
F: FnMut(usize) -> *mut (),
R: Read + ?Sized,
{
match elt_tag {
Tag::Bool => {
@ -57,7 +56,7 @@ where
let ptr = storage as *mut u32;
let dest = core::slice::from_raw_parts_mut(ptr as *mut u8, length * 4);
reader.read_exact(dest)?;
drop(dest);
let _ = dest;
let dest = core::slice::from_raw_parts_mut(ptr, length);
NativeEndian::from_slice_u32(dest);
}
@ -65,7 +64,7 @@ where
let ptr = storage as *mut u64;
let dest = core::slice::from_raw_parts_mut(ptr as *mut u8, length * 8);
reader.read_exact(dest)?;
drop(dest);
let _ = dest;
let dest = core::slice::from_raw_parts_mut(ptr, length);
NativeEndian::from_slice_u64(dest);
}
@ -82,7 +81,7 @@ where
unsafe fn recv_value<F, R>(reader: &mut R, tag: Tag, data: &mut *mut (), alloc: &mut F) -> Result<(), Error>
where
F: FnMut(usize) -> *mut (),
R: Read + ?Sized,
R: ProtoRead,
{
macro_rules! consume_value {
($ty:ty, | $ptr:ident | $map:expr) => {{
@ -99,16 +98,16 @@ where
Ok(())
}),
Tag::Int32 => consume_value!(i32, |ptr| {
*ptr = reader.read_u32()? as i32;
*ptr = reader.read_u32::<NativeEndian>()? as i32;
Ok(())
}),
Tag::Int64 | Tag::Float64 => consume_value!(i64, |ptr| {
*ptr = reader.read_u64()? as i64;
*ptr = reader.read_u64::<NativeEndian>()? as i64;
Ok(())
}),
Tag::String | Tag::Bytes | Tag::ByteArray => {
consume_value!(CMutSlice<u8>, |ptr| {
let length = reader.read_u32()? as usize;
let length = reader.read_u32::<NativeEndian>()? as usize;
*ptr = CMutSlice::new(alloc(length) as *mut u8, length);
reader.read_exact((*ptr).as_mut())?;
Ok(())
@ -133,7 +132,7 @@ where
}
consume_value!(*mut List, |ptr_to_list| {
let tag = it.clone().next().expect("truncated tag");
let length = reader.read_u32()? as usize;
let length = reader.read_u32::<NativeEndian>()? as usize;
let list_size = 4 + 4;
let storage_offset = round_up(list_size, tag.alignment());
@ -152,7 +151,7 @@ where
consume_value!(*mut (), |buffer| {
let mut total_len: usize = 1;
for _ in 0..num_dims {
let len = reader.read_u32()? as usize;
let len = reader.read_u32::<NativeEndian>()? as usize;
total_len *= len;
consume_value!(usize, |ptr| *ptr = len)
}
@ -183,7 +182,7 @@ pub fn recv_return<'a, F, R>(
) -> Result<&'a [u8], Error>
where
F: FnMut(usize) -> *mut (),
R: Read + ?Sized,
R: ProtoRead,
{
let mut it = TagIterator::new(tag_bytes);
trace!("recv ...->{}", it);
@ -195,16 +194,13 @@ where
Ok(it.data)
}
unsafe fn send_elements<W>(
unsafe fn send_elements<W: ProtoWrite>(
writer: &mut W,
elt_tag: Tag,
length: usize,
data: *const (),
write_tags: bool,
) -> Result<(), Error>
where
W: Write + ?Sized,
{
) -> Result<(), Error> {
if write_tags {
writer.write_u8(elt_tag.as_u8())?;
}
@ -233,8 +229,12 @@ where
Ok(())
}
unsafe fn send_value<W>(writer: &mut W, tag: Tag, data: &mut *const (), write_tags: bool) -> Result<(), Error>
where W: Write + ?Sized {
unsafe fn send_value<W: ProtoWrite>(
writer: &mut W,
tag: Tag,
data: &mut *const (),
write_tags: bool,
) -> Result<(), Error> {
macro_rules! consume_value {
($ty:ty, | $ptr:ident | $map:expr) => {{
let $ptr = align_ptr::<$ty>(*data);
@ -249,12 +249,14 @@ where W: Write + ?Sized {
match tag {
Tag::None => Ok(()),
Tag::Bool => consume_value!(u8, |ptr| writer.write_u8(*ptr)),
Tag::Int32 => consume_value!(u32, |ptr| writer.write_u32(*ptr)),
Tag::Int64 | Tag::Float64 => consume_value!(u64, |ptr| writer.write_u64(*ptr)),
Tag::Int32 => consume_value!(u32, |ptr| writer.write_u32::<NativeEndian>(*ptr)),
Tag::Int64 | Tag::Float64 => consume_value!(u64, |ptr| writer.write_u64::<NativeEndian>(*ptr)),
Tag::String => consume_value!(CSlice<u8>, |ptr| {
writer.write_string(str::from_utf8((*ptr).as_ref()).unwrap())
writer.write_string::<NativeEndian>(str::from_utf8((*ptr).as_ref()).unwrap())
}),
Tag::Bytes | Tag::ByteArray => consume_value!(CSlice<u8>, |ptr| writer.write_bytes((*ptr).as_ref())),
Tag::Bytes | Tag::ByteArray => {
consume_value!(CSlice<u8>, |ptr| writer.write_bytes::<NativeEndian>((*ptr).as_ref()))
}
Tag::Tuple(it, arity) => {
let mut it = it.clone();
if write_tags {
@ -277,7 +279,7 @@ where W: Write + ?Sized {
}
consume_value!(&List, |ptr| {
let length = (**ptr).length as usize;
writer.write_u32((*ptr).length)?;
writer.write_u32::<NativeEndian>((*ptr).length)?;
let tag = it.clone().next().expect("truncated tag");
send_elements(writer, tag, length, (**ptr).elements, write_tags)
})
@ -292,7 +294,7 @@ where W: Write + ?Sized {
let mut total_len = 1;
for _ in 0..num_dims {
consume_value!(u32, |len| {
writer.write_u32(*len)?;
writer.write_u32::<NativeEndian>(*len)?;
total_len *= *len;
})
}
@ -313,7 +315,7 @@ where W: Write + ?Sized {
name: CSlice<'a, u8>,
}
consume_value!(Keyword, |ptr| {
writer.write_string(str::from_utf8((*ptr).name.as_ref()).unwrap())?;
writer.write_string::<NativeEndian>(str::from_utf8((*ptr).name.as_ref()).unwrap())?;
let tag = it.clone().next().expect("truncated tag");
let mut data = ptr.offset(1) as *const ();
send_value(writer, tag, &mut data, write_tags)
@ -326,28 +328,25 @@ where W: Write + ?Sized {
struct Object {
id: u32,
}
consume_value!(*const Object, |ptr| writer.write_u32((**ptr).id))
consume_value!(*const Object, |ptr| writer.write_u32::<NativeEndian>((**ptr).id))
}
}
}
pub fn send_args<W>(
pub fn send_args<W: ProtoWrite>(
writer: &mut W,
service: u32,
tag_bytes: &[u8],
data: *const *const (),
write_tags: bool,
) -> Result<(), Error>
where
W: Write + ?Sized,
{
) -> Result<(), Error> {
let (arg_tags_bytes, return_tag_bytes) = split_tag(tag_bytes);
let mut args_it = TagIterator::new(arg_tags_bytes);
let return_it = TagIterator::new(return_tag_bytes);
trace!("send<{}>({})->{}", service, args_it, return_it);
writer.write_u32(service)?;
writer.write_u32::<NativeEndian>(service)?;
for index in 0.. {
if let Some(arg_tag) = args_it.next() {
let mut data = unsafe { *data.offset(index) };
@ -357,7 +356,7 @@ where
}
}
writer.write_u8(0)?;
writer.write_bytes(return_tag_bytes)?;
writer.write_bytes::<NativeEndian>(return_tag_bytes)?;
Ok(())
}

View File

@ -1,8 +1,6 @@
#![no_std]
#![feature(link_cfg)]
#![feature(nll)]
#![feature(c_unwind)]
#![feature(static_nobundle)]
#![cfg_attr(not(target_env = "msvc"), feature(libc))]
cfg_if::cfg_if! {
@ -24,7 +22,12 @@ cfg_if::cfg_if! {
extern "C" {}
#[cfg(target_os = "redox")]
#[link(name = "gcc_eh", kind = "static-nobundle", cfg(target_feature = "crt-static"))]
#[link(
name = "gcc_eh",
kind = "static",
modifiers = "-bundle",
cfg(target_feature = "crt-static")
)]
#[link(name = "gcc_s", cfg(not(target_feature = "crt-static")))]
extern "C" {}

View File

@ -16,7 +16,7 @@ build_zynq = { path = "../libbuild_zynq" }
[dependencies]
num-traits = { version = "0.2", default-features = false }
num-derive = "0.3"
num-derive = "0.4"
cslice = "0.3"
log = "0.4"
embedded-hal = "0.2"
@ -25,7 +25,7 @@ crc = { version = "1.7", default-features = false }
byteorder = { version = "1.3", default-features = false }
void = { version = "1", default-features = false }
futures = { version = "0.3", default-features = false, features = ["async-await"] }
async-recursion = "0.3"
async-recursion = "1.1"
log_buffer = { version = "1.2" }
vcell = "0.1"

View File

@ -397,6 +397,42 @@ 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(aux_mutex, routing_table, timer, &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;
}
#[cfg(has_drtio)]
kernel::Message::I2cWriteRequest { busno, data } => {
let result = rtio_mgt::drtio::i2c_send_write(aux_mutex, routing_table, timer, 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;
}
#[cfg(has_drtio)]
kernel::Message::I2cReadRequest { busno, ack } => {
let result = rtio_mgt::drtio::i2c_send_read(aux_mutex, routing_table, timer, 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;
}
#[cfg(has_drtio)]
kernel::Message::SubkernelLoadRunRequest {
id,
destination: _,
@ -521,6 +557,10 @@ async fn handle_run_kernel(
.async_send(kernel::Message::UpDestinationsReply(result))
.await;
}
#[cfg(has_drtio)]
kernel::Message::RtioInitRequest => {
rtio_mgt::drtio::reset(aux_mutex, routing_table, timer).await;
}
_ => {
panic!("unexpected message from core1 while kernel was running: {:?}", reply);
}

View File

@ -2,8 +2,10 @@
#![no_main]
#![recursion_limit = "1024"] // for futures_util::select!
#![feature(alloc_error_handler)]
#![feature(const_btree_new)]
#![feature(const_btree_len)]
#![feature(panic_info_message)]
#![allow(internal_features)]
#![feature(lang_items)]
#[macro_use]
extern crate alloc;
@ -11,8 +13,9 @@ extern crate alloc;
#[cfg(all(feature = "target_kasli_soc", has_virtual_leds))]
use core::cell::RefCell;
use ksupport;
use libasync::task;
#[cfg(has_cxp_grabber)]
use libboard_artiq::cxp_phys;
#[cfg(has_drtio_eem)]
use libboard_artiq::drtio_eem;
#[cfg(feature = "target_kasli_soc")]
@ -78,6 +81,23 @@ mod grabber {
}
}
#[cfg(has_cxp_grabber)]
mod cxp {
use libasync::delay;
use libboard_artiq::cxp_grabber;
use libboard_zynq::time::Milliseconds;
use crate::GlobalTimer;
pub async fn grabber_thread(timer: GlobalTimer) {
let mut countdown = timer.countdown();
loop {
cxp_grabber::tick(timer);
delay(&mut countdown, Milliseconds(200)).await;
}
}
}
static mut LOG_BUFFER: [u8; 1 << 17] = [0; 1 << 17];
#[no_mangle]
@ -100,10 +120,10 @@ pub fn main_core0() {
info!("gateware ident: {}", identifier_read(&mut [0; 64]));
ksupport::i2c::init();
ksupport::kernel::i2c::init();
#[cfg(feature = "target_kasli_soc")]
{
let i2c_bus = unsafe { (ksupport::i2c::I2C_BUS).as_mut().unwrap() };
let i2c_bus = ksupport::kernel::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
@ -150,5 +170,11 @@ pub fn main_core0() {
task::spawn(ksupport::report_async_rtio_errors());
#[cfg(has_cxp_grabber)]
{
cxp_phys::setup();
task::spawn(cxp::grabber_thread(timer));
}
comms::main(timer, cfg);
}

View File

@ -99,7 +99,7 @@ async fn read_log_level_filter(stream: &mut TcpStream) -> Result<log::LevelFilte
async fn get_logger_buffer_pred<F>(f: F) -> LogBufferRef<'static>
where F: Fn(&LogBufferRef) -> bool {
poll_fn(|ctx| {
let logger = unsafe { BufferLogger::get_logger().as_mut().unwrap() };
let logger = BufferLogger::get_logger();
match logger.buffer() {
Some(buffer) if f(&buffer) => Poll::Ready(buffer),
_ => {
@ -435,8 +435,8 @@ mod remote_coremgmt {
_restart_idle: &Rc<Semaphore>,
) -> Result<()> {
let mut message = Vec::with_capacity(key.len() + value.len() + 4 * 2);
message.write_string(key).unwrap();
message.write_bytes(&value).unwrap();
message.write_string::<NativeEndian>(key).unwrap();
message.write_bytes::<NativeEndian>(&value).unwrap();
match drtio::partition_data(
linkno,
@ -750,7 +750,7 @@ mod local_coremgmt {
write_chunk(stream, &bytes).await?;
if log::max_level() == log::LevelFilter::Trace {
// temporarily discard all trace level log
let logger = unsafe { BufferLogger::get_logger().as_mut().unwrap() };
let logger = BufferLogger::get_logger();
logger.set_buffer_log_level(log::LevelFilter::Debug);
stream.flush().await?;
logger.set_buffer_log_level(log::LevelFilter::Trace);
@ -768,9 +768,7 @@ mod local_coremgmt {
pub async fn set_uart_log_filter(stream: &mut TcpStream, lvl: log::LevelFilter) -> Result<()> {
info!("Changing UART log level to {}", lvl);
unsafe {
BufferLogger::get_logger().as_ref().unwrap().set_uart_log_level(lvl);
}
BufferLogger::get_logger().set_uart_log_level(lvl);
write_i8(stream, Reply::Success as i8).await?;
Ok(())
}
@ -903,6 +901,7 @@ macro_rules! process {
}}
}
#[allow(dead_code)]
#[derive(Clone)]
pub struct DrtioContext(pub Rc<Mutex<bool>>, pub Rc<RefCell<RoutingTable>>, pub GlobalTimer);

View File

@ -71,3 +71,7 @@ fn soft_panic(info: &core::panic::PanicInfo) -> ! {
};
soft_panic_main(timer, cfg);
}
#[lang = "eh_personality"]
#[no_mangle]
pub extern "C" fn rust_eh_personality() {}

View File

@ -38,7 +38,7 @@ where
let ptr = storage as *mut u32;
let dest = core::slice::from_raw_parts_mut(ptr as *mut u8, length * 4);
proto_async::read_chunk(stream, dest).await?;
drop(dest);
let _ = dest;
let dest = core::slice::from_raw_parts_mut(ptr, length);
NativeEndian::from_slice_u32(dest);
}
@ -46,7 +46,7 @@ where
let ptr = storage as *mut u64;
let dest = core::slice::from_raw_parts_mut(ptr as *mut u8, length * 8);
proto_async::read_chunk(stream, dest).await?;
drop(dest);
let _ = dest;
let dest = core::slice::from_raw_parts_mut(ptr, length);
NativeEndian::from_slice_u64(dest);
}

View File

@ -1,7 +1,7 @@
#[cfg(not(feature = "target_ebaz4205"))]
use embedded_hal::blocking::delay::DelayMs;
#[cfg(has_si5324)]
use ksupport::i2c;
use ksupport::kernel::i2c;
#[cfg(not(feature = "target_ebaz4205"))]
use libboard_artiq::pl;
#[cfg(has_si5324)]
@ -446,7 +446,7 @@ pub fn init(timer: &mut GlobalTimer, cfg: &Config) {
let clk = get_rtio_clock_cfg(cfg);
#[cfg(has_si5324)]
{
let i2c = unsafe { (&mut i2c::I2C_BUS).as_mut().unwrap() };
let i2c = i2c::get_bus();
match clk {
RtioClock::Ext0_Bypass => {
info!("bypassing the PLL for RTIO clock");

View File

@ -144,7 +144,7 @@ pub mod remote_dma {
pub async fn playback_done(&mut self, source: u8, error: u8, channel: u32, timestamp: u64) {
let mut traces_locked = self.traces.async_lock().await;
let mut trace = traces_locked.get_mut(&source).unwrap();
let trace = traces_locked.get_mut(&source).unwrap();
trace.state = RemoteState::PlaybackEnded {
error: error,
channel: channel,

View File

@ -15,8 +15,8 @@ pub mod drtio {
use embedded_hal::blocking::delay::DelayMs;
#[cfg(has_drtio_eem)]
use embedded_hal::blocking::delay::DelayUs;
use ksupport::{resolve_channel_name, ASYNC_ERROR_BUSY, ASYNC_ERROR_COLLISION, ASYNC_ERROR_SEQUENCE_ERROR,
SEEN_ASYNC_ERRORS};
use ksupport::{kernel::Message as KernelMessage, resolve_channel_name, ASYNC_ERROR_BUSY, ASYNC_ERROR_COLLISION,
ASYNC_ERROR_SEQUENCE_ERROR, SEEN_ASYNC_ERRORS};
use libasync::{delay, task};
#[cfg(has_drtio_eem)]
use libboard_artiq::drtio_eem;
@ -411,29 +411,32 @@ pub mod drtio {
}
Ok(Packet::DestinationOkReply) => (),
Ok(Packet::DestinationSequenceErrorReply { channel }) => {
let global_ch = ((destination as u32) << 16) | channel as u32;
error!(
"[DEST#{}] RTIO sequence error involving channel 0x{:04x}:{}",
destination,
channel,
resolve_channel_name(channel as u32)
resolve_channel_name(global_ch)
);
unsafe { SEEN_ASYNC_ERRORS |= ASYNC_ERROR_SEQUENCE_ERROR };
}
Ok(Packet::DestinationCollisionReply { channel }) => {
let global_ch = ((destination as u32) << 16) | channel as u32;
error!(
"[DEST#{}] RTIO collision involving channel 0x{:04x}:{}",
destination,
channel,
resolve_channel_name(channel as u32)
resolve_channel_name(global_ch)
);
unsafe { SEEN_ASYNC_ERRORS |= ASYNC_ERROR_COLLISION };
}
Ok(Packet::DestinationBusyReply { channel }) => {
let global_ch = ((destination as u32) << 16) | channel as u32;
error!(
"[DEST#{}] RTIO busy error involving channel 0x{:04x}:{}",
destination,
channel,
resolve_channel_name(channel as u32)
resolve_channel_name(global_ch)
);
unsafe { SEEN_ASYNC_ERRORS |= ASYNC_ERROR_BUSY };
}
@ -544,8 +547,7 @@ pub mod drtio {
}
}
#[allow(dead_code)]
pub fn reset(aux_mutex: Rc<Mutex<bool>>, routing_table: &RoutingTable, mut timer: GlobalTimer) {
pub async fn reset(aux_mutex: &Rc<Mutex<bool>>, routing_table: &RoutingTable, mut timer: GlobalTimer) {
for linkno in 0..csr::DRTIO.len() {
unsafe {
(csr::DRTIO[linkno].reset_write)(1);
@ -560,14 +562,8 @@ pub mod drtio {
for linkno in 0..csr::DRTIO.len() {
let linkno = linkno as u8;
if task::block_on(link_rx_up(linkno, &mut timer)) {
let reply = task::block_on(aux_transact(
&aux_mutex,
linkno,
routing_table,
&Packet::ResetRequest,
timer,
));
if link_rx_up(linkno, &mut timer).await {
let reply = aux_transact(&aux_mutex, linkno, routing_table, &Packet::ResetRequest, timer).await;
match reply {
Ok(Packet::ResetAck) => (),
Ok(_) => error!("[LINK#{}] reset failed, received unexpected aux packet", linkno),
@ -926,6 +922,91 @@ pub mod drtio {
)
.await
}
pub async fn i2c_send_basic(
aux_mutex: &Rc<Mutex<bool>>,
routing_table: &RoutingTable,
timer: GlobalTimer,
request: &KernelMessage,
busno: u32,
) -> Result<bool, Error> {
let destination = (busno >> 16) as u8;
let busno = busno as u8;
let packet = match request {
KernelMessage::I2cStartRequest(_) => Packet::I2cStartRequest { destination, busno },
KernelMessage::I2cRestartRequest(_) => Packet::I2cRestartRequest { destination, busno },
KernelMessage::I2cStopRequest(_) => Packet::I2cStopRequest { destination, busno },
KernelMessage::I2cSwitchSelectRequest { address, mask, .. } => Packet::I2cSwitchSelectRequest {
destination,
busno,
address: *address,
mask: *mask,
},
_ => unreachable!(),
};
let linkno = routing_table.0[destination as usize][0] - 1;
let reply = aux_transact(aux_mutex, linkno, routing_table, &packet, timer).await?;
match reply {
Packet::I2cBasicReply { succeeded } => Ok(succeeded),
_ => Err(Error::UnexpectedReply),
}
}
pub async fn i2c_send_write(
aux_mutex: &Rc<Mutex<bool>>,
routing_table: &RoutingTable,
timer: GlobalTimer,
busno: u32,
data: u8,
) -> Result<(bool, bool), Error> {
let destination = (busno >> 16) as u8;
let busno = busno as u8;
let linkno = routing_table.0[destination as usize][0] - 1;
let reply = aux_transact(
aux_mutex,
linkno,
routing_table,
&Packet::I2cWriteRequest {
destination,
busno,
data,
},
timer,
)
.await?;
match reply {
Packet::I2cWriteReply { succeeded, ack } => Ok((succeeded, ack)),
_ => Err(Error::UnexpectedReply),
}
}
pub async fn i2c_send_read(
aux_mutex: &Rc<Mutex<bool>>,
routing_table: &RoutingTable,
timer: GlobalTimer,
busno: u32,
ack: bool,
) -> Result<(bool, u8), Error> {
let destination = (busno >> 16) as u8;
let busno = busno as u8;
let linkno = routing_table.0[destination as usize][0] - 1;
let reply = aux_transact(
aux_mutex,
linkno,
routing_table,
&Packet::I2cReadRequest {
destination,
busno,
ack,
},
timer,
)
.await?;
match reply {
Packet::I2cReadReply { succeeded, data } => Ok((succeeded, data)),
_ => Err(Error::UnexpectedReply),
}
}
}
#[cfg(not(has_drtio))]
@ -979,11 +1060,3 @@ pub fn startup(
csr::rtio_core::reset_phy_write(1);
}
}
#[allow(dead_code)]
pub fn reset(aux_mutex: Rc<Mutex<bool>>, routing_table: &RoutingTable, timer: GlobalTimer) {
unsafe {
csr::rtio_core::reset_write(1);
}
drtio::reset(aux_mutex, routing_table, timer)
}

View File

@ -40,6 +40,7 @@ impl From<DrtioError> for Error {
}
}
#[allow(dead_code)]
pub struct SubkernelFinished {
pub id: u32,
pub status: FinishStatus,

View File

@ -9,7 +9,6 @@ format_code_in_doc_comments = false
comment_width = 100
normalize_comments = false
normalize_doc_attributes = false
license_template_path = ""
format_strings = true
format_macro_matchers = true
format_macro_bodies = true
@ -19,7 +18,7 @@ fn_single_line = false
where_single_line = true
imports_indent = "Visual"
imports_layout = "Mixed"
merge_imports = true
imports_granularity = "Crate"
group_imports = "StdExternalCrate"
reorder_imports = true
reorder_modules = true
@ -37,7 +36,7 @@ enum_discrim_align_threshold = 0
match_arm_blocks = true
match_arm_leading_pipes = "Never"
force_multiline_blocks = false
fn_args_layout = "Tall"
fn_params_layout = "Tall"
brace_style = "SameLineWhere"
control_brace_style = "AlwaysSameLine"
trailing_semicolon = true
@ -54,15 +53,13 @@ use_field_init_shorthand = false
force_explicit_abi = true
condense_wildcard_suffixes = false
color = "Auto"
required_version = "1.4.37"
required_version = "1.7.0"
unstable_features = false
disable_all_formatting = false
skip_children = false
hide_parse_errors = false
error_on_line_overflow = false
error_on_unformatted = false
report_todo = "Never"
report_fixme = "Never"
ignore = []
emit_mode = "Files"
make_backup = false

View File

@ -1,6 +1,8 @@
#![no_std]
#![no_main]
#![allow(internal_features)]
#![feature(alloc_error_handler, never_type, panic_info_message)]
#![feature(lang_items)]
#[macro_use]
extern crate log;
@ -26,6 +28,8 @@ extern crate alloc;
use analyzer::Analyzer;
use dma::Manager as DmaManager;
use embedded_hal::blocking::delay::DelayUs;
#[cfg(has_drtio_eem)]
use libboard_artiq::drtio_eem;
#[cfg(has_grabber)]
use libboard_artiq::grabber;
#[cfg(feature = "target_kasli_soc")]
@ -40,7 +44,10 @@ use libboard_artiq::{drtio_routing, drtioaux,
pl::csr};
#[cfg(feature = "target_kasli_soc")]
use libboard_zynq::error_led::ErrorLED;
use libboard_zynq::{i2c::I2c, print, println, slcr, time::Milliseconds, timer::GlobalTimer};
use libboard_zynq::{i2c::{Error as I2cError, I2c},
print, println, slcr,
time::Milliseconds,
timer::GlobalTimer};
use libconfig::Config;
use libcortex_a9::{l2c::enable_l2_cache, regs::MPIDR};
use libregister::RegisterR;
@ -431,11 +438,18 @@ fn process_aux_packet(
timer
);
match i2c.write(data) {
Ok(ack) => drtioaux::send(
Ok(()) => drtioaux::send(
0,
&drtioaux::Packet::I2cWriteReply {
succeeded: true,
ack: ack,
ack: true,
},
),
Err(I2cError::Nack) => drtioaux::send(
0,
&drtioaux::Packet::I2cWriteReply {
succeeded: true,
ack: false,
},
),
Err(_) => drtioaux::send(
@ -1097,12 +1111,7 @@ fn process_aux_packet(
if let Ok(level_filter) = mgmt::byte_to_level_filter(log_level) {
info!("Changing UART log level to {}", level_filter);
unsafe {
logger::BufferLogger::get_logger()
.as_ref()
.unwrap()
.set_uart_log_level(level_filter);
}
logger::BufferLogger::get_logger().set_uart_log_level(level_filter);
drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded: true })
} else {
drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded: false })
@ -1340,6 +1349,12 @@ fn process_aux_packet(
unsafe {
csr::gt_drtio::txenable_write(0);
}
#[cfg(has_drtio_eem)]
unsafe {
csr::eem_transceiver::txenable_write(0);
}
core_manager.write_image();
info!("reboot imminent");
slcr::reboot();
@ -1523,20 +1538,20 @@ pub extern "C" fn main_core0() -> i32 {
ram::init_alloc_core0();
ksupport::i2c::init();
let mut i2c = unsafe { (ksupport::i2c::I2C_BUS).as_mut().unwrap() };
ksupport::kernel::i2c::init();
let i2c = ksupport::kernel::i2c::get_bus();
#[cfg(feature = "target_kasli_soc")]
let (mut io_expander0, mut io_expander1);
#[cfg(feature = "target_kasli_soc")]
{
io_expander0 = io_expander::IoExpander::new(&mut i2c, 0).unwrap();
io_expander1 = io_expander::IoExpander::new(&mut i2c, 1).unwrap();
io_expander0 = io_expander::IoExpander::new(i2c, 0).unwrap();
io_expander1 = io_expander::IoExpander::new(i2c, 1).unwrap();
io_expander0
.init(&mut i2c)
.init(i2c)
.expect("I2C I/O expander #0 initialization failed");
io_expander1
.init(&mut i2c)
.init(i2c)
.expect("I2C I/O expander #1 initialization failed");
// Drive CLK_SEL to true
@ -1548,12 +1563,12 @@ pub extern "C" fn main_core0() -> i32 {
io_expander1.set(0, 1, false);
io_expander0.set(1, 1, false);
io_expander1.set(1, 1, false);
io_expander0.service(&mut i2c).unwrap();
io_expander1.service(&mut i2c).unwrap();
io_expander0.service(i2c).unwrap();
io_expander1.service(i2c).unwrap();
}
#[cfg(has_si5324)]
si5324::setup(&mut i2c, &SI5324_SETTINGS, si5324::Input::Ckin1, &mut timer).expect("cannot initialize Si5324");
si5324::setup(i2c, &SI5324_SETTINGS, si5324::Input::Ckin1, &mut timer).expect("cannot initialize Si5324");
#[cfg(has_si549)]
si549::main_setup(&mut timer, &SI549_SETTINGS).expect("cannot initialize main Si549");
@ -1573,6 +1588,12 @@ pub extern "C" fn main_core0() -> i32 {
unsafe {
csr::gt_drtio::txenable_write(0xffffffffu32 as _);
}
#[cfg(has_drtio_eem)]
unsafe {
csr::eem_transceiver::txenable_write(0xffffffffu32 as _);
}
#[cfg(has_si549)]
si549::helper_setup(&mut timer, &SI549_SETTINGS).expect("cannot initialize helper Si549");
@ -1598,6 +1619,12 @@ pub extern "C" fn main_core0() -> i32 {
toggle_sed_spread(0);
}
#[cfg(has_drtio_eem)]
{
drtio_eem::init(&mut timer, &cfg);
unsafe { csr::eem_transceiver::rx_ready_write(1) }
}
#[cfg(has_drtio_routing)]
let mut repeaters = [repeater::Repeater::default(); csr::DRTIOREP.len()];
#[cfg(not(has_drtio_routing))]
@ -1624,12 +1651,8 @@ pub extern "C" fn main_core0() -> i32 {
}
#[cfg(feature = "target_kasli_soc")]
{
io_expander0
.service(&mut i2c)
.expect("I2C I/O expander #0 service failed");
io_expander1
.service(&mut i2c)
.expect("I2C I/O expander #1 service failed");
io_expander0.service(i2c).expect("I2C I/O expander #0 service failed");
io_expander1.service(i2c).expect("I2C I/O expander #1 service failed");
}
hardware_tick(&mut hardware_tick_ts, &mut timer);
@ -1638,7 +1661,7 @@ pub extern "C" fn main_core0() -> i32 {
info!("uplink is up, switching to recovered clock");
#[cfg(has_siphaser)]
{
si5324::siphaser::select_recovered_clock(&mut i2c, true, &mut timer).expect("failed to switch clocks");
si5324::siphaser::select_recovered_clock(i2c, true, &mut timer).expect("failed to switch clocks");
si5324::siphaser::calibrate_skew(&mut timer).expect("failed to calibrate skew");
}
@ -1665,7 +1688,7 @@ pub extern "C" fn main_core0() -> i32 {
&mut rank,
&mut destination,
&mut timer,
&mut i2c,
i2c,
&mut dma_manager,
&mut analyzer,
&mut kernel_manager,
@ -1678,12 +1701,8 @@ pub extern "C" fn main_core0() -> i32 {
}
#[cfg(feature = "target_kasli_soc")]
{
io_expander0
.service(&mut i2c)
.expect("I2C I/O expander #0 service failed");
io_expander1
.service(&mut i2c)
.expect("I2C I/O expander #1 service failed");
io_expander0.service(i2c).expect("I2C I/O expander #0 service failed");
io_expander1.service(i2c).expect("I2C I/O expander #1 service failed");
}
hardware_tick(&mut hardware_tick_ts, &mut timer);
if drtiosat_tsc_loaded() {
@ -1743,7 +1762,7 @@ pub extern "C" fn main_core0() -> i32 {
drtiosat_tsc_loaded();
info!("uplink is down, switching to local oscillator clock");
#[cfg(has_siphaser)]
si5324::siphaser::select_recovered_clock(&mut i2c, false, &mut timer).expect("failed to switch clocks");
si5324::siphaser::select_recovered_clock(i2c, false, &mut timer).expect("failed to switch clocks");
#[cfg(has_wrpll)]
si549::wrpll::select_recovered_clock(false, &mut timer);
}
@ -1810,3 +1829,7 @@ pub fn panic_fmt(info: &core::panic::PanicInfo) -> ! {
loop {}
}
#[lang = "eh_personality"]
#[no_mangle]
pub extern "C" fn rust_eh_personality() {}

View File

@ -1,8 +1,9 @@
use alloc::vec::Vec;
use byteorder::{ByteOrder, NativeEndian};
use core_io::Write;
use crc::crc32;
use io::{ProtoRead, ProtoWrite};
use io::ProtoRead;
use libboard_artiq::{drtioaux_proto::SAT_PAYLOAD_MAX_SIZE,
logger::{BufferLogger, LogBufferRef}};
use libconfig::Config;
@ -28,7 +29,7 @@ pub fn byte_to_level_filter(level_byte: u8) -> Result<LevelFilter> {
}
fn get_logger_buffer() -> LogBufferRef<'static> {
let logger = unsafe { BufferLogger::get_logger().as_mut().unwrap() };
let logger = BufferLogger::get_logger();
loop {
if let Some(buffer_ref) = logger.buffer() {
return buffer_ref;
@ -97,9 +98,11 @@ impl<'a> Manager<'_> {
pub fn write_config(&mut self) -> Result<()> {
let mut payload = &self.config_payload[..];
let key = payload.read_string().map_err(|_err| error!("error on reading key"))?;
let key = payload
.read_string::<NativeEndian>()
.map_err(|_err| error!("error on reading key"))?;
debug!("write key: {}", key);
let value = payload.read_bytes().unwrap();
let value = payload.read_bytes::<NativeEndian>().unwrap();
self.cfg
.write(&key, value)

View File

@ -4,11 +4,12 @@ use alloc::{collections::BTreeMap,
vec::Vec};
use core::{slice, str};
use core_io::{Error as IoError, Write};
use byteorder::NativeEndian;
use core_io::Error as IoError;
use cslice::AsCSlice;
use dma::{Error as DmaError, Manager as DmaManager};
use io::{Cursor, ProtoWrite};
use ksupport::{eh_artiq, kernel, rpc, rtio};
use ksupport::{eh_artiq, kernel, kernel::rtio, rpc};
use libboard_artiq::{drtio_routing::RoutingTable,
drtioaux,
drtioaux_proto::{PayloadStatus, MASTER_PAYLOAD_MAX_SIZE},
@ -52,6 +53,7 @@ enum KernelState {
},
}
#[allow(dead_code)]
#[derive(Debug)]
pub enum Error {
Load(String),
@ -844,6 +846,8 @@ impl<'a> Manager<'_> {
destination == (self_destination as i32),
));
}
/* core.reset() on satellites only affects the satellite, ignore the request */
kernel::Message::RtioInitRequest => {}
_ => {
unexpected!("unexpected message from core1 while kernel was running: {:?}", reply);
}
@ -980,27 +984,24 @@ impl<'a> Manager<'_> {
}
}
fn write_exception<W>(
fn write_exception<W: ProtoWrite>(
writer: &mut W,
exceptions: &[Option<eh_artiq::Exception>],
stack_pointers: &[eh_artiq::StackPointerBacktrace],
backtrace: &[(usize, usize)],
async_errors: u8,
) -> Result<(), Error>
where
W: Write + ?Sized,
{
) -> Result<(), Error> {
/* header */
writer.write_bytes(&[0x5a, 0x5a, 0x5a, 0x5a, /*Reply::KernelException*/ 9])?;
writer.write_u32(exceptions.len() as u32)?;
writer.write_bytes::<NativeEndian>(&[0x5a, 0x5a, 0x5a, 0x5a, /*Reply::KernelException*/ 9])?;
writer.write_u32::<NativeEndian>(exceptions.len() as u32)?;
for exception in exceptions.iter() {
let exception = exception.as_ref().unwrap();
writer.write_u32(exception.id)?;
writer.write_u32::<NativeEndian>(exception.id)?;
if exception.message.len() == usize::MAX {
// exception with host string
writer.write_u32(u32::MAX)?;
writer.write_u32(exception.message.as_ptr() as u32)?;
writer.write_u32::<NativeEndian>(u32::MAX)?;
writer.write_u32::<NativeEndian>(exception.message.as_ptr() as u32)?;
} else {
let msg =
str::from_utf8(unsafe { slice::from_raw_parts(exception.message.as_ptr(), exception.message.len()) })
@ -1013,26 +1014,26 @@ where
ksupport::resolve_channel_name(exception.param[0] as u32)
),
);
writer.write_string(&msg)?;
writer.write_string::<NativeEndian>(&msg)?;
}
writer.write_u64(exception.param[0] as u64)?;
writer.write_u64(exception.param[1] as u64)?;
writer.write_u64(exception.param[2] as u64)?;
writer.write_bytes(exception.file.as_ref())?;
writer.write_u32(exception.line)?;
writer.write_u32(exception.column)?;
writer.write_bytes(exception.function.as_ref())?;
writer.write_u64::<NativeEndian>(exception.param[0] as u64)?;
writer.write_u64::<NativeEndian>(exception.param[1] as u64)?;
writer.write_u64::<NativeEndian>(exception.param[2] as u64)?;
writer.write_bytes::<NativeEndian>(exception.file.as_ref())?;
writer.write_u32::<NativeEndian>(exception.line)?;
writer.write_u32::<NativeEndian>(exception.column)?;
writer.write_bytes::<NativeEndian>(exception.function.as_ref())?;
}
for sp in stack_pointers.iter() {
writer.write_u32(sp.stack_pointer as u32)?;
writer.write_u32(sp.initial_backtrace_size as u32)?;
writer.write_u32(sp.current_backtrace_size as u32)?;
writer.write_u32::<NativeEndian>(sp.stack_pointer as u32)?;
writer.write_u32::<NativeEndian>(sp.initial_backtrace_size as u32)?;
writer.write_u32::<NativeEndian>(sp.current_backtrace_size as u32)?;
}
writer.write_u32(backtrace.len() as u32)?;
writer.write_u32::<NativeEndian>(backtrace.len() as u32)?;
for &(addr, sp) in backtrace {
writer.write_u32(addr as u32)?;
writer.write_u32(sp as u32)?;
writer.write_u32::<NativeEndian>(addr as u32)?;
writer.write_u32::<NativeEndian>(sp as u32)?;
}
writer.write_u8(async_errors as u8)?;
Ok(())