forked from M-Labs/artiq-zynq
Compare commits
67 Commits
Author | SHA1 | Date | |
---|---|---|---|
afd0389bf3 | |||
f5139ee140 | |||
761b7c99cd | |||
5982937ee6 | |||
32889c11f1 | |||
bc7925989b | |||
b2256800fe | |||
637163bbca | |||
50ead76c09 | |||
267a1222ed | |||
fe09e8615e | |||
cb8fa20beb | |||
0efa450537 | |||
4c59ab933b | |||
504d7a8d5b | |||
a577238bae | |||
1c90228f84 | |||
8129b8163c | |||
95175b7168 | |||
3172625ba6 | |||
9e51599195 | |||
5445a1268c | |||
48ed2f188e | |||
64d79de6c5 | |||
be8f618d95 | |||
dca808b2e4 | |||
e4b85bf51a | |||
c2c5367572 | |||
290134e07e | |||
e07dad71d5 | |||
d0c34671d7 | |||
82a1b38a19 | |||
db76dfc209 | |||
b0ceac0f3a | |||
a0673f13a1 | |||
6086b867c8 | |||
17f59e2353 | |||
f080bee029 | |||
599442dc0d | |||
622bca24d1 | |||
bcab64f1ff | |||
dfc731a4c1 | |||
58ecf62921 | |||
11134cdfd6 | |||
2e99b9cf0d | |||
4f79ee962c | |||
d4105b79e7 | |||
1beb6fd944 | |||
ce1c430fdc | |||
cf99700299 | |||
9f1f349b29 | |||
98255ec25a | |||
421033ef98 | |||
c603a4ba12 | |||
529d7819a9 | |||
1a1a7112ca | |||
e524317eb9 | |||
d545feddbd | |||
0e6da19406 | |||
d0e2404311 | |||
cd9f8e6d7c | |||
4a2b28dcc3 | |||
21a4a0b5dd | |||
a82d356f52 | |||
8b9bb38331 | |||
63157588bb | |||
11f8675ad6 |
42
flake.lock
generated
42
flake.lock
generated
@ -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"
|
||||
},
|
||||
|
17
flake.nix
17
flake.nix
@ -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}";
|
||||
|
@ -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
64
src/Cargo.lock
generated
@ -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",
|
||||
|
@ -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",
|
||||
|
74
src/gateware/cxp_4r_fmc.py
Normal file
74
src/gateware/cxp_4r_fmc.py
Normal file
@ -0,0 +1,74 @@
|
||||
from migen.build.generic_platform import *
|
||||
|
||||
fmc_adapter_io = [
|
||||
# CoaXPress high speed link
|
||||
("CXP_HS", 0,
|
||||
Subsignal("rxp", Pins("HPC:DP0_M2C_P")),
|
||||
Subsignal("rxn", Pins("HPC:DP0_M2C_N")),
|
||||
),
|
||||
("CXP_HS", 1,
|
||||
Subsignal("rxp", Pins("HPC:DP1_M2C_P")),
|
||||
Subsignal("rxn", Pins("HPC:DP1_M2C_N")),
|
||||
),
|
||||
("CXP_HS", 2,
|
||||
Subsignal("rxp", Pins("HPC:DP2_M2C_P")),
|
||||
Subsignal("rxn", Pins("HPC:DP2_M2C_N")),
|
||||
),
|
||||
("CXP_HS", 3,
|
||||
Subsignal("rxp", Pins("HPC:DP3_M2C_P")),
|
||||
Subsignal("rxn", Pins("HPC:DP3_M2C_N")),
|
||||
),
|
||||
|
||||
# CoaXPress low speed link
|
||||
("CXP_LS", 0, Pins("HPC:LA00_CC_P"), IOStandard("LVCMOS33")),
|
||||
("CXP_LS", 1, Pins("HPC:LA01_CC_N"), IOStandard("LVCMOS33")),
|
||||
("CXP_LS", 2, Pins("HPC:LA01_CC_P"), IOStandard("LVCMOS33")),
|
||||
("CXP_LS", 3, Pins("HPC:LA02_N"), IOStandard("LVCMOS33")),
|
||||
|
||||
# CoaXPress green and red LED
|
||||
("CXP_LED", 0,
|
||||
Subsignal("green", Pins("HPC:LA11_P"), IOStandard("LVCMOS33")),
|
||||
Subsignal("red", Pins("HPC:LA11_N"), IOStandard("LVCMOS33")),
|
||||
),
|
||||
("CXP_LED", 1,
|
||||
Subsignal("green", Pins("HPC:LA12_P"), IOStandard("LVCMOS33")),
|
||||
Subsignal("red", Pins("HPC:LA12_N"), IOStandard("LVCMOS33")),
|
||||
),
|
||||
("CXP_LED", 2,
|
||||
Subsignal("green", Pins("HPC:LA13_P"), IOStandard("LVCMOS33")),
|
||||
Subsignal("red", Pins("HPC:LA13_N"), IOStandard("LVCMOS33")),
|
||||
),
|
||||
("CXP_LED", 3,
|
||||
Subsignal("green", Pins("HPC:LA14_P"), IOStandard("LVCMOS33")),
|
||||
Subsignal("red", Pins("HPC:LA14_N"), IOStandard("LVCMOS33")),
|
||||
),
|
||||
|
||||
# Power over CoaXPress
|
||||
("PoCXP", 0,
|
||||
Subsignal("enable", Pins("HPC:LA21_N"), IOStandard("LVCMOS33")),
|
||||
Subsignal("alert", Pins("HPC:LA18_CC_P"), IOStandard("LVCMOS33")),
|
||||
),
|
||||
("PoCXP", 1,
|
||||
Subsignal("enable", Pins("HPC:LA21_P"), IOStandard("LVCMOS33")),
|
||||
Subsignal("alert", Pins("HPC:LA19_N"), IOStandard("LVCMOS33")),
|
||||
),
|
||||
("PoCXP", 2,
|
||||
Subsignal("enable", Pins("HPC:LA22_N"), IOStandard("LVCMOS33")),
|
||||
Subsignal("alert", Pins("HPC:LA19_P"), IOStandard("LVCMOS33")),
|
||||
),
|
||||
("PoCXP", 3,
|
||||
Subsignal("enable", Pins("HPC:LA22_P"), IOStandard("LVCMOS33")),
|
||||
Subsignal("alert", Pins("HPC:LA20_N"), IOStandard("LVCMOS33")),
|
||||
),
|
||||
("i2c", 0,
|
||||
Subsignal("scl", Pins("HPC:IIC_SCL")),
|
||||
Subsignal("sda", Pins("HPC:IIC_SDA")),
|
||||
IOStandard("LVCMOS33")
|
||||
),
|
||||
|
||||
# On board 125MHz reference
|
||||
("clk125", 0,
|
||||
Subsignal("p", Pins("HPC:GBTCLK0_M2C_P")),
|
||||
Subsignal("n", Pins("HPC:GBTCLK0_M2C_N")),
|
||||
),
|
||||
]
|
@ -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")
|
||||
|
@ -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(
|
||||
|
@ -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" }
|
||||
|
305
src/libboard_artiq/src/cxp_camera_setup.rs
Normal file
305
src/libboard_artiq/src/cxp_camera_setup.rs
Normal 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)
|
||||
}
|
250
src/libboard_artiq/src/cxp_ctrl.rs
Normal file
250
src/libboard_artiq/src/cxp_ctrl.rs
Normal file
@ -0,0 +1,250 @@
|
||||
use core::fmt;
|
||||
|
||||
use byteorder::{ByteOrder, NetworkEndian};
|
||||
use core_io::{Error as IoError, Read, Write};
|
||||
use crc::crc32::checksum_ieee;
|
||||
use io::{Cursor, ProtoRead, ProtoWrite};
|
||||
|
||||
pub const CTRL_PACKET_MAXSIZE: usize = 128; // for compatibility with version1.x compliant Devices - Section 12.1.6 (CXP-001-2021)
|
||||
pub const DATA_MAXSIZE: usize =
|
||||
CTRL_PACKET_MAXSIZE - /*packet start KCodes, data packet types, CMD, Tag, Addr, CRC, packet end KCode*/4*7;
|
||||
|
||||
pub enum Error {
|
||||
CorruptedPacket,
|
||||
CtrlAckError(u8),
|
||||
Io(IoError),
|
||||
LengthOutOfRange(u32),
|
||||
TagMismatch,
|
||||
TimedOut,
|
||||
UnexpectedReply,
|
||||
UnknownPacket(u8),
|
||||
}
|
||||
|
||||
impl fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
&Error::CorruptedPacket => write!(f, "CorruptedPacket - Received packet fail CRC test"),
|
||||
&Error::CtrlAckError(ref ack_code) => match ack_code {
|
||||
0x40 => write!(f, "CtrlAckError - Invalid Address"),
|
||||
0x41 => write!(f, "CtrlAckError - Invalid data for the address"),
|
||||
0x42 => write!(f, "CtrlAckError - Invalid operation code"),
|
||||
0x43 => write!(f, "CtrlAckError - Write attempted to a read-only address"),
|
||||
0x44 => write!(f, "CtrlAckError - Read attempted from a write-only address"),
|
||||
0x45 => write!(f, "CtrlAckError - Size field too large, exceed packet size limit"),
|
||||
0x46 => write!(f, "CtrlAckError - Message size is inconsistent with size field"),
|
||||
0x47 => write!(f, "CtrlAckError - Malformed packet"),
|
||||
0x80 => write!(f, "CtrlAckError - Failed CRC test in last received command"),
|
||||
_ => write!(f, "CtrlAckError - Unknown ack code {:#X}", ack_code),
|
||||
},
|
||||
&Error::Io(ref err) => write!(f, "IoError - {:?}", err),
|
||||
&Error::LengthOutOfRange(length) => write!(
|
||||
f,
|
||||
"LengthOutOfRange - Message length {} is not between 1 and {}",
|
||||
length, DATA_MAXSIZE
|
||||
),
|
||||
&Error::TagMismatch => write!(f, "TagMismatch - Received tag is different from the transmitted tag"),
|
||||
&Error::TimedOut => write!(f, "MessageTimedOut"),
|
||||
&Error::UnexpectedReply => write!(f, "UnexpectedReply"),
|
||||
&Error::UnknownPacket(packet_type) => {
|
||||
write!(f, "UnknownPacket - Unknown packet type id {:#X} ", packet_type)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<IoError> for Error {
|
||||
fn from(value: IoError) -> Error {
|
||||
Error::Io(value)
|
||||
}
|
||||
}
|
||||
|
||||
fn get_cxp_crc(bytes: &[u8]) -> u32 {
|
||||
// Section 9.2.2.2 (CXP-001-2021)
|
||||
// Only Control packet need CRC32 appended in the end of the packet
|
||||
// CoaXpress use the polynomial of IEEE-802.3 (Ethernet) CRC but the checksum calculation is different
|
||||
(!checksum_ieee(bytes)).swap_bytes()
|
||||
}
|
||||
|
||||
trait CxpRead: Read {
|
||||
fn read_exact_4x(&mut self, buf: &mut [u8]) -> Result<(), Error> {
|
||||
let mut temp = [0u8; 4];
|
||||
for byte in buf {
|
||||
// Section 9.2.2.1 (CXP-001-2021)
|
||||
// decoder should immune to single bit errors when handling 4x duplicated characters
|
||||
self.read_exact(&mut temp)?;
|
||||
let [a, b, c, d] = temp;
|
||||
// vote and return majority
|
||||
*byte = a & b & c | a & b & d | a & c & d | b & c & d;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn read_4x_u8(&mut self) -> Result<u8, Error> {
|
||||
let mut bytes = [0; 1];
|
||||
self.read_exact_4x(&mut bytes)?;
|
||||
Ok(bytes[0])
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Read> CxpRead for T {}
|
||||
impl<T: Write> CxpWrite for T {}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum RXCTRLPacket {
|
||||
CtrlReply {
|
||||
tag: Option<u8>,
|
||||
length: u32,
|
||||
data: [u8; DATA_MAXSIZE],
|
||||
},
|
||||
CtrlDelay {
|
||||
tag: Option<u8>,
|
||||
time: u32,
|
||||
},
|
||||
CtrlAck {
|
||||
tag: Option<u8>,
|
||||
},
|
||||
}
|
||||
|
||||
impl RXCTRLPacket {
|
||||
pub fn read_from(reader: &mut Cursor<&[u8]>) -> Result<Self, Error> {
|
||||
match reader.read_4x_u8()? {
|
||||
0x03 => RXCTRLPacket::get_ctrl_packet(reader, false),
|
||||
0x06 => RXCTRLPacket::get_ctrl_packet(reader, true),
|
||||
ty => Err(Error::UnknownPacket(ty)),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_ctrl_packet(reader: &mut Cursor<&[u8]>, with_tag: bool) -> Result<Self, Error> {
|
||||
let mut tag: Option<u8> = None;
|
||||
if with_tag {
|
||||
tag = Some(reader.read_4x_u8()?);
|
||||
}
|
||||
|
||||
let ackcode = reader.read_4x_u8()?;
|
||||
|
||||
match ackcode {
|
||||
0x00 | 0x04 => {
|
||||
let length = reader.read_u32::<NetworkEndian>()?;
|
||||
let mut data: [u8; DATA_MAXSIZE] = [0; DATA_MAXSIZE];
|
||||
reader.read(&mut data[0..length as usize])?;
|
||||
|
||||
// Section 9.6.3 (CXP-001-2021)
|
||||
// when length is not multiple of 4, dummy bits are padded to align to the word boundary
|
||||
// set position to next word boundary for CRC calculation
|
||||
let padding = (4 - (reader.position() % 4)) % 4;
|
||||
reader.set_position(reader.position() + padding);
|
||||
|
||||
// Section 9.6.3 (CXP-001-2021)
|
||||
// only bytes after the first 4 are used in calculating the checksum
|
||||
let checksum = get_cxp_crc(&reader.get_ref()[4..reader.position()]);
|
||||
if reader.read_u32::<NetworkEndian>()? != checksum {
|
||||
return Err(Error::CorruptedPacket);
|
||||
}
|
||||
|
||||
if ackcode == 0x00 {
|
||||
return Ok(RXCTRLPacket::CtrlReply { tag, length, data });
|
||||
} else {
|
||||
return Ok(RXCTRLPacket::CtrlDelay {
|
||||
tag,
|
||||
time: NetworkEndian::read_u32(&data[..4]),
|
||||
});
|
||||
}
|
||||
}
|
||||
0x01 => return Ok(RXCTRLPacket::CtrlAck { tag }),
|
||||
_ => return Err(Error::CtrlAckError(ackcode)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
trait CxpWrite: Write {
|
||||
fn write_all_4x(&mut self, buf: &[u8]) -> Result<(), Error> {
|
||||
for byte in buf {
|
||||
self.write_all(&[*byte; 4])?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_4x_u8(&mut self, value: u8) -> Result<(), Error> {
|
||||
self.write_all_4x(&[value])
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum TXCTRLPacket {
|
||||
CtrlRead {
|
||||
tag: Option<u8>,
|
||||
addr: u32,
|
||||
length: u32,
|
||||
},
|
||||
CtrlWrite {
|
||||
tag: Option<u8>,
|
||||
addr: u32,
|
||||
length: u32,
|
||||
data: [u8; DATA_MAXSIZE],
|
||||
},
|
||||
}
|
||||
|
||||
impl TXCTRLPacket {
|
||||
pub fn write_to(&self, writer: &mut Cursor<&mut [u8]>) -> Result<(), Error> {
|
||||
match *self {
|
||||
TXCTRLPacket::CtrlRead { tag, addr, length } => {
|
||||
match tag {
|
||||
Some(t) => {
|
||||
writer.write_4x_u8(0x05)?;
|
||||
writer.write_4x_u8(t)?;
|
||||
}
|
||||
None => {
|
||||
writer.write_4x_u8(0x02)?;
|
||||
}
|
||||
}
|
||||
|
||||
let mut bytes = [0; 3];
|
||||
NetworkEndian::write_u24(&mut bytes, length);
|
||||
writer.write_all(&[0x00, bytes[0], bytes[1], bytes[2]])?;
|
||||
|
||||
writer.write_u32::<NetworkEndian>(addr)?;
|
||||
|
||||
// Section 9.6.2 (CXP-001-2021)
|
||||
// only bytes after the first 4 are used in calculating the checksum
|
||||
let checksum = get_cxp_crc(&writer.get_ref()[4..writer.position()]);
|
||||
writer.write_u32::<NetworkEndian>(checksum)?;
|
||||
}
|
||||
TXCTRLPacket::CtrlWrite {
|
||||
tag,
|
||||
addr,
|
||||
length,
|
||||
data,
|
||||
} => {
|
||||
match tag {
|
||||
Some(t) => {
|
||||
writer.write_4x_u8(0x05)?;
|
||||
writer.write_4x_u8(t)?;
|
||||
}
|
||||
None => {
|
||||
writer.write_4x_u8(0x02)?;
|
||||
}
|
||||
}
|
||||
|
||||
let mut bytes = [0; 3];
|
||||
NetworkEndian::write_u24(&mut bytes, length);
|
||||
writer.write_all(&[0x01, bytes[0], bytes[1], bytes[2]])?;
|
||||
|
||||
writer.write_u32::<NetworkEndian>(addr)?;
|
||||
writer.write_all(&data[0..length as usize])?;
|
||||
|
||||
// Section 9.6.2 (CXP-001-2021)
|
||||
// when length is not multiple of 4, dummy bites are padded to align to the word boundary
|
||||
let padding = (4 - (writer.position() % 4)) % 4;
|
||||
for _ in 0..padding {
|
||||
writer.write_u8(0)?;
|
||||
}
|
||||
|
||||
// Section 9.6.2 (CXP-001-2021)
|
||||
// only bytes after the first 4 are used in calculating the checksum
|
||||
let checksum = get_cxp_crc(&writer.get_ref()[4..writer.position()]);
|
||||
writer.write_u32::<NetworkEndian>(checksum)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
90
src/libboard_artiq/src/cxp_grabber.rs
Normal file
90
src/libboard_artiq/src/cxp_grabber.rs
Normal 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
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
192
src/libboard_artiq/src/cxp_packet.rs
Normal file
192
src/libboard_artiq/src/cxp_packet.rs
Normal 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)
|
||||
}
|
193
src/libboard_artiq/src/cxp_phys.rs
Normal file
193
src/libboard_artiq/src/cxp_phys.rs
Normal 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 {}
|
||||
}
|
||||
}
|
||||
}
|
@ -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())
|
||||
})
|
||||
|
@ -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())
|
||||
})
|
||||
|
@ -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 } => {
|
||||
|
@ -1,3 +1,5 @@
|
||||
use core::arch::asm;
|
||||
|
||||
use libboard_zynq::{println, stdio};
|
||||
use libcortex_a9::{interrupt_handler, regs::MPIDR};
|
||||
use libregister::RegisterR;
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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>> {
|
||||
|
@ -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)
|
||||
|
@ -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 {
|
||||
|
@ -1,6 +1,5 @@
|
||||
#![no_std]
|
||||
#![feature(never_type)]
|
||||
#![feature(asm)]
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
extern crate alloc;
|
||||
|
@ -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
228
src/libksupport/src/cxp.rs
Normal 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,
|
||||
}
|
||||
}
|
||||
}
|
@ -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 {
|
||||
|
@ -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) };
|
||||
}
|
@ -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};
|
||||
|
@ -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),
|
||||
|
@ -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();
|
||||
|
@ -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>) {
|
||||
|
192
src/libksupport/src/kernel/i2c.rs
Normal file
192
src/libksupport/src/kernel/i2c.rs
Normal 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() }
|
||||
}
|
@ -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,
|
||||
|
@ -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 {
|
@ -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 {
|
@ -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 {
|
||||
|
@ -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) {
|
||||
|
@ -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(())
|
||||
}
|
||||
|
@ -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" {}
|
||||
|
||||
|
@ -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"
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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() {}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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");
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -40,6 +40,7 @@ impl From<DrtioError> for Error {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub struct SubkernelFinished {
|
||||
pub id: u32,
|
||||
pub status: FinishStatus,
|
||||
|
@ -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
|
||||
|
@ -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() {}
|
||||
|
@ -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)
|
||||
|
@ -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(())
|
||||
|
Loading…
x
Reference in New Issue
Block a user