Compare commits

..

36 Commits

Author SHA1 Message Date
586fd2f17e Gateware: remove redundant si549.py & wrpll.py 2024-05-30 15:27:16 +08:00
377f8779a0 kasli soc: refactor to use wrpll from artiq 2024-05-30 15:25:33 +08:00
1fbaacfc43 flake: update artiq 2024-05-30 15:14:02 +08:00
127ea9ea4d flake: update dependencies 2024-05-28 17:30:49 +08:00
174c301d7d add llvmPackages_11 2024-05-24 15:29:29 +08:00
52defff000 flake: update dependencies 2024-05-24 15:29:19 +08:00
2b2ebb5354 aux: increase max payload size 2024-05-20 15:20:06 +08:00
4341d2d2a5 update to LLLVM 14 2024-05-09 10:05:33 +08:00
57b885ed99 flake: update dependencies 2024-05-09 10:03:57 +08:00
e922543855 flake: update dependencies 2024-05-08 18:56:15 +08:00
35ea0ed2ca WRPLL: add filter for DRTIO 100MHz 2024-05-08 18:50:55 +08:00
cdf4ff24c0 WRPLL: replace PI controller with new filter 2024-05-08 18:50:55 +08:00
285b02c4b1 WRPLL: remove anti-windup 2024-05-08 18:50:55 +08:00
53cb592d19 kasli soc: add rtio_frequency cfg for runtime 2024-05-08 16:14:56 +08:00
c261897658 rename build derivation to board-package-set 2024-04-29 13:05:49 +08:00
1d603c73b7 DDMTD: replace 1st edge to median edge deglitcher 2024-04-29 13:05:02 +08:00
61315c29b9 Si549: recalibrate TAG_OFFSET for ISERDESE2 2024-04-29 13:03:30 +08:00
3f57de6ec7 DDMTD: replace FD with ISERDESE2 2024-04-29 13:03:30 +08:00
cca23aa2a5 wrpll runtime: reduce mmcm output jitter
rtio_clocking: update mmcm setting to use HIGH bandwidth
2024-04-29 11:20:50 +08:00
2bbaea3ad5 SMAFreqMulti: set mmcm bw to HIGH for lower jitter 2024-04-29 11:20:50 +08:00
5abd274060 update copyright year 2024-04-26 12:26:30 +08:00
3abe9caadb flake: update dependencies 2024-04-26 11:37:14 +08:00
0a19f8fb89 satman: revert async flag changes 2024-04-26 11:37:14 +08:00
a30c7d1f3a runtime: drtio aux refactoring, revert async flag 2024-04-26 11:37:14 +08:00
2d10503c20 libboard_artiq: support multiple aux rx buffers 2024-04-24 17:12:57 +08:00
92a29051f7 drtio_aux_controller: support aux_buffer_count 2024-04-24 17:12:39 +08:00
14fa038118 Firmware: Runtime WRPLL
runtime: drive CLK_SEL to true when si549 is used
runtime & libboard_artiq: allow standalone to use io_expander
si549: add bit bang mmcm dynamic configuration
si549: add frequency counter for refclk
rtio_clocking & si549: add 125Mhz wrpll refclk setup
2024-04-12 16:38:46 +08:00
b81323af30 Firmware: Satman skew calibration & tester
cargo template: add calibrate_wrpll_skew feature
tag collector: add TAG_OFFSET for Satman WRPLL
tag collector: add TAG_OFFSET getter & setter for calibration
wrpll: add skew tester and calibration
wrpll: gate calibration behind calibrate_wrpll_skew feature
2024-04-12 16:38:46 +08:00
291777f764 Firmware: Satman WRPLL
satman: drive CLK_SEL to true when si549 is used
satman : add main & helper si549 setup
satman : add WRPLL select_recovered_clock
si549: add tag collector to process gtx & main tags
si549: add frequency counter to set BASE_ADPLL
si549: add set_adpll for main & helper PLL
si549: add main & helper PLL
FIQ & si549: replace dummy with a custom handler for gtx & main tags ISR
2024-04-12 16:38:39 +08:00
a1d80fb93b Firmware: Si549 and io_expander
io_expander: set CLK_SEL pin to output when si549 is used
io_expander: gate virtual leds for standalone
si549: add bit bang i2c
si549: add si549 programming
si549: add main & helper setup
2024-04-11 15:18:10 +08:00
7827c7b803 Gateware: kasli_soc WRPLL setup
kasli_soc: use enable_wrpll from json to switch from si5324 to si549
kasli_soc: add wrpll for all variants
kasli_soc: add gtx & main tag nFIQ for all variants
kasli_soc: add clk_synth_se for master & satellite
kasli_soc: add wrpll_refclk for runtime
kasli_soc: add skewtester for satman
kasli_soc: add WRPLL_REF_CLK config for firmware
2024-04-11 15:18:10 +08:00
e4d8d44c7c Gateware: WRPLL
ddmtd: add DDMTD and deglitcher
wrpll: add helper clockdomain
wrpll: add frequency counter
wrpll: add skewtester
wrpll: add gtx & main tag collection
wrpll: add gtx & main tag eventmanager for shared peripheral interrupt
wrpll: add SMA frequency multiplier to generate 125Mhz refclk
si549: add i2c and adpll programmer
2024-04-11 15:18:04 +08:00
4f34a7c6d0 flake: update artiq 2024-03-15 12:11:32 +08:00
1f7c53b8d0 flake: update zynq-rs 2024-03-08 10:18:54 +08:00
4455f740d2 main: set exception vector table addr
linker: add exceptions start & end symbol
2024-03-07 15:37:42 +08:00
63bf1c81d4 fiq: use dummy handler to fix compilation error 2024-03-07 13:26:52 +08:00
29 changed files with 1006 additions and 1331 deletions

View File

@ -62,7 +62,7 @@ Notes:
License License
------- -------
Copyright (C) 2019-2023 M-Labs Limited. Copyright (C) 2019-2024 M-Labs Limited.
ARTIQ is free software: you can redistribute it and/or modify ARTIQ is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by

56
flake.lock generated
View File

@ -11,11 +11,11 @@
"src-pythonparser": "src-pythonparser" "src-pythonparser": "src-pythonparser"
}, },
"locked": { "locked": {
"lastModified": 1706785107, "lastModified": 1716972728,
"narHash": "sha256-Uj72tqigiOCdewSSBBMg6zUpVKhwjAo1HeLJgvyZ3oc=", "narHash": "sha256-88J+eckZamtwhcCQkPpKLu6R1hmgj5+C9n2U5i+sHUE=",
"ref": "refs/heads/master", "ref": "refs/heads/master",
"rev": "3aaa7e04f26a495e8847e47424bfc16d76d82bf8", "rev": "49e402780bebba437c6098047ab1dc68eaf5a17c",
"revCount": 8672, "revCount": 8808,
"type": "git", "type": "git",
"url": "https://github.com/m-labs/artiq.git" "url": "https://github.com/m-labs/artiq.git"
}, },
@ -37,11 +37,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1701573753, "lastModified": 1707216368,
"narHash": "sha256-vhEtXjb9AM6/HnsgfVmhJQeqQ9JqysUm7iWNzTIbexs=", "narHash": "sha256-ZXoqzG2QsVsybALLYXs473avXcyKSZNh2kIgcPo60XQ=",
"owner": "m-labs", "owner": "m-labs",
"repo": "artiq-comtools", "repo": "artiq-comtools",
"rev": "199bdabf4de49cb7ada8a4ac7133008e0f8434b7", "rev": "e5d0204490bccc07ef9141b0d7c405ab01cb8273",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -103,11 +103,11 @@
"mozilla-overlay_3": { "mozilla-overlay_3": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1695805681, "lastModified": 1704373101,
"narHash": "sha256-1ElPLD8eFfnuIk0G52HGGpRtQZ4QPCjChRlEOfkZ5ro=", "narHash": "sha256-+gi59LRWRQmwROrmE1E2b3mtocwueCQqZ60CwLG+gbg=",
"owner": "mozilla", "owner": "mozilla",
"repo": "nixpkgs-mozilla", "repo": "nixpkgs-mozilla",
"rev": "6eabade97bc28d707a8b9d82ad13ef143836736e", "rev": "9b11a87c0cc54e308fa83aac5b4ee1816d5418a2",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -118,16 +118,16 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1706515015, "lastModified": 1716542732,
"narHash": "sha256-eFfY5A7wlYy3jD/75lx6IJRueg4noE+jowl0a8lIlVo=", "narHash": "sha256-0Y9fRr0CUqWT4KgBITmaGwlnNIGMYuydu2L8iLTfHU4=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "f4a8d6d5324c327dcc2d863eb7f3cc06ad630df4", "rev": "d12251ef6e8e6a46e05689eeccd595bdbd3c9e60",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "NixOS", "owner": "NixOS",
"ref": "nixos-23.11", "ref": "nixos-24.05",
"repo": "nixpkgs", "repo": "nixpkgs",
"type": "github" "type": "github"
} }
@ -147,11 +147,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1701572254, "lastModified": 1708937641,
"narHash": "sha256-ixq8dlpyOytDr+d/OmW8v1Ioy9V2G2ibOlNj8GFDSq4=", "narHash": "sha256-Hkb9VYFzFgkYxfbh4kYcDSn7DbMUYehoQDeTALrxo2Q=",
"owner": "m-labs", "owner": "m-labs",
"repo": "sipyco", "repo": "sipyco",
"rev": "cceac0df537887135f99aa6b1bdd82853f16b4d6", "rev": "4a28b311ce0069454b4e8fe1e6049db11b9f1296",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -163,11 +163,11 @@
"src-migen": { "src-migen": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1702942348, "lastModified": 1715484909,
"narHash": "sha256-gKIfHZxsv+jcgDFRW9mPqmwqbZXuRvXefkZcSFjOGHw=", "narHash": "sha256-4DCHBUBfc/VA+7NW2Hr0+JP4NnKPru2uVJyZjCCk0Ws=",
"owner": "m-labs", "owner": "m-labs",
"repo": "migen", "repo": "migen",
"rev": "50934ad10a87ade47219b796535978b9bdf24023", "rev": "4790bb577681a8c3a8d226bc196a4e5deb39e4df",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -179,11 +179,11 @@
"src-misoc": { "src-misoc": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1699352904, "lastModified": 1715647536,
"narHash": "sha256-SglyTmXOPv8jJOjwAjJrj/WhAkItQfUbvKfUqrynwRg=", "narHash": "sha256-q+USDcaKHABwW56Jzq8u94iGPWlyLXMyVt0j/Gyg+IE=",
"ref": "refs/heads/master", "ref": "refs/heads/master",
"rev": "a53859f2167c31ab5225b6c09f30cf05527b94f4", "rev": "fea9de558c730bc394a5936094ae95bb9d6fa726",
"revCount": 2452, "revCount": 2455,
"submodules": true, "submodules": true,
"type": "git", "type": "git",
"url": "https://github.com/m-labs/misoc.git" "url": "https://github.com/m-labs/misoc.git"
@ -234,11 +234,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1702982463, "lastModified": 1716519432,
"narHash": "sha256-jKR3drE2rsTaYGEgIdv5kUo2LOb1JyIb4tJhVuCXTTc=", "narHash": "sha256-vgKBJCQRPCutJ4n+FtJNczMZULWW7J3B8icf/PUothw=",
"ref": "refs/heads/master", "ref": "refs/heads/master",
"rev": "4168eb63a7e846863331ae4e656cfd82a867cca8", "rev": "46dc25b89e46b9043129d77e3c9348916748e325",
"revCount": 636, "revCount": 645,
"type": "git", "type": "git",
"url": "https://git.m-labs.hk/m-labs/zynq-rs" "url": "https://git.m-labs.hk/m-labs/zynq-rs"
}, },

View File

@ -11,6 +11,7 @@
pkgs = import artiq.inputs.nixpkgs { system = "x86_64-linux"; overlays = [ (import mozilla-overlay) ]; }; pkgs = import artiq.inputs.nixpkgs { system = "x86_64-linux"; overlays = [ (import mozilla-overlay) ]; };
zynqpkgs = zynq-rs.packages.x86_64-linux; zynqpkgs = zynq-rs.packages.x86_64-linux;
artiqpkgs = artiq.packages.x86_64-linux; artiqpkgs = artiq.packages.x86_64-linux;
llvmPackages_11 = zynq-rs.llvmPackages_11;
rust = zynq-rs.rust; rust = zynq-rs.rust;
rustPlatform = zynq-rs.rustPlatform; rustPlatform = zynq-rs.rustPlatform;
@ -113,7 +114,7 @@
"nist_clock_satellite" "nist_qc2_satellite" "acpki_nist_clock_satellite" "acpki_nist_qc2_satellite" "nist_clock_satellite" "nist_qc2_satellite" "acpki_nist_clock_satellite" "acpki_nist_qc2_satellite"
"nist_clock_satellite_100mhz" "nist_qc2_satellite_100mhz" "acpki_nist_clock_satellite_100mhz" "acpki_nist_qc2_satellite_100mhz" "nist_clock_satellite_100mhz" "nist_qc2_satellite_100mhz" "acpki_nist_clock_satellite_100mhz" "acpki_nist_qc2_satellite_100mhz"
]; ];
build = { target, variant, json ? null }: let board-package-set = { target, variant, json ? null }: let
szl = zynqpkgs."${target}-szl"; szl = zynqpkgs."${target}-szl";
fsbl = zynqpkgs."${target}-fsbl"; fsbl = zynqpkgs."${target}-fsbl";
fwtype = if builtins.elem variant sat_variants then "satman" else "runtime"; fwtype = if builtins.elem variant sat_variants then "satman" else "runtime";
@ -132,12 +133,12 @@
pkgs.gnumake pkgs.gnumake
(pkgs.python3.withPackages(ps: [ ps.jsonschema artiqpkgs.migen migen-axi artiqpkgs.misoc artiqpkgs.artiq ])) (pkgs.python3.withPackages(ps: [ ps.jsonschema artiqpkgs.migen migen-axi artiqpkgs.misoc artiqpkgs.artiq ]))
zynqpkgs.cargo-xbuild zynqpkgs.cargo-xbuild
pkgs.llvmPackages_9.llvm llvmPackages_11.llvm
pkgs.llvmPackages_9.clang-unwrapped llvmPackages_11.clang-unwrapped
]; ];
buildPhase = '' buildPhase = ''
export XARGO_RUST_SRC="${rust}/lib/rustlib/src/rust/library" export XARGO_RUST_SRC="${rust}/lib/rustlib/src/rust/library"
export CLANG_EXTRA_INCLUDE_DIR="${pkgs.llvmPackages_9.clang-unwrapped.lib}/lib/clang/9.0.1/include" export CLANG_EXTRA_INCLUDE_DIR="${llvmPackages_11.clang-unwrapped.lib}/lib/clang/11.1.0/include"
export CARGO_HOME=$(mktemp -d cargo-home.XXX) export CARGO_HOME=$(mktemp -d cargo-home.XXX)
export ZYNQ_RS=${zynq-rs} export ZYNQ_RS=${zynq-rs}
make TARGET=${target} GWARGS="${if json == null then "-V ${variant}" else json}" ${fwtype} make TARGET=${target} GWARGS="${if json == null then "-V ${variant}" else json}" ${fwtype}
@ -273,7 +274,7 @@
}; };
# for hitl-tests # for hitl-tests
zc706-nist_qc2 = (build { target = "zc706"; variant = "nist_qc2"; }); zc706-nist_qc2 = (board-package-set { target = "zc706"; variant = "nist_qc2"; });
zc706-hitl-tests = pkgs.stdenv.mkDerivation { zc706-hitl-tests = pkgs.stdenv.mkDerivation {
name = "zc706-hitl-tests"; name = "zc706-hitl-tests";
@ -340,29 +341,29 @@
{ {
inherit fastnumbers artiq-netboot ramda migen-axi binutils-arm; inherit fastnumbers artiq-netboot ramda migen-axi binutils-arm;
} // } //
(build { target = "zc706"; variant = "nist_clock"; }) // (board-package-set { target = "zc706"; variant = "nist_clock"; }) //
(build { target = "zc706"; variant = "nist_clock_master"; }) // (board-package-set { target = "zc706"; variant = "nist_clock_master"; }) //
(build { target = "zc706"; variant = "nist_clock_master_100mhz"; }) // (board-package-set { target = "zc706"; variant = "nist_clock_master_100mhz"; }) //
(build { target = "zc706"; variant = "nist_clock_satellite"; }) // (board-package-set { target = "zc706"; variant = "nist_clock_satellite"; }) //
(build { target = "zc706"; variant = "nist_clock_satellite_100mhz"; }) // (board-package-set { target = "zc706"; variant = "nist_clock_satellite_100mhz"; }) //
(build { target = "zc706"; variant = "nist_qc2"; }) // (board-package-set { target = "zc706"; variant = "nist_qc2"; }) //
(build { target = "zc706"; variant = "nist_qc2_master"; }) // (board-package-set { target = "zc706"; variant = "nist_qc2_master"; }) //
(build { target = "zc706"; variant = "nist_qc2_master_100mhz"; }) // (board-package-set { target = "zc706"; variant = "nist_qc2_master_100mhz"; }) //
(build { target = "zc706"; variant = "nist_qc2_satellite"; }) // (board-package-set { target = "zc706"; variant = "nist_qc2_satellite"; }) //
(build { target = "zc706"; variant = "nist_qc2_satellite_100mhz"; }) // (board-package-set { target = "zc706"; variant = "nist_qc2_satellite_100mhz"; }) //
(build { target = "zc706"; variant = "acpki_nist_clock"; }) // (board-package-set { target = "zc706"; variant = "acpki_nist_clock"; }) //
(build { target = "zc706"; variant = "acpki_nist_clock_master"; }) // (board-package-set { target = "zc706"; variant = "acpki_nist_clock_master"; }) //
(build { target = "zc706"; variant = "acpki_nist_clock_master_100mhz"; }) // (board-package-set { target = "zc706"; variant = "acpki_nist_clock_master_100mhz"; }) //
(build { target = "zc706"; variant = "acpki_nist_clock_satellite"; }) // (board-package-set { target = "zc706"; variant = "acpki_nist_clock_satellite"; }) //
(build { target = "zc706"; variant = "acpki_nist_clock_satellite_100mhz"; }) // (board-package-set { target = "zc706"; variant = "acpki_nist_clock_satellite_100mhz"; }) //
(build { target = "zc706"; variant = "acpki_nist_qc2"; }) // (board-package-set { target = "zc706"; variant = "acpki_nist_qc2"; }) //
(build { target = "zc706"; variant = "acpki_nist_qc2_master"; }) // (board-package-set { target = "zc706"; variant = "acpki_nist_qc2_master"; }) //
(build { target = "zc706"; variant = "acpki_nist_qc2_master_100mhz"; }) // (board-package-set { target = "zc706"; variant = "acpki_nist_qc2_master_100mhz"; }) //
(build { target = "zc706"; variant = "acpki_nist_qc2_satellite"; }) // (board-package-set { target = "zc706"; variant = "acpki_nist_qc2_satellite"; }) //
(build { target = "zc706"; variant = "acpki_nist_qc2_satellite_100mhz"; }) // (board-package-set { target = "zc706"; variant = "acpki_nist_qc2_satellite_100mhz"; }) //
(build { target = "kasli_soc"; variant = "demo"; json = ./demo.json; }) // (board-package-set { target = "kasli_soc"; variant = "demo"; json = ./demo.json; }) //
(build { target = "kasli_soc"; variant = "master"; json = ./kasli-soc-master.json; }) // (board-package-set { target = "kasli_soc"; variant = "master"; json = ./kasli-soc-master.json; }) //
(build { target = "kasli_soc"; variant = "satellite"; json = ./kasli-soc-satellite.json; }); (board-package-set { target = "kasli_soc"; variant = "satellite"; json = ./kasli-soc-satellite.json; });
hydraJobs = packages.x86_64-linux // { inherit zc706-hitl-tests; inherit gateware-sim; inherit fmt-check; }; hydraJobs = packages.x86_64-linux // { inherit zc706-hitl-tests; inherit gateware-sim; inherit fmt-check; };
@ -370,8 +371,8 @@
name = "artiq-zynq-dev-shell"; name = "artiq-zynq-dev-shell";
buildInputs = with pkgs; [ buildInputs = with pkgs; [
rust rust
llvmPackages_9.llvm llvmPackages_11.llvm
llvmPackages_9.clang-unwrapped llvmPackages_11.clang-unwrapped
gnumake gnumake
cacert cacert
zynqpkgs.cargo-xbuild zynqpkgs.cargo-xbuild
@ -384,13 +385,13 @@
binutils-arm binutils-arm
]; ];
XARGO_RUST_SRC = "${rust}/lib/rustlib/src/rust/library"; XARGO_RUST_SRC = "${rust}/lib/rustlib/src/rust/library";
CLANG_EXTRA_INCLUDE_DIR = "${pkgs.llvmPackages_9.clang-unwrapped.lib}/lib/clang/9.0.1/include"; CLANG_EXTRA_INCLUDE_DIR = "${llvmPackages_11.clang-unwrapped.lib}/lib/clang/11.1.0/include";
ZYNQ_RS = "${zynq-rs}"; ZYNQ_RS = "${zynq-rs}";
OPENOCD_ZYNQ = "${zynq-rs}/openocd"; OPENOCD_ZYNQ = "${zynq-rs}/openocd";
SZL = "${zynqpkgs.szl}"; SZL = "${zynqpkgs.szl}";
}; };
makeArtiqZynqPackage = build; makeArtiqZynqPackage = board-package-set;
}; };
} }

View File

@ -4,50 +4,98 @@ from misoc.interconnect.csr import *
class DDMTDSampler(Module): class DDMTDSampler(Module):
def __init__(self, cd_ref, main_dcxo_pads): def __init__(self, cd_ref, main_clk_se):
self.ref_beating = Signal() self.ref_beating = Signal()
self.main_beating = Signal() self.main_beating = Signal()
# # # # # #
main_clk_se = Signal() ref_clk = Signal()
ref_beating_FF = Signal() self.specials +=[
main_beating_FF = Signal() # ISERDESE2 can only be driven from fabric via IDELAYE2 (see UG471)
self.specials += [ Instance("IDELAYE2",
Instance("IBUFDS", p_DELAY_SRC="DATAIN",
i_I=main_dcxo_pads.p, i_IB=main_dcxo_pads.n, p_HIGH_PERFORMANCE_MODE="TRUE",
o_O=main_clk_se), p_REFCLK_FREQUENCY=208.3, # REFCLK frequency from IDELAYCTRL
# Two back to back FFs are used to prevent metastability p_IDELAY_VALUE=0,
Instance("FD", i_C=ClockSignal("helper"),
i_D=cd_ref.clk, o_Q=ref_beating_FF), i_DATAIN=cd_ref.clk,
Instance("FD", i_C=ClockSignal("helper"),
i_D=ref_beating_FF, o_Q=self.ref_beating), o_DATAOUT=ref_clk
Instance("FD", i_C=ClockSignal("helper"), ),
i_D=main_clk_se, o_Q=main_beating_FF), Instance("ISERDESE2",
Instance("FD", i_C=ClockSignal("helper"), p_IOBDELAY="IFD", # use DDLY as input
i_D=main_beating_FF, o_Q=self.main_beating) p_DATA_RATE="SDR",
p_DATA_WIDTH=2, # min is 2
p_NUM_CE=1,
i_DDLY=ref_clk,
i_CE1=1,
i_CLK=ClockSignal("helper"),
i_CLKDIV=ClockSignal("helper"),
o_Q1=self.ref_beating
),
Instance("ISERDESE2",
p_DATA_RATE="SDR",
p_DATA_WIDTH=2, # min is 2
p_NUM_CE=1,
i_D=main_clk_se,
i_CE1=1,
i_CLK=ClockSignal("helper"),
i_CLKDIV=ClockSignal("helper"),
o_Q1=self.main_beating,
),
] ]
class DDMTDDeglitcherFirstEdge(Module): class DDMTDDeglitcherMedianEdge(Module):
def __init__(self, input_signal, blind_period=300): def __init__(self, counter, input_signal, stable_0_period=100, stable_1_period=100):
self.tag = Signal(len(counter))
self.detect = Signal() self.detect = Signal()
rising = Signal()
input_signal_r = Signal() stable_0_counter = Signal(reset=stable_0_period - 1, max=stable_0_period)
stable_1_counter = Signal(reset=stable_1_period - 1, max=stable_1_period)
# # # # # #
self.sync.helper += [ # Based on CERN's median edge deglitcher FSM
input_signal_r.eq(input_signal), # https://white-rabbit.web.cern.ch/documents/Precise_time_and_frequency_transfer_in_a_White_Rabbit_network.pdf (p.72)
rising.eq(input_signal & ~input_signal_r) fsm = ClockDomainsRenamer("helper")(FSM(reset_state="WAIT_STABLE_0"))
] self.submodules += fsm
blind_counter = Signal(max=blind_period) fsm.act("WAIT_STABLE_0",
self.sync.helper += [ If(stable_0_counter != 0,
If(blind_counter != 0, blind_counter.eq(blind_counter - 1)), NextValue(stable_0_counter, stable_0_counter - 1)
If(input_signal_r, blind_counter.eq(blind_period - 1)), ).Else(
self.detect.eq(rising & (blind_counter == 0)) NextValue(stable_0_counter, stable_0_period - 1),
] NextState("WAIT_EDGE")
),
If(input_signal,
NextValue(stable_0_counter, stable_0_period - 1)
),
)
fsm.act("WAIT_EDGE",
If(input_signal,
NextValue(self.tag, counter),
NextState("GOT_EDGE")
)
)
fsm.act("GOT_EDGE",
If(stable_1_counter != 0,
NextValue(stable_1_counter, stable_1_counter - 1)
).Else(
NextValue(stable_1_counter, stable_1_period - 1),
self.detect.eq(1),
NextState("WAIT_STABLE_0")
),
If(~input_signal,
NextValue(self.tag, self.tag + 1),
NextValue(stable_1_counter, stable_1_period - 1)
),
)
class DDMTD(Module): class DDMTD(Module):
@ -59,13 +107,13 @@ class DDMTD(Module):
# # # # # #
deglitcher = DDMTDDeglitcherFirstEdge(input_signal) deglitcher = DDMTDDeglitcherMedianEdge(counter, input_signal)
self.submodules += deglitcher self.submodules += deglitcher
self.sync.helper += [ self.sync.helper += [
self.h_tag_update.eq(0), self.h_tag_update.eq(0),
If(deglitcher.detect, If(deglitcher.detect,
self.h_tag_update.eq(1), self.h_tag_update.eq(1),
self.h_tag.eq(counter) self.h_tag.eq(deglitcher.tag)
) )
] ]

View File

@ -1,12 +1,12 @@
"""Auxiliary controller, common to satellite and master""" """Auxiliary controller, common to satellite and master"""
from artiq.gateware.drtio.aux_controller import Transmitter, Receiver from artiq.gateware.drtio.aux_controller import (max_packet, aux_buffer_count,
Transmitter, Receiver)
from migen.fhdl.simplify import FullMemoryWE from migen.fhdl.simplify import FullMemoryWE
from misoc.interconnect.csr import * from misoc.interconnect.csr import *
from migen_axi.interconnect.sram import SRAM from migen_axi.interconnect.sram import SRAM
from migen_axi.interconnect import axi from migen_axi.interconnect import axi
max_packet = 1024
class _DRTIOAuxControllerBase(Module): class _DRTIOAuxControllerBase(Module):
def __init__(self, link_layer): def __init__(self, link_layer):
@ -27,12 +27,12 @@ class DRTIOAuxControllerAxi(_DRTIOAuxControllerBase):
tx_sdram_if = SRAM(self.transmitter.mem, read_only=False) tx_sdram_if = SRAM(self.transmitter.mem, read_only=False)
rx_sdram_if = SRAM(self.receiver.mem, read_only=True) rx_sdram_if = SRAM(self.receiver.mem, read_only=True)
aw_decoder = axi.AddressDecoder(self.bus.aw, aw_decoder = axi.AddressDecoder(self.bus.aw,
[(lambda a: a[log2_int(max_packet)] == 0, tx_sdram_if.bus.aw), [(lambda a: a[log2_int(max_packet*aux_buffer_count)] == 0, tx_sdram_if.bus.aw),
(lambda a: a[log2_int(max_packet)] == 1, rx_sdram_if.bus.aw)], (lambda a: a[log2_int(max_packet*aux_buffer_count)] == 1, rx_sdram_if.bus.aw)],
register=True) register=True)
ar_decoder = axi.AddressDecoder(self.bus.ar, ar_decoder = axi.AddressDecoder(self.bus.ar,
[(lambda a: a[log2_int(max_packet)] == 0, tx_sdram_if.bus.ar), [(lambda a: a[log2_int(max_packet*aux_buffer_count)] == 0, tx_sdram_if.bus.ar),
(lambda a: a[log2_int(max_packet)] == 1, rx_sdram_if.bus.ar)], (lambda a: a[log2_int(max_packet*aux_buffer_count)] == 1, rx_sdram_if.bus.ar)],
register=True) register=True)
# unlike wb, axi address decoder only connects ar/aw lanes, # unlike wb, axi address decoder only connects ar/aw lanes,
# the rest must also be connected! # the rest must also be connected!
@ -82,4 +82,4 @@ class DRTIOAuxControllerBare(_DRTIOAuxControllerBase):
return self.receiver.mem.get_port(write_capable=False) return self.receiver.mem.get_port(write_capable=False)
def get_mem_size(self): def get_mem_size(self):
return max_packet return max_packet*aux_buffer_count

View File

@ -20,14 +20,13 @@ from artiq.gateware.drtio.transceiver import gtx_7series, eem_serdes
from artiq.gateware.drtio.siphaser import SiPhaser7Series from artiq.gateware.drtio.siphaser import SiPhaser7Series
from artiq.gateware.drtio.rx_synchronizer import XilinxRXSynchronizer from artiq.gateware.drtio.rx_synchronizer import XilinxRXSynchronizer
from artiq.gateware.drtio import * from artiq.gateware.drtio import *
from artiq.gateware.wrpll import wrpll
import dma import dma
import analyzer import analyzer
import acpki import acpki
import drtio_aux_controller import drtio_aux_controller
import zynq_clocking import zynq_clocking
import wrpll
import si549
from config import write_csr_file, write_mem_file, write_rustc_cfg_file from config import write_csr_file, write_mem_file, write_rustc_cfg_file
eem_iostandard_dict = { eem_iostandard_dict = {
@ -107,9 +106,10 @@ class GTPBootstrapClock(Module):
class GenericStandalone(SoCCore): class GenericStandalone(SoCCore):
def __init__(self, description, acpki=False, with_wrpll=False): def __init__(self, description, acpki=False):
self.acpki = acpki self.acpki = acpki
clk_freq = description["rtio_frequency"] clk_freq = description["rtio_frequency"]
with_wrpll = description["enable_wrpll"]
platform = kasli_soc.Platform() platform = kasli_soc.Platform()
platform.toolchain.bitstream_commands.extend([ platform.toolchain.bitstream_commands.extend([
@ -121,13 +121,6 @@ class GenericStandalone(SoCCore):
SoCCore.__init__(self, platform=platform, csr_data_width=32, ident=ident, ps_cd_sys=False) SoCCore.__init__(self, platform=platform, csr_data_width=32, ident=ident, ps_cd_sys=False)
self.config["HW_REV"] = description["hw_rev"] self.config["HW_REV"] = description["hw_rev"]
self.submodules += SMAClkinForward(self.platform)
self.config["HAS_SI5324"] = None
self.config["SI5324_SOFT_RESET"] = None
clk_synth = platform.request("cdr_clk_clean_fabric") clk_synth = platform.request("cdr_clk_clean_fabric")
clk_synth_se = Signal() clk_synth_se = Signal()
clk_synth_se_buf = Signal() clk_synth_se_buf = Signal()
@ -142,6 +135,7 @@ class GenericStandalone(SoCCore):
] ]
fix_serdes_timing_path(platform) fix_serdes_timing_path(platform)
self.submodules.bootstrap = GTPBootstrapClock(self.platform, clk_freq) self.submodules.bootstrap = GTPBootstrapClock(self.platform, clk_freq)
self.config["RTIO_FREQUENCY"] = str(clk_freq/1e6)
self.config["CLOCK_FREQUENCY"] = int(clk_freq) self.config["CLOCK_FREQUENCY"] = int(clk_freq)
self.submodules.sys_crg = zynq_clocking.SYSCRG(self.platform, self.ps7, clk_synth_se_buf) self.submodules.sys_crg = zynq_clocking.SYSCRG(self.platform, self.ps7, clk_synth_se_buf)
@ -151,6 +145,23 @@ class GenericStandalone(SoCCore):
self.crg = self.ps7 # HACK for eem_7series to find the clock self.crg = self.ps7 # HACK for eem_7series to find the clock
self.crg.cd_sys = self.sys_crg.cd_sys self.crg.cd_sys = self.sys_crg.cd_sys
if with_wrpll:
self.submodules.wrpll_refclk = wrpll.FrequencyMultiplier(platform.request("sma_clkin"))
self.submodules.wrpll = wrpll.WRPLL(
platform=self.platform,
cd_ref=self.wrpll_refclk.cd_ref,
main_clk_se=clk_synth_se)
self.csr_devices.append("wrpll_refclk")
self.csr_devices.append("wrpll")
self.comb += self.ps7.core.core0.nfiq.eq(self.wrpll.ev.irq)
self.config["HAS_SI549"] = None
self.config["WRPLL_REF_CLK"] = "SMA_CLKIN"
else:
self.submodules += SMAClkinForward(self.platform)
self.config["HAS_SI5324"] = None
self.config["SI5324_SOFT_RESET"] = None
self.rtio_channels = [] self.rtio_channels = []
has_grabber = any(peripheral["type"] == "grabber" for peripheral in description["peripherals"]) has_grabber = any(peripheral["type"] == "grabber" for peripheral in description["peripherals"])
if has_grabber: if has_grabber:
@ -207,8 +218,9 @@ class GenericStandalone(SoCCore):
class GenericMaster(SoCCore): class GenericMaster(SoCCore):
def __init__(self, description, acpki=False, with_wrpll=False): def __init__(self, description, acpki=False):
clk_freq = description["rtio_frequency"] clk_freq = description["rtio_frequency"]
with_wrpll = description["enable_wrpll"]
has_drtio_over_eem = any(peripheral["type"] == "shuttler" for peripheral in description["peripherals"]) has_drtio_over_eem = any(peripheral["type"] == "shuttler" for peripheral in description["peripherals"])
self.acpki = acpki self.acpki = acpki
@ -259,16 +271,16 @@ class GenericMaster(SoCCore):
self.specials += MultiReg(self.sys_crg.clk_sw_fsm.o_clk_sw & self.sys_crg.mmcm_locked, self.gt_drtio.clk_path_ready, odomain="bootstrap") self.specials += MultiReg(self.sys_crg.clk_sw_fsm.o_clk_sw & self.sys_crg.mmcm_locked, self.gt_drtio.clk_path_ready, odomain="bootstrap")
if with_wrpll: if with_wrpll:
self.submodules.wrpll_refclk = wrpll.SMAFrequencyMultiplier(platform.request("sma_clkin")) clk_synth = platform.request("cdr_clk_clean_fabric")
self.submodules.main_dcxo = si549.Si549(platform.request("ddmtd_main_dcxo_i2c")) clk_synth_se = Signal()
self.submodules.helper_dcxo = si549.Si549(platform.request("ddmtd_helper_dcxo_i2c")) platform.add_period_constraint(clk_synth.p, 8.0)
self.specials += Instance("IBUFGDS", p_DIFF_TERM="TRUE", p_IBUF_LOW_PWR="FALSE", i_I=clk_synth.p, i_IB=clk_synth.n, o_O=clk_synth_se)
self.submodules.wrpll_refclk = wrpll.FrequencyMultiplier(platform.request("sma_clkin"))
self.submodules.wrpll = wrpll.WRPLL( self.submodules.wrpll = wrpll.WRPLL(
platform=self.platform,
cd_ref=self.wrpll_refclk.cd_ref, cd_ref=self.wrpll_refclk.cd_ref,
main_dcxo_pads=platform.request("cdr_clk_clean_fabric"), main_clk_se=clk_synth_se)
helper_dcxo_pads=platform.request("ddmtd_helper_clk"))
self.csr_devices.append("wrpll_refclk") self.csr_devices.append("wrpll_refclk")
self.csr_devices.append("main_dcxo")
self.csr_devices.append("helper_dcxo")
self.csr_devices.append("wrpll") self.csr_devices.append("wrpll")
self.comb += self.ps7.core.core0.nfiq.eq(self.wrpll.ev.irq) self.comb += self.ps7.core.core0.nfiq.eq(self.wrpll.ev.irq)
self.config["HAS_SI549"] = None self.config["HAS_SI549"] = None
@ -416,8 +428,9 @@ class GenericMaster(SoCCore):
class GenericSatellite(SoCCore): class GenericSatellite(SoCCore):
def __init__(self, description, acpki=False, with_wrpll=False): def __init__(self, description, acpki=False):
clk_freq = description["rtio_frequency"] clk_freq = description["rtio_frequency"]
with_wrpll = description["enable_wrpll"]
self.acpki = acpki self.acpki = acpki
@ -570,18 +583,20 @@ class GenericSatellite(SoCCore):
self.config["CLOCK_FREQUENCY"] = int(clk_freq) self.config["CLOCK_FREQUENCY"] = int(clk_freq)
if with_wrpll: if with_wrpll:
self.submodules.main_dcxo = si549.Si549(platform.request("ddmtd_main_dcxo_i2c")) clk_synth = platform.request("cdr_clk_clean_fabric")
self.submodules.helper_dcxo = si549.Si549(platform.request("ddmtd_helper_dcxo_i2c")) clk_synth_se = Signal()
platform.add_period_constraint(clk_synth.p, 8.0)
self.specials += Instance("IBUFGDS", p_DIFF_TERM="TRUE", p_IBUF_LOW_PWR="FALSE", i_I=clk_synth.p, i_IB=clk_synth.n, o_O=clk_synth_se)
self.submodules.wrpll = wrpll.WRPLL( self.submodules.wrpll = wrpll.WRPLL(
platform=self.platform,
cd_ref=self.gt_drtio.cd_rtio_rx0, cd_ref=self.gt_drtio.cd_rtio_rx0,
main_dcxo_pads=platform.request("cdr_clk_clean_fabric"), main_clk_se=clk_synth_se)
helper_dcxo_pads=platform.request("ddmtd_helper_clk")) self.submodules.wrpll_skewtester = wrpll.SkewTester(self.rx_synchronizer)
self.csr_devices.append("main_dcxo") self.csr_devices.append("wrpll_skewtester")
self.csr_devices.append("helper_dcxo")
self.csr_devices.append("wrpll") self.csr_devices.append("wrpll")
self.comb += self.ps7.core.core0.nfiq.eq(self.wrpll.ev.irq) self.comb += self.ps7.core.core0.nfiq.eq(self.wrpll.ev.irq)
self.config["HAS_SI549"] = None self.config["HAS_SI549"] = None
self.config["WRPLL_REF_CLK"] = "GTX_CDR" self.config["WRPLL_REF_CLK"] = "GT_CDR"
else: else:
self.submodules.siphaser = SiPhaser7Series( self.submodules.siphaser = SiPhaser7Series(
si5324_clkin=platform.request("cdr_clk"), si5324_clkin=platform.request("cdr_clk"),
@ -620,8 +635,6 @@ def main():
help="build gateware into the specified directory") help="build gateware into the specified directory")
parser.add_argument("--acpki", default=False, action="store_true", parser.add_argument("--acpki", default=False, action="store_true",
help="enable ACPKI") help="enable ACPKI")
parser.add_argument("--with-wrpll", default=True, action="store_true",
help="enable WRPLL")
parser.add_argument("description", metavar="DESCRIPTION", parser.add_argument("description", metavar="DESCRIPTION",
help="JSON system description file") help="JSON system description file")
args = parser.parse_args() args = parser.parse_args()
@ -639,7 +652,7 @@ def main():
else: else:
raise ValueError("Invalid DRTIO role") raise ValueError("Invalid DRTIO role")
soc = cls(description, acpki=args.acpki, with_wrpll=args.with_wrpll) soc = cls(description, acpki=args.acpki)
soc.finalize() soc.finalize()
if args.r is not None: if args.r is not None:

View File

@ -1,278 +0,0 @@
from migen import *
from migen.genlib.fsm import *
from misoc.interconnect.csr import *
class I2CClockGen(Module):
def __init__(self, width):
self.load = Signal(width)
self.clk2x = Signal()
cnt = Signal.like(self.load)
self.comb += [
self.clk2x.eq(cnt == 0),
]
self.sync += [
If(self.clk2x,
cnt.eq(self.load),
).Else(
cnt.eq(cnt - 1),
)
]
class I2CMasterMachine(Module):
def __init__(self, clock_width):
self.scl = Signal(reset=1)
self.sda_o = Signal(reset=1)
self.sda_i = Signal()
self.submodules.cg = CEInserter()(I2CClockGen(clock_width))
self.start = Signal()
self.stop = Signal()
self.write = Signal()
self.ack = Signal()
self.data = Signal(8)
self.ready = Signal()
# # #
bits = Signal(4)
data = Signal(8)
fsm = CEInserter()(FSM("IDLE"))
self.submodules += fsm
fsm.act("IDLE",
self.ready.eq(1),
If(self.start,
NextState("START0"),
).Elif(self.stop,
NextState("STOP0"),
).Elif(self.write,
NextValue(bits, 8),
NextValue(data, self.data),
NextState("WRITE0")
)
)
fsm.act("START0",
NextValue(self.scl, 1),
NextState("START1")
)
fsm.act("START1",
NextValue(self.sda_o, 0),
NextState("IDLE")
)
fsm.act("STOP0",
NextValue(self.scl, 0),
NextState("STOP1")
)
fsm.act("STOP1",
NextValue(self.sda_o, 0),
NextState("STOP2")
)
fsm.act("STOP2",
NextValue(self.scl, 1),
NextState("STOP3")
)
fsm.act("STOP3",
NextValue(self.sda_o, 1),
NextState("IDLE")
)
fsm.act("WRITE0",
NextValue(self.scl, 0),
NextState("WRITE1")
)
fsm.act("WRITE1",
If(bits == 0,
NextValue(self.sda_o, 1),
NextState("READACK0"),
).Else(
NextValue(self.sda_o, data[7]),
NextState("WRITE2"),
)
)
fsm.act("WRITE2",
NextValue(self.scl, 1),
NextValue(data[1:], data[:-1]),
NextValue(bits, bits - 1),
NextState("WRITE0"),
)
fsm.act("READACK0",
NextValue(self.scl, 1),
NextState("READACK1"),
)
fsm.act("READACK1",
NextValue(self.ack, ~self.sda_i),
NextState("IDLE")
)
run = Signal()
idle = Signal()
self.comb += [
run.eq((self.start | self.stop | self.write) & self.ready),
idle.eq(~run & fsm.ongoing("IDLE")),
self.cg.ce.eq(~idle),
fsm.ce.eq(run | self.cg.clk2x),
]
class ADPLLProgrammer(Module):
def __init__(self):
self.i2c_divider = Signal(16)
self.i2c_address = Signal(7)
self.adpll = Signal(24)
self.stb = Signal()
self.busy = Signal()
self.nack = Signal()
self.scl = Signal()
self.sda_i = Signal()
self.sda_o = Signal()
# # #
master = I2CMasterMachine(16)
self.submodules += master
self.comb += [
master.cg.load.eq(self.i2c_divider),
self.scl.eq(master.scl),
master.sda_i.eq(self.sda_i),
self.sda_o.eq(master.sda_o)
]
fsm = FSM()
self.submodules += fsm
adpll = Signal.like(self.adpll)
fsm.act("IDLE",
If(self.stb,
NextValue(adpll, self.adpll),
NextState("START")
)
)
fsm.act("START",
master.start.eq(1),
If(master.ready, NextState("DEVADDRESS"))
)
fsm.act("DEVADDRESS",
master.data.eq(self.i2c_address << 1),
master.write.eq(1),
If(master.ready, NextState("REGADRESS"))
)
fsm.act("REGADRESS",
master.data.eq(231),
master.write.eq(1),
If(master.ready,
If(master.ack,
NextState("DATA0")
).Else(
self.nack.eq(1),
NextState("STOP")
)
)
)
fsm.act("DATA0",
master.data.eq(adpll[0:8]),
master.write.eq(1),
If(master.ready,
If(master.ack,
NextState("DATA1")
).Else(
self.nack.eq(1),
NextState("STOP")
)
)
)
fsm.act("DATA1",
master.data.eq(adpll[8:16]),
master.write.eq(1),
If(master.ready,
If(master.ack,
NextState("DATA2")
).Else(
self.nack.eq(1),
NextState("STOP")
)
)
)
fsm.act("DATA2",
master.data.eq(adpll[16:24]),
master.write.eq(1),
If(master.ready,
If(~master.ack, self.nack.eq(1)),
NextState("STOP")
)
)
fsm.act("STOP",
master.stop.eq(1),
If(master.ready,
If(~master.ack, self.nack.eq(1)),
NextState("IDLE")
)
)
self.comb += self.busy.eq(~fsm.ongoing("IDLE"))
class Si549(Module, AutoCSR):
def __init__(self, pads):
self.i2c_divider = CSRStorage(16, reset=75)
self.i2c_address = CSRStorage(7)
self.adpll = CSRStorage(24)
self.adpll_stb = CSRStorage()
self.adpll_busy = CSRStatus()
self.nack = CSRStatus()
self.bitbang_enable = CSRStorage()
self.sda_oe = CSRStorage()
self.sda_out = CSRStorage()
self.sda_in = CSRStatus()
self.scl_oe = CSRStorage()
self.scl_out = CSRStorage()
# # #
self.submodules.programmer = ADPLLProgrammer()
self.comb += [
self.programmer.i2c_divider.eq(self.i2c_divider.storage),
self.programmer.i2c_address.eq(self.i2c_address.storage),
self.programmer.adpll.eq(self.adpll.storage),
self.programmer.stb.eq(self.adpll_stb.storage),
self.adpll_busy.status.eq(self.programmer.busy),
self.nack.status.eq(self.programmer.nack)
]
# I2C with bitbang/gateware mode select
sda_t = TSTriple(1)
scl_t = TSTriple(1)
self.specials += [
sda_t.get_tristate(pads.sda),
scl_t.get_tristate(pads.scl)
]
self.comb += [
If(self.bitbang_enable.storage,
sda_t.oe.eq(self.sda_oe.storage),
sda_t.o.eq(self.sda_out.storage),
self.sda_in.status.eq(sda_t.i),
scl_t.oe.eq(self.scl_oe.storage),
scl_t.o.eq(self.scl_out.storage)
).Else(
sda_t.oe.eq(~self.programmer.sda_o),
sda_t.o.eq(0),
self.programmer.sda_i.eq(sda_t.i),
scl_t.oe.eq(~self.programmer.scl),
scl_t.o.eq(0),
)
]

View File

@ -1,185 +0,0 @@
from migen import *
from migen.genlib.cdc import MultiReg, AsyncResetSynchronizer, PulseSynchronizer
from misoc.interconnect.csr import *
from misoc.interconnect.csr_eventmanager import *
from ddmtd import DDMTDSampler, DDMTD
class FrequencyCounter(Module, AutoCSR):
def __init__(self, domains, counter_width=24):
for domain in domains:
name = "counter_" + domain
counter = CSRStatus(counter_width, name=name)
setattr(self, name, counter)
self.update_en = CSRStorage()
timer = Signal(counter_width)
timer_tick = Signal()
self.sync += Cat(timer, timer_tick).eq(timer + 1)
for domain in domains:
sync_domain = getattr(self.sync, domain)
divider = Signal(2)
sync_domain += divider.eq(divider + 1)
divided = Signal()
sync_domain += divided.eq(divider[-1])
divided_sys = Signal()
self.specials += MultiReg(divided, divided_sys)
divided_sys_r = Signal()
divided_tick = Signal()
self.sync += divided_sys_r.eq(divided_sys)
self.comb += divided_tick.eq(divided_sys & ~divided_sys_r)
counter = Signal(counter_width)
counter_csr = getattr(self, "counter_" + domain)
self.sync += [
If(timer_tick,
If(self.update_en.storage, counter_csr.status.eq(counter)),
counter.eq(0),
).Else(
If(divided_tick, counter.eq(counter + 1))
)
]
class WRPLL(Module, AutoCSR):
def __init__(self, cd_ref, main_dcxo_pads, helper_dcxo_pads, COUNTER_BIT=32):
self.ref_tag = CSRStatus(COUNTER_BIT)
self.main_tag = CSRStatus(COUNTER_BIT)
ddmtd_counter = Signal(COUNTER_BIT)
ref_tag_sys = Signal(COUNTER_BIT)
main_tag_sys = Signal(COUNTER_BIT)
ref_tag_stb_sys = Signal()
main_tag_stb_sys = Signal()
# # #
self.helper_reset = CSRStorage()
self.clock_domains.cd_helper = ClockDomain()
self.specials += [
Instance("IBUFGDS",
i_I=helper_dcxo_pads.p, i_IB=helper_dcxo_pads.n,
o_O=self.cd_helper.clk),
AsyncResetSynchronizer(self.cd_helper, self.helper_reset.storage)
]
self.submodules.frequency_counter = FrequencyCounter(["sys", cd_ref.name])
self.submodules.ddmtd_sampler = DDMTDSampler(cd_ref, main_dcxo_pads)
self.sync.helper += ddmtd_counter.eq(ddmtd_counter + 1)
self.submodules.ddmtd_ref = DDMTD(ddmtd_counter, self.ddmtd_sampler.ref_beating)
self.submodules.ddmtd_main = DDMTD(ddmtd_counter, self.ddmtd_sampler.main_beating)
# DDMTD tags collection
self.specials += [
MultiReg(self.ddmtd_ref.h_tag, ref_tag_sys),
MultiReg(self.ddmtd_main.h_tag, main_tag_sys)
]
ref_tag_stb_ps = PulseSynchronizer("helper", "sys")
main_tag_stb_ps = PulseSynchronizer("helper", "sys")
self.submodules += [
ref_tag_stb_ps,
main_tag_stb_ps
]
self.sync.helper += [
ref_tag_stb_ps.i.eq(self.ddmtd_ref.h_tag_update),
main_tag_stb_ps.i.eq(self.ddmtd_main.h_tag_update)
]
self.sync += [
ref_tag_stb_sys.eq(ref_tag_stb_ps.o),
main_tag_stb_sys.eq(main_tag_stb_ps.o)
]
self.sync += [
If(ref_tag_stb_sys,
self.ref_tag.status.eq(ref_tag_sys),
),
If(main_tag_stb_sys,
self.main_tag.status.eq(main_tag_sys)
)
]
# PL->PS interrupt
self.submodules.ref_tag_ev = EventManager()
self.ref_tag_ev.stb = EventSourcePulse()
self.ref_tag_ev.finalize()
self.submodules.main_tag_ev = EventManager()
self.main_tag_ev.stb = EventSourcePulse()
self.main_tag_ev.finalize()
self.sync += [
self.ref_tag_ev.stb.trigger.eq(ref_tag_stb_sys),
self.main_tag_ev.stb.trigger.eq(main_tag_stb_sys)
]
self.submodules.ev = SharedIRQ(self.ref_tag_ev, self.main_tag_ev)
class SMAFrequencyMultiplier(Module, AutoCSR):
def __init__(self, sma_clkin):
freq = 125e6
period = 1e9/freq # ns
sma_clkin_se = Signal()
mmcm_locked = Signal()
mmcm_fb_clk = Signal()
ref_clk = Signal()
self.clock_domains.cd_ref = ClockDomain()
self.mmcm_locked = CSRStatus()
self.mmcm_reset = CSRStorage()
self.mmcm_daddr = CSRStorage(7)
self.mmcm_din = CSRStorage(16)
self.mmcm_dwen = CSRStorage()
self.mmcm_den = CSRStorage()
self.mmcm_dclk = CSRStorage()
self.mmcm_dout = CSRStatus(16)
self.mmcm_dready = CSRStatus()
# # #
self.specials += [
Instance("IBUFDS",
i_I=sma_clkin.p, i_IB=sma_clkin.n,
o_O=sma_clkin_se),
# MMCME2 is capable to accept 10Mhz input while PLLE2 only support down to 19Mhz input (DS191)
Instance("MMCME2_ADV",
p_BANDWIDTH="LOW", # lower jitter
o_LOCKED=self.mmcm_locked.status,
i_RST=self.mmcm_reset.storage,
p_CLKIN1_PERIOD=period,
i_CLKIN1=sma_clkin_se,
i_CLKINSEL=1, # 1=CLKIN1 0=CLKIN2
# VCO @ 1.25Ghz
p_CLKFBOUT_MULT_F=10, p_DIVCLK_DIVIDE=1,
i_CLKFBIN=mmcm_fb_clk, o_CLKFBOUT=mmcm_fb_clk,
# 125Mhz for WRPLL
p_CLKOUT0_DIVIDE_F=10, p_CLKOUT0_PHASE=0.0, o_CLKOUT0=ref_clk,
# Dynamic Reconfiguration Port
i_DADDR = self.mmcm_daddr.storage,
i_DI = self.mmcm_din.storage,
i_DWE = self.mmcm_dwen.storage,
i_DEN = self.mmcm_den.storage,
i_DCLK = self.mmcm_dclk.storage,
o_DO = self.mmcm_dout.status,
o_DRDY = self.mmcm_dready.status
),
Instance("BUFG", i_I=ref_clk, o_O=self.cd_ref.clk),
AsyncResetSynchronizer(self.cd_ref, ~self.mmcm_locked.status),
]

View File

@ -10,6 +10,7 @@ name = "libboard_artiq"
[features] [features]
target_zc706 = ["libboard_zynq/target_zc706", "libconfig/target_zc706"] target_zc706 = ["libboard_zynq/target_zc706", "libconfig/target_zc706"]
target_kasli_soc = ["libboard_zynq/target_kasli_soc", "libconfig/target_kasli_soc"] target_kasli_soc = ["libboard_zynq/target_kasli_soc", "libconfig/target_kasli_soc"]
calibrate_wrpll_skew = []
[build-dependencies] [build-dependencies]
build_zynq = { path = "../libbuild_zynq" } build_zynq = { path = "../libbuild_zynq" }

View File

@ -1,9 +1,10 @@
use core::slice;
use core_io::{Error as IoError, ErrorKind as IoErrorKind}; use core_io::{Error as IoError, ErrorKind as IoErrorKind};
use crc; use crc;
use io::{proto::{ProtoRead, ProtoWrite}, use io::{proto::{ProtoRead, ProtoWrite},
Cursor}; Cursor};
use libboard_zynq::{time::Milliseconds, timer::GlobalTimer}; use libboard_zynq::{time::Milliseconds, timer::GlobalTimer};
use libcortex_a9::asm::dmb;
pub use crate::drtioaux_proto::Packet; pub use crate::drtioaux_proto::Packet;
use crate::{drtioaux_proto::Error as ProtocolError, mem::mem::DRTIOAUX_MEM, pl::csr::DRTIOAUX}; use crate::{drtioaux_proto::Error as ProtocolError, mem::mem::DRTIOAUX_MEM, pl::csr::DRTIOAUX};
@ -56,30 +57,14 @@ pub fn has_rx_error(linkno: u8) -> bool {
} }
} }
pub fn copy_work_buffer(src: *mut u32, dst: *mut u32, len: isize) {
// AXI writes must be 4-byte aligned (drtio proto doesn't care for that),
// and AXI burst reads/writes are not implemented yet in gateware
// thus the need for a work buffer for transmitting and copying it over
unsafe {
for i in 0..(len / 4) {
*dst.offset(i) = *src.offset(i);
//data memory barrier to prevent bursts
dmb();
}
}
}
fn receive<F, T>(linkno: u8, f: F) -> Result<Option<T>, Error> fn receive<F, T>(linkno: u8, f: F) -> Result<Option<T>, Error>
where F: FnOnce(&[u8]) -> Result<T, Error> { where F: FnOnce(&[u8]) -> Result<T, Error> {
let linkidx = linkno as usize; let linkidx = linkno as usize;
unsafe { unsafe {
if (DRTIOAUX[linkidx].aux_rx_present_read)() == 1 { if (DRTIOAUX[linkidx].aux_rx_present_read)() == 1 {
let ptr = (DRTIOAUX_MEM[linkidx].base + DRTIOAUX_MEM[linkidx].size / 2) as *mut u32; let read_ptr = (DRTIOAUX[linkidx].aux_read_pointer_read)() as usize;
let len = (DRTIOAUX[linkidx].aux_rx_length_read)() as usize; let ptr = (DRTIOAUX_MEM[linkidx].base + DRTIOAUX_MEM[linkidx].size / 2 + read_ptr * 0x400) as *mut u32;
// work buffer to accomodate axi burst reads let result = f(slice::from_raw_parts(ptr as *mut u8, 0x400 as usize));
let mut buf: [u8; 1024] = [0; 1024];
copy_work_buffer(ptr, buf.as_mut_ptr() as *mut u32, len as isize);
let result = f(&buf[0..len]);
(DRTIOAUX[linkidx].aux_rx_present_write)(1); (DRTIOAUX[linkidx].aux_rx_present_write)(1);
Ok(Some(result?)) Ok(Some(result?))
} else { } else {
@ -100,15 +85,15 @@ pub fn recv(linkno: u8) -> Result<Option<Packet>, Error> {
let mut reader = Cursor::new(buffer); let mut reader = Cursor::new(buffer);
let checksum_at = buffer.len() - 4; let packet = Packet::read_from(&mut reader)?;
let padding = (12 - (reader.position() % 8)) % 8;
let checksum_at = reader.position() + padding;
let checksum = crc::crc32::checksum_ieee(&reader.get_ref()[0..checksum_at]); let checksum = crc::crc32::checksum_ieee(&reader.get_ref()[0..checksum_at]);
reader.set_position(checksum_at); reader.set_position(checksum_at);
if reader.read_u32()? != checksum { if reader.read_u32()? != checksum {
return Err(Error::CorruptedPacket); return Err(Error::CorruptedPacket);
} }
reader.set_position(0); Ok(packet)
Ok(Packet::read_from(&mut reader)?)
}) })
} }
@ -130,11 +115,7 @@ where F: FnOnce(&mut [u8]) -> Result<usize, Error> {
unsafe { unsafe {
while (DRTIOAUX[linkno].aux_tx_read)() != 0 {} while (DRTIOAUX[linkno].aux_tx_read)() != 0 {}
let ptr = DRTIOAUX_MEM[linkno].base as *mut u32; let ptr = DRTIOAUX_MEM[linkno].base as *mut u32;
let len = DRTIOAUX_MEM[linkno].size / 2; let len = f(slice::from_raw_parts_mut(ptr as *mut u8, 0x400 as usize))?;
// work buffer, works with unaligned mem access
let mut buf: [u8; 1024] = [0; 1024];
let len = f(&mut buf[0..len])?;
copy_work_buffer(buf.as_mut_ptr() as *mut u32, ptr, len as isize);
(DRTIOAUX[linkno].aux_tx_length_write)(len as u16); (DRTIOAUX[linkno].aux_tx_length_write)(len as u16);
(DRTIOAUX[linkno].aux_tx_write)(1); (DRTIOAUX[linkno].aux_tx_write)(1);
Ok(()) Ok(())

View File

@ -1,3 +1,5 @@
use core::slice;
use core_io::{Error as IoError, ErrorKind as IoErrorKind}; use core_io::{Error as IoError, ErrorKind as IoErrorKind};
use crc; use crc;
use io::{proto::{ProtoRead, ProtoWrite}, use io::{proto::{ProtoRead, ProtoWrite},
@ -8,7 +10,7 @@ use nb;
use void::Void; use void::Void;
pub use crate::drtioaux_proto::Packet; pub use crate::drtioaux_proto::Packet;
use crate::{drtioaux::{copy_work_buffer, has_rx_error, Error}, use crate::{drtioaux::{has_rx_error, Error},
mem::mem::DRTIOAUX_MEM, mem::mem::DRTIOAUX_MEM,
pl::csr::DRTIOAUX}; pl::csr::DRTIOAUX};
@ -38,12 +40,9 @@ where F: FnOnce(&[u8]) -> Result<T, Error> {
let linkidx = linkno as usize; let linkidx = linkno as usize;
unsafe { unsafe {
if (DRTIOAUX[linkidx].aux_rx_present_read)() == 1 { if (DRTIOAUX[linkidx].aux_rx_present_read)() == 1 {
let ptr = (DRTIOAUX_MEM[linkidx].base + DRTIOAUX_MEM[linkidx].size / 2) as *mut u32; let read_ptr = (DRTIOAUX[linkidx].aux_read_pointer_read)() as usize;
let len = (DRTIOAUX[linkidx].aux_rx_length_read)() as usize; let ptr = (DRTIOAUX_MEM[linkidx].base + DRTIOAUX_MEM[linkidx].size / 2 + read_ptr * 0x400) as *mut u32;
// work buffer to accomodate axi burst reads let result = f(slice::from_raw_parts(ptr as *mut u8, 0x400 as usize));
let mut buf: [u8; 1024] = [0; 1024];
copy_work_buffer(ptr, buf.as_mut_ptr() as *mut u32, len as isize);
let result = f(&buf[0..len]);
(DRTIOAUX[linkidx].aux_rx_present_write)(1); (DRTIOAUX[linkidx].aux_rx_present_write)(1);
Ok(Some(result?)) Ok(Some(result?))
} else { } else {
@ -64,15 +63,15 @@ pub async fn recv(linkno: u8) -> Result<Option<Packet>, Error> {
let mut reader = Cursor::new(buffer); let mut reader = Cursor::new(buffer);
let checksum_at = buffer.len() - 4; let packet = Packet::read_from(&mut reader)?;
let padding = (12 - (reader.position() % 8)) % 8;
let checksum_at = reader.position() + padding;
let checksum = crc::crc32::checksum_ieee(&reader.get_ref()[0..checksum_at]); let checksum = crc::crc32::checksum_ieee(&reader.get_ref()[0..checksum_at]);
reader.set_position(checksum_at); reader.set_position(checksum_at);
if reader.read_u32()? != checksum { if reader.read_u32()? != checksum {
return Err(Error::CorruptedPacket); return Err(Error::CorruptedPacket);
} }
reader.set_position(0); Ok(packet)
Ok(Packet::read_from(&mut reader)?)
}) })
.await .await
} }
@ -103,11 +102,7 @@ where F: FnOnce(&mut [u8]) -> Result<usize, Error> {
unsafe { unsafe {
let _ = block_async!(tx_ready(linkno)).await; let _ = block_async!(tx_ready(linkno)).await;
let ptr = DRTIOAUX_MEM[linkno].base as *mut u32; let ptr = DRTIOAUX_MEM[linkno].base as *mut u32;
let len = DRTIOAUX_MEM[linkno].size / 2; let len = f(slice::from_raw_parts_mut(ptr as *mut u8, 0x400 as usize))?;
// work buffer, works with unaligned mem access
let mut buf: [u8; 1024] = [0; 1024];
let len = f(&mut buf[0..len])?;
copy_work_buffer(buf.as_mut_ptr() as *mut u32, ptr, len as isize);
(DRTIOAUX[linkno].aux_tx_length_write)(len as u16); (DRTIOAUX[linkno].aux_tx_length_write)(len as u16);
(DRTIOAUX[linkno].aux_tx_write)(1); (DRTIOAUX[linkno].aux_tx_write)(1);
Ok(()) Ok(())

View File

@ -1,9 +1,11 @@
use core_io::{Error as IoError, Read, Write}; use core_io::{Error as IoError, Read, Write};
use io::proto::{ProtoRead, ProtoWrite}; use io::proto::{ProtoRead, ProtoWrite};
const MAX_PACKET: usize = 1024;
// maximum size of arbitrary payloads // maximum size of arbitrary payloads
// used by satellite -> master analyzer, subkernel exceptions // used by satellite -> master analyzer, subkernel exceptions
pub const SAT_PAYLOAD_MAX_SIZE: usize = /*max size*/512 - /*CRC*/4 - /*packet ID*/1 - /*last*/1 - /*length*/2; pub const SAT_PAYLOAD_MAX_SIZE: usize = /*max size*/MAX_PACKET - /*CRC*/4 - /*packet ID*/1 - /*last*/1 - /*length*/2;
// used by DDMA, subkernel program data (need to provide extra ID and destination) // used by DDMA, subkernel program data (need to provide extra ID and destination)
pub const MASTER_PAYLOAD_MAX_SIZE: usize = SAT_PAYLOAD_MAX_SIZE - /*source*/1 - /*destination*/1 - /*ID*/4; pub const MASTER_PAYLOAD_MAX_SIZE: usize = SAT_PAYLOAD_MAX_SIZE - /*source*/1 - /*destination*/1 - /*ID*/4;
@ -89,8 +91,6 @@ pub enum Packet {
RoutingSetRank { RoutingSetRank {
rank: u8, rank: u8,
}, },
RoutingRetrievePackets,
RoutingNoPackets,
RoutingAck, RoutingAck,
MonitorRequest { MonitorRequest {
@ -325,8 +325,6 @@ impl Packet {
rank: reader.read_u8()?, rank: reader.read_u8()?,
}, },
0x32 => Packet::RoutingAck, 0x32 => Packet::RoutingAck,
0x33 => Packet::RoutingRetrievePackets,
0x34 => Packet::RoutingNoPackets,
0x40 => Packet::MonitorRequest { 0x40 => Packet::MonitorRequest {
destination: reader.read_u8()?, destination: reader.read_u8()?,
@ -602,8 +600,6 @@ impl Packet {
writer.write_u8(rank)?; writer.write_u8(rank)?;
} }
Packet::RoutingAck => writer.write_u8(0x32)?, Packet::RoutingAck => writer.write_u8(0x32)?,
Packet::RoutingRetrievePackets => writer.write_u8(0x33)?,
Packet::RoutingNoPackets => writer.write_u8(0x34)?,
Packet::MonitorRequest { Packet::MonitorRequest {
destination, destination,

View File

@ -1,15 +1,15 @@
#[cfg(has_wrpll)]
use libboard_artiq::si549;
use libboard_zynq::{println, stdio}; use libboard_zynq::{println, stdio};
use libcortex_a9::{interrupt_handler, regs::MPIDR}; use libcortex_a9::{interrupt_handler, regs::MPIDR};
use libregister::RegisterR; use libregister::RegisterR;
#[cfg(has_si549)]
use crate::si549;
interrupt_handler!(FIQ, fiq, __irq_stack0_start, __irq_stack1_start, { interrupt_handler!(FIQ, fiq, __irq_stack0_start, __irq_stack1_start, {
// println!("hello?");
match MPIDR.read().cpu_id() { match MPIDR.read().cpu_id() {
0 => { 0 => {
// nFIQ is driven directly and bypass GIC // nFIQ is driven directly and bypass GIC
#[cfg(has_wrpll)] #[cfg(has_si549)]
si549::wrpll::interrupt_handler(); si549::wrpll::interrupt_handler();
return; return;
} }

View File

@ -1,6 +1,7 @@
use libboard_zynq::i2c; use libboard_zynq::i2c;
use log::info; use log::info;
#[cfg(has_virtual_leds)]
use crate::pl::csr; use crate::pl::csr;
// Only the bare minimum registers. Bits/IO connections equivalent between IC types. // Only the bare minimum registers. Bits/IO connections equivalent between IC types.
@ -37,6 +38,7 @@ const IODIR1: [u8; 2] = [
pub struct IoExpander { pub struct IoExpander {
address: u8, address: u8,
#[cfg(has_virtual_leds)]
virtual_led_mapping: &'static [(u8, u8, u8)], virtual_led_mapping: &'static [(u8, u8, u8)],
iodir: [u8; 2], iodir: [u8; 2],
out_current: [u8; 2], out_current: [u8; 2],
@ -46,17 +48,18 @@ pub struct IoExpander {
impl IoExpander { impl IoExpander {
pub fn new(i2c: &mut i2c::I2c, index: u8) -> Result<Self, &'static str> { pub fn new(i2c: &mut i2c::I2c, index: u8) -> Result<Self, &'static str> {
#[cfg(hw_rev = "v1.0")] #[cfg(all(hw_rev = "v1.0", has_virtual_leds))]
const VIRTUAL_LED_MAPPING0: [(u8, u8, u8); 2] = [(0, 0, 6), (1, 1, 6)]; const VIRTUAL_LED_MAPPING0: [(u8, u8, u8); 2] = [(0, 0, 6), (1, 1, 6)];
#[cfg(hw_rev = "v1.1")] #[cfg(all(hw_rev = "v1.1", has_virtual_leds))]
const VIRTUAL_LED_MAPPING0: [(u8, u8, u8); 2] = [(0, 0, 7), (1, 1, 6)]; const VIRTUAL_LED_MAPPING0: [(u8, u8, u8); 2] = [(0, 0, 7), (1, 1, 6)];
#[cfg(has_virtual_leds)]
const VIRTUAL_LED_MAPPING1: [(u8, u8, u8); 2] = [(2, 0, 6), (3, 1, 6)]; const VIRTUAL_LED_MAPPING1: [(u8, u8, u8); 2] = [(2, 0, 6), (3, 1, 6)];
// Both expanders on SHARED I2C bus // Both expanders on SHARED I2C bus
let mut io_expander = match index { let mut io_expander = match index {
0 => IoExpander { 0 => IoExpander {
address: 0x40, address: 0x40,
#[cfg(has_virtual_leds)]
virtual_led_mapping: &VIRTUAL_LED_MAPPING0, virtual_led_mapping: &VIRTUAL_LED_MAPPING0,
iodir: IODIR0, iodir: IODIR0,
out_current: [0; 2], out_current: [0; 2],
@ -70,6 +73,7 @@ impl IoExpander {
}, },
1 => IoExpander { 1 => IoExpander {
address: 0x42, address: 0x42,
#[cfg(has_virtual_leds)]
virtual_led_mapping: &VIRTUAL_LED_MAPPING1, virtual_led_mapping: &VIRTUAL_LED_MAPPING1,
iodir: IODIR1, iodir: IODIR1,
out_current: [0; 2], out_current: [0; 2],

View File

@ -1,5 +1,7 @@
#![no_std] #![no_std]
#![feature(never_type)] #![feature(never_type)]
#![feature(naked_functions)]
#![feature(asm)]
extern crate core_io; extern crate core_io;
extern crate crc; extern crate crc;
@ -19,7 +21,8 @@ pub mod drtioaux;
#[cfg(has_drtio)] #[cfg(has_drtio)]
pub mod drtioaux_async; pub mod drtioaux_async;
pub mod drtioaux_proto; pub mod drtioaux_proto;
#[cfg(all(feature = "target_kasli_soc", has_drtio))] pub mod fiq;
#[cfg(feature = "target_kasli_soc")]
pub mod io_expander; pub mod io_expander;
pub mod logger; pub mod logger;
#[cfg(has_drtio)] #[cfg(has_drtio)]

View File

@ -7,17 +7,16 @@ use crate::pl::csr;
#[cfg(feature = "target_kasli_soc")] #[cfg(feature = "target_kasli_soc")]
const ADDRESS: u8 = 0x67; const ADDRESS: u8 = 0x67;
#[derive(Clone, Copy)] const ADPLL_MAX: i32 = (950.0 / 0.0001164) as i32;
pub struct DividerConfig { pub struct DividerConfig {
pub hsdiv: u16, pub hsdiv: u16,
pub lsdiv: u8, pub lsdiv: u8,
pub fbdiv: u64, pub fbdiv: u64,
} }
#[derive(Clone, Copy)]
pub struct FrequencySetting { pub struct FrequencySetting {
pub main: DividerConfig, pub main: DividerConfig,
#[cfg(has_wrpll)]
pub helper: DividerConfig, pub helper: DividerConfig,
} }
@ -27,7 +26,6 @@ mod i2c {
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub enum DCXO { pub enum DCXO {
Main, Main,
#[cfg(has_wrpll)]
Helper, Helper,
} }
@ -37,45 +35,40 @@ mod i2c {
fn sda_i(dcxo: DCXO) -> bool { fn sda_i(dcxo: DCXO) -> bool {
match dcxo { match dcxo {
DCXO::Main => unsafe { csr::main_dcxo::sda_in_read() == 1 }, DCXO::Main => unsafe { csr::wrpll::main_dcxo_sda_in_read() == 1 },
#[cfg(has_wrpll)] DCXO::Helper => unsafe { csr::wrpll::helper_dcxo_sda_in_read() == 1 },
DCXO::Helper => unsafe { csr::helper_dcxo::sda_in_read() == 1 },
} }
} }
fn sda_oe(dcxo: DCXO, oe: bool) { fn sda_oe(dcxo: DCXO, oe: bool) {
let val = if oe { 1 } else { 0 }; let val = if oe { 1 } else { 0 };
match dcxo { match dcxo {
DCXO::Main => unsafe { csr::main_dcxo::sda_oe_write(val) }, DCXO::Main => unsafe { csr::wrpll::main_dcxo_sda_oe_write(val) },
#[cfg(has_wrpll)] DCXO::Helper => unsafe { csr::wrpll::helper_dcxo_sda_oe_write(val) },
DCXO::Helper => unsafe { csr::helper_dcxo::sda_oe_write(val) },
}; };
} }
fn sda_o(dcxo: DCXO, o: bool) { fn sda_o(dcxo: DCXO, o: bool) {
let val = if o { 1 } else { 0 }; let val = if o { 1 } else { 0 };
match dcxo { match dcxo {
DCXO::Main => unsafe { csr::main_dcxo::sda_out_write(val) }, DCXO::Main => unsafe { csr::wrpll::main_dcxo_sda_out_write(val) },
#[cfg(has_wrpll)] DCXO::Helper => unsafe { csr::wrpll::helper_dcxo_sda_out_write(val) },
DCXO::Helper => unsafe { csr::helper_dcxo::sda_out_write(val) },
}; };
} }
fn scl_oe(dcxo: DCXO, oe: bool) { fn scl_oe(dcxo: DCXO, oe: bool) {
let val = if oe { 1 } else { 0 }; let val = if oe { 1 } else { 0 };
match dcxo { match dcxo {
DCXO::Main => unsafe { csr::main_dcxo::scl_oe_write(val) }, DCXO::Main => unsafe { csr::wrpll::main_dcxo_scl_oe_write(val) },
#[cfg(has_wrpll)] DCXO::Helper => unsafe { csr::wrpll::helper_dcxo_scl_oe_write(val) },
DCXO::Helper => unsafe { csr::helper_dcxo::scl_oe_write(val) },
}; };
} }
fn scl_o(dcxo: DCXO, o: bool) { fn scl_o(dcxo: DCXO, o: bool) {
let val = if o { 1 } else { 0 }; let val = if o { 1 } else { 0 };
match dcxo { match dcxo {
DCXO::Main => unsafe { csr::main_dcxo::scl_out_write(val) }, DCXO::Main => unsafe { csr::wrpll::main_dcxo_scl_out_write(val) },
#[cfg(has_wrpll)] DCXO::Helper => unsafe { csr::wrpll::helper_dcxo_scl_out_write(val) },
DCXO::Helper => unsafe { csr::helper_dcxo::scl_out_write(val) },
}; };
} }
@ -219,7 +212,7 @@ fn read(dcxo: i2c::DCXO, reg: u8, timer: &mut GlobalTimer) -> Result<u8, &'stati
Ok(val) Ok(val)
} }
fn setup(dcxo: i2c::DCXO, config: DividerConfig, timer: &mut GlobalTimer) -> Result<(), &'static str> { fn setup(dcxo: i2c::DCXO, config: &DividerConfig, timer: &mut GlobalTimer) -> Result<(), &'static str> {
i2c::init(dcxo, timer)?; i2c::init(dcxo, timer)?;
write(dcxo, 255, 0x00, timer)?; // PAGE write(dcxo, 255, 0x00, timer)?; // PAGE
@ -252,47 +245,137 @@ fn setup(dcxo: i2c::DCXO, config: DividerConfig, timer: &mut GlobalTimer) -> Res
Ok(()) Ok(())
} }
pub fn main_setup(timer: &mut GlobalTimer, settings: FrequencySetting) -> Result<(), &'static str> { pub fn main_setup(timer: &mut GlobalTimer, settings: &FrequencySetting) -> Result<(), &'static str> {
unsafe { unsafe {
csr::main_dcxo::bitbang_enable_write(1); csr::wrpll::main_dcxo_bitbang_enable_write(1);
csr::main_dcxo::i2c_address_write(ADDRESS); csr::wrpll::main_dcxo_i2c_address_write(ADDRESS);
} }
setup(i2c::DCXO::Main, settings.main, timer)?; setup(i2c::DCXO::Main, &settings.main, timer)?;
// Si549 maximum settling time for large frequency change. // Si549 maximum settling time for large frequency change.
timer.delay_us(40_000); timer.delay_us(40_000);
unsafe { unsafe {
csr::main_dcxo::bitbang_enable_write(0); csr::wrpll::main_dcxo_bitbang_enable_write(0);
} }
info!("Main Si549 started"); info!("Main Si549 started");
Ok(()) Ok(())
} }
pub fn helper_setup(timer: &mut GlobalTimer, settings: &FrequencySetting) -> Result<(), &'static str> {
unsafe {
csr::wrpll::helper_reset_write(1);
csr::wrpll::helper_dcxo_bitbang_enable_write(1);
csr::wrpll::helper_dcxo_i2c_address_write(ADDRESS);
}
setup(i2c::DCXO::Helper, &settings.helper, timer)?;
// Si549 maximum settling time for large frequency change.
timer.delay_us(40_000);
unsafe {
csr::wrpll::helper_reset_write(0);
csr::wrpll::helper_dcxo_bitbang_enable_write(0);
}
info!("Helper Si549 started");
Ok(())
}
fn set_adpll(dcxo: i2c::DCXO, adpll: i32) -> Result<(), &'static str> {
if adpll.abs() > ADPLL_MAX {
return Err("adpll is too large");
}
match dcxo {
i2c::DCXO::Main => unsafe {
if csr::wrpll::main_dcxo_bitbang_enable_read() == 1 {
return Err("Main si549 bitbang mode is active when using gateware i2c");
}
while csr::wrpll::main_dcxo_adpll_busy_read() == 1 {}
if csr::wrpll::main_dcxo_nack_read() == 1 {
return Err("Main si549 failed to ack adpll write");
}
csr::wrpll::main_dcxo_i2c_address_write(ADDRESS);
csr::wrpll::main_dcxo_adpll_write(adpll as u32);
csr::wrpll::main_dcxo_adpll_stb_write(1);
},
i2c::DCXO::Helper => unsafe {
if csr::wrpll::helper_dcxo_bitbang_enable_read() == 1 {
return Err("Helper si549 bitbang mode is active when using gateware i2c");
}
while csr::wrpll::helper_dcxo_adpll_busy_read() == 1 {}
if csr::wrpll::helper_dcxo_nack_read() == 1 {
return Err("Helper si549 failed to ack adpll write");
}
csr::wrpll::helper_dcxo_i2c_address_write(ADDRESS);
csr::wrpll::helper_dcxo_adpll_write(adpll as u32);
csr::wrpll::helper_dcxo_adpll_stb_write(1);
},
};
Ok(())
}
#[cfg(has_wrpll)] #[cfg(has_wrpll)]
pub mod wrpll { pub mod wrpll {
use embedded_hal::blocking::delay::DelayMs;
use libcortex_a9::mutex::Mutex;
use super::*; use super::*;
const TIMER_WIDTH: u32 = 24; const BEATING_PERIOD: i32 = 0x8000;
const COUNTER_DIV: u32 = 2; const BEATING_HALFPERIOD: i32 = 0x4000;
const COUNTER_WIDTH: u32 = 24;
const DIV_WIDTH: u32 = 2;
const ADPLL_MAX: i32 = (950.0 / 0.0001164) as i32; // y[n] = b0*x[n] + b1*x[n-1] + b2*x[n-2] - a1*y[n-1] - a2*y[n-2]
struct FilterParameters {
pub b0: f64,
pub b1: f64,
pub b2: f64,
pub a1: f64,
pub a2: f64,
}
const KP: i32 = 6; #[cfg(rtio_frequency = "100.0")]
const KI: i32 = 2; const LPF: FilterParameters = FilterParameters {
b0: 0.03967479060647884,
b1: 0.07934958121295768,
b2: 0.03967479060647884,
a1: -1.3865593741228928,
a2: 0.5452585365488082,
};
static BASE_ADPLL: Mutex<i32> = Mutex::new(0); #[cfg(rtio_frequency = "125.0")]
static H_INTEGRATOR: Mutex<i32> = Mutex::new(0); const LPF: FilterParameters = FilterParameters {
static M_INTEGRATOR: Mutex<i32> = Mutex::new(0); b0: 0.07209205036273991,
b1: 0.14418410072547982,
b2: 0.07209205036273991,
a1: -0.6114078511562919,
a2: -0.10022394739274834,
};
static mut H_ADPLL1: i32 = 0;
static mut H_ADPLL2: i32 = 0;
static mut PERIOD_ERR1: i32 = 0;
static mut PERIOD_ERR2: i32 = 0;
static mut M_ADPLL1: i32 = 0;
static mut M_ADPLL2: i32 = 0;
static mut PHASE_ERR1: i32 = 0;
static mut PHASE_ERR2: i32 = 0;
static mut BASE_ADPLL: i32 = 0;
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub enum FIQ { pub enum ISR {
RefTag, RefTag,
MainTag, MainTag,
} }
@ -300,46 +383,62 @@ pub mod wrpll {
mod tag_collector { mod tag_collector {
use super::*; use super::*;
const BEATING_PERIOD: i32 = 0x8000; #[cfg(wrpll_ref_clk = "GT_CDR")]
const BEATING_HALFPERIOD: i32 = 0x4000; static mut TAG_OFFSET: u32 = 8382;
#[cfg(wrpll_ref_clk = "SMA_CLKIN")]
static REF_TAG: Mutex<u32> = Mutex::new(0); static mut TAG_OFFSET: u32 = 0;
static REF_TAG_READY: Mutex<bool> = Mutex::new(false); static mut REF_TAG: u32 = 0;
static MAIN_TAG: Mutex<u32> = Mutex::new(0); static mut REF_TAG_READY: bool = false;
static MAIN_TAG_READY: Mutex<bool> = Mutex::new(false); static mut MAIN_TAG: u32 = 0;
static mut MAIN_TAG_READY: bool = false;
pub fn reset() { pub fn reset() {
clear_phase_diff_ready(); clear_phase_diff_ready();
*REF_TAG.lock() = 0; unsafe {
*MAIN_TAG.lock() = 0; REF_TAG = 0;
MAIN_TAG = 0;
}
} }
pub fn clear_phase_diff_ready() { pub fn clear_phase_diff_ready() {
*REF_TAG_READY.lock() = false; unsafe {
*MAIN_TAG_READY.lock() = false; REF_TAG_READY = false;
MAIN_TAG_READY = false;
}
} }
pub fn collect_tags(interrupt: FIQ) { pub fn collect_tags(interrupt: ISR) {
match interrupt { match interrupt {
FIQ::RefTag => { ISR::RefTag => unsafe {
*REF_TAG.lock() = unsafe { csr::wrpll::ref_tag_read() }; REF_TAG = csr::wrpll::ref_tag_read();
*REF_TAG_READY.lock() = true; REF_TAG_READY = true;
} },
FIQ::MainTag => { ISR::MainTag => unsafe {
*MAIN_TAG.lock() = unsafe { csr::wrpll::main_tag_read() }; MAIN_TAG = csr::wrpll::main_tag_read();
*MAIN_TAG_READY.lock() = true; MAIN_TAG_READY = true;
} },
} }
} }
pub fn phase_diff_ready() -> bool { pub fn phase_diff_ready() -> bool {
*REF_TAG_READY.lock() && *MAIN_TAG_READY.lock() unsafe { REF_TAG_READY && MAIN_TAG_READY }
}
#[cfg(feature = "calibrate_wrpll_skew")]
pub fn set_tag_offset(offset: u32) {
unsafe {
TAG_OFFSET = offset;
}
}
#[cfg(feature = "calibrate_wrpll_skew")]
pub fn get_tag_offset() -> u32 {
unsafe { TAG_OFFSET }
} }
pub fn get_period_error() -> i32 { pub fn get_period_error() -> i32 {
// n * BEATING_PERIOD - REF_TAG(n) mod BEATING_PERIOD // n * BEATING_PERIOD - REF_TAG(n) mod BEATING_PERIOD
let mut period_error = (*REF_TAG.lock()).overflowing_neg().0.rem_euclid(BEATING_PERIOD as u32) as i32; let mut period_error = unsafe { REF_TAG.overflowing_neg().0.rem_euclid(BEATING_PERIOD as u32) as i32 };
// mapping tags from [0, 2π] -> [-π, π] // mapping tags from [0, 2π] -> [-π, π]
if period_error > BEATING_HALFPERIOD { if period_error > BEATING_HALFPERIOD {
period_error -= BEATING_PERIOD period_error -= BEATING_PERIOD
@ -348,11 +447,13 @@ pub mod wrpll {
} }
pub fn get_phase_error() -> i32 { pub fn get_phase_error() -> i32 {
// MAIN_TAG(n) - REF_TAG(n) mod BEATING_PERIOD // MAIN_TAG(n) - REF_TAG(n) - TAG_OFFSET mod BEATING_PERIOD
let mut phase_error = (*MAIN_TAG.lock()) let mut phase_error = unsafe {
.overflowing_sub(*REF_TAG.lock()) MAIN_TAG
.0 .overflowing_sub(REF_TAG + TAG_OFFSET)
.rem_euclid(BEATING_PERIOD as u32) as i32; .0
.rem_euclid(BEATING_PERIOD as u32) as i32
};
// mapping tags from [0, 2π] -> [-π, π] // mapping tags from [0, 2π] -> [-π, π]
if phase_error > BEATING_HALFPERIOD { if phase_error > BEATING_HALFPERIOD {
@ -362,29 +463,7 @@ pub mod wrpll {
} }
} }
pub fn helper_setup(timer: &mut GlobalTimer, settings: FrequencySetting) -> Result<(), &'static str> { fn set_isr(en: bool) {
unsafe {
csr::wrpll::helper_reset_write(1);
csr::helper_dcxo::bitbang_enable_write(1);
csr::helper_dcxo::i2c_address_write(ADDRESS);
}
setup(i2c::DCXO::Helper, settings.helper, timer)?;
// Si549 maximum settling time for large frequency change.
timer.delay_us(40_000);
unsafe {
csr::wrpll::helper_reset_write(0);
csr::helper_dcxo::bitbang_enable_write(0);
}
info!("Helper Si549 started");
timer.delay_ms(5_000);
Ok(())
}
fn set_fiq(en: bool) {
let val = if en { 1 } else { 0 }; let val = if en { 1 } else { 0 };
unsafe { unsafe {
csr::wrpll::ref_tag_ev_enable_write(val); csr::wrpll::ref_tag_ev_enable_write(val);
@ -392,71 +471,24 @@ pub mod wrpll {
} }
} }
/// set adpll using gateware i2c fn set_base_adpll() -> Result<(), &'static str> {
/// Note: disable main/helper i2c bitbang before using this function
fn set_adpll(dcxo: i2c::DCXO, adpll: i32) -> Result<(), &'static str> {
if adpll.abs() > ADPLL_MAX {
return Err("adpll is too large");
}
match dcxo {
i2c::DCXO::Main => unsafe {
if csr::main_dcxo::bitbang_enable_read() == 1 {
return Err("Main si549 bitbang mode is active when using gateware i2c");
}
while csr::main_dcxo::adpll_busy_read() == 1 {}
csr::main_dcxo::i2c_address_write(ADDRESS);
csr::main_dcxo::adpll_write(adpll as u32);
csr::main_dcxo::adpll_stb_write(1);
csr::main_dcxo::adpll_stb_write(0);
if csr::main_dcxo::nack_read() == 1 {
return Err("Main si549 failed to ack adpll write");
}
},
i2c::DCXO::Helper => unsafe {
if csr::helper_dcxo::bitbang_enable_read() == 1 {
return Err("Helper si549 bitbang mode is active when using gateware i2c");
}
while csr::helper_dcxo::adpll_busy_read() == 1 {}
csr::helper_dcxo::i2c_address_write(ADDRESS);
csr::helper_dcxo::adpll_write(adpll as u32);
csr::helper_dcxo::adpll_stb_write(1);
csr::helper_dcxo::adpll_stb_write(0);
if csr::helper_dcxo::nack_read() == 1 {
return Err("Helper si549 failed to ack adpll write");
}
},
};
Ok(())
}
/// To get within capture range
fn set_base_adpll(timer: &mut GlobalTimer) -> Result<(), &'static str> {
let count2adpll = let count2adpll =
|error: i32| (((error) as f64 * 1e6) / (0.0001164 * (1 << (TIMER_WIDTH - COUNTER_DIV)) as f64)) as i32; |error: i32| ((error as f64 * 1e6) / (0.0001164 * (1 << (COUNTER_WIDTH - DIV_WIDTH)) as f64)) as i32;
let (ref_count, main_count) = get_freq_counts(timer);
let mut base_adpll_lock = BASE_ADPLL.lock();
*base_adpll_lock = count2adpll(ref_count as i32 - main_count as i32);
set_adpll(i2c::DCXO::Main, *base_adpll_lock)?;
set_adpll(i2c::DCXO::Helper, *base_adpll_lock)?;
let (ref_count, main_count) = get_freq_counts();
unsafe {
BASE_ADPLL = count2adpll(ref_count as i32 - main_count as i32);
set_adpll(i2c::DCXO::Main, BASE_ADPLL)?;
set_adpll(i2c::DCXO::Helper, BASE_ADPLL)?;
}
Ok(()) Ok(())
} }
pub fn get_freq_counts(timer: &mut GlobalTimer) -> (u32, u32) { fn get_freq_counts() -> (u32, u32) {
unsafe { unsafe {
csr::wrpll::frequency_counter_update_en_write(1); csr::wrpll::frequency_counter_update_write(1);
timer.delay_us(150_000); // 8ns << TIMER_WIDTH while csr::wrpll::frequency_counter_busy_read() == 1 {}
csr::wrpll::frequency_counter_update_en_write(0); #[cfg(wrpll_ref_clk = "GT_CDR")]
#[cfg(wrpll_ref_clk = "GTX_CDR")]
let ref_count = csr::wrpll::frequency_counter_counter_rtio_rx0_read(); let ref_count = csr::wrpll::frequency_counter_counter_rtio_rx0_read();
#[cfg(wrpll_ref_clk = "SMA_CLKIN")] #[cfg(wrpll_ref_clk = "SMA_CLKIN")]
let ref_count = csr::wrpll::frequency_counter_counter_ref_read(); let ref_count = csr::wrpll::frequency_counter_counter_ref_read();
@ -466,39 +498,48 @@ pub mod wrpll {
} }
} }
fn reset_plls() -> Result<(), &'static str> { fn reset_plls(timer: &mut GlobalTimer) -> Result<(), &'static str> {
*H_INTEGRATOR.lock() = 0; unsafe {
*M_INTEGRATOR.lock() = 0; H_ADPLL1 = 0;
H_ADPLL2 = 0;
PERIOD_ERR1 = 0;
PERIOD_ERR2 = 0;
M_ADPLL1 = 0;
M_ADPLL2 = 0;
PHASE_ERR1 = 0;
PHASE_ERR2 = 0;
}
set_adpll(i2c::DCXO::Main, 0)?; set_adpll(i2c::DCXO::Main, 0)?;
set_adpll(i2c::DCXO::Helper, 0)?; set_adpll(i2c::DCXO::Helper, 0)?;
// wait for adpll to transfer and DCXO to settle
timer.delay_us(200);
Ok(()) Ok(())
} }
fn clear_pending(interrupt: FIQ) { fn clear_pending(interrupt: ISR) {
match interrupt { match interrupt {
FIQ::RefTag => unsafe { csr::wrpll::ref_tag_ev_pending_write(1) }, ISR::RefTag => unsafe { csr::wrpll::ref_tag_ev_pending_write(1) },
FIQ::MainTag => unsafe { csr::wrpll::main_tag_ev_pending_write(1) }, ISR::MainTag => unsafe { csr::wrpll::main_tag_ev_pending_write(1) },
}; };
} }
fn is_pending(interrupt: FIQ) -> bool { fn is_pending(interrupt: ISR) -> bool {
match interrupt { match interrupt {
FIQ::RefTag => unsafe { csr::wrpll::ref_tag_ev_pending_read() == 1 }, ISR::RefTag => unsafe { csr::wrpll::ref_tag_ev_pending_read() == 1 },
FIQ::MainTag => unsafe { csr::wrpll::main_tag_ev_pending_read() == 1 }, ISR::MainTag => unsafe { csr::wrpll::main_tag_ev_pending_read() == 1 },
} }
} }
pub fn interrupt_handler() { pub fn interrupt_handler() {
if is_pending(FIQ::RefTag) { if is_pending(ISR::RefTag) {
tag_collector::collect_tags(FIQ::RefTag); tag_collector::collect_tags(ISR::RefTag);
clear_pending(FIQ::RefTag); clear_pending(ISR::RefTag);
helper_pll().expect("failed to run helper DCXO PLL"); helper_pll().expect("failed to run helper DCXO PLL");
} }
if is_pending(FIQ::MainTag) { if is_pending(ISR::MainTag) {
tag_collector::collect_tags(FIQ::MainTag); tag_collector::collect_tags(ISR::MainTag);
clear_pending(FIQ::MainTag); clear_pending(ISR::MainTag);
} }
if tag_collector::phase_diff_ready() { if tag_collector::phase_diff_ready() {
@ -508,125 +549,165 @@ pub mod wrpll {
} }
fn helper_pll() -> Result<(), &'static str> { fn helper_pll() -> Result<(), &'static str> {
// unsafe {
// use libboard_zynq::println;
// ERR_ARR[COUNTER] = tag_collector::get_period_error();
// if COUNTER == SIZE - 1 {
// for i in 0..SIZE {
// println!("{}", ERR_ARR[i])
// }
// COUNTER = 0;
// let mut timer = GlobalTimer::get();
// timer.delay_us(20_000_000);
// }
// COUNTER += 1;
// }
let period_err = tag_collector::get_period_error(); let period_err = tag_collector::get_period_error();
let mut integrator_lock = H_INTEGRATOR.lock(); unsafe {
let adpll = ((LPF.b0 * period_err as f64) + (LPF.b1 * PERIOD_ERR1 as f64) + (LPF.b2 * PERIOD_ERR2 as f64)
*integrator_lock += period_err * KI; - (LPF.a1 * H_ADPLL1 as f64)
let mut h_adpll = *BASE_ADPLL.lock() + period_err * KP + *integrator_lock; - (LPF.a2 * H_ADPLL2 as f64)) as i32;
set_adpll(i2c::DCXO::Helper, BASE_ADPLL + adpll)?;
h_adpll = h_adpll.clamp(-ADPLL_MAX, ADPLL_MAX); H_ADPLL2 = H_ADPLL1;
set_adpll(i2c::DCXO::Helper, h_adpll)?; PERIOD_ERR2 = PERIOD_ERR1;
H_ADPLL1 = adpll;
PERIOD_ERR1 = period_err;
};
Ok(()) Ok(())
} }
const SIZE: usize = 2000;
static mut COUNTER: usize = 0;
static mut ERR_ARR: [i32; SIZE] = [0; SIZE];
static mut FIN_ADPLL: i32 = 0;
fn main_pll() -> Result<(), &'static str> { fn main_pll() -> Result<(), &'static str> {
// unsafe {
// use libboard_zynq::println;
// ERR_ARR[COUNTER] = tag_collector::get_phase_error();
// if COUNTER == SIZE - 1 {
// for i in 0..SIZE {
// println!("{}", ERR_ARR[i])
// }
// println!("{:>3} Zero crossing adpll = {:>5}", SIZE, FIN_ADPLL);
// COUNTER = 0;
// let mut timer = GlobalTimer::get();
// timer.delay_us(20_000_000);
// }
// COUNTER += 1;
// }
let phase_err = tag_collector::get_phase_error(); let phase_err = tag_collector::get_phase_error();
let mut integrator_lock = M_INTEGRATOR.lock();
*integrator_lock += phase_err * KI;
let mut m_adpll = *BASE_ADPLL.lock() + phase_err * KP + *integrator_lock;
m_adpll = m_adpll.clamp(-ADPLL_MAX, ADPLL_MAX);
set_adpll(i2c::DCXO::Main, m_adpll)?;
unsafe { unsafe {
if ERR_ARR[COUNTER] == 0 { let adpll = ((LPF.b0 * phase_err as f64) + (LPF.b1 * PHASE_ERR1 as f64) + (LPF.b2 * PHASE_ERR2 as f64)
FIN_ADPLL = m_adpll; - (LPF.a1 * M_ADPLL1 as f64)
- (LPF.a2 * M_ADPLL2 as f64)) as i32;
set_adpll(i2c::DCXO::Main, BASE_ADPLL + adpll)?;
M_ADPLL2 = M_ADPLL1;
PHASE_ERR2 = PHASE_ERR1;
M_ADPLL1 = adpll;
PHASE_ERR1 = phase_err;
};
Ok(())
}
#[cfg(wrpll_ref_clk = "GT_CDR")]
fn test_skew(timer: &mut GlobalTimer) -> Result<(), &'static str> {
// wait for PLL to stabilize
timer.delay_us(20_000);
info!("testing the skew of SYS CLK...");
if has_timing_error(timer) {
return Err("the skew cannot satisfy setup/hold time constraint of RX synchronizer");
}
info!("the skew of SYS CLK met the timing constraint");
Ok(())
}
#[cfg(wrpll_ref_clk = "GT_CDR")]
fn has_timing_error(timer: &mut GlobalTimer) -> bool {
unsafe {
csr::wrpll_skewtester::error_write(1);
}
timer.delay_us(5_000);
unsafe { csr::wrpll_skewtester::error_read() == 1 }
}
#[cfg(feature = "calibrate_wrpll_skew")]
fn find_edge(target: bool, timer: &mut GlobalTimer) -> Result<u32, &'static str> {
const STEP: u32 = 8;
const STABLE_THRESHOLD: u32 = 10;
enum FSM {
Init,
WaitEdge,
GotEdge,
}
let mut state: FSM = FSM::Init;
let mut offset: u32 = tag_collector::get_tag_offset();
let mut median_edge: u32 = 0;
let mut stable_counter: u32 = 0;
for _ in 0..(BEATING_PERIOD as u32 / STEP) as usize {
tag_collector::set_tag_offset(offset);
offset += STEP;
// wait for PLL to stabilize
timer.delay_us(20_000);
let error = has_timing_error(timer);
// A median edge deglitcher
match state {
FSM::Init => {
if error != target {
stable_counter += 1;
} else {
stable_counter = 0;
}
if stable_counter >= STABLE_THRESHOLD {
state = FSM::WaitEdge;
stable_counter = 0;
}
}
FSM::WaitEdge => {
if error == target {
state = FSM::GotEdge;
median_edge = offset;
}
}
FSM::GotEdge => {
if error != target {
median_edge += STEP;
stable_counter = 0;
} else {
stable_counter += 1;
}
if stable_counter >= STABLE_THRESHOLD {
return Ok(median_edge);
}
}
} }
} }
return Err("failed to find timing error edge");
}
#[cfg(feature = "calibrate_wrpll_skew")]
fn calibrate_skew(timer: &mut GlobalTimer) -> Result<(), &'static str> {
info!("calibrating skew to meet timing constraint...");
// clear calibrated value
tag_collector::set_tag_offset(0);
let rising = find_edge(true, timer)? as i32;
let falling = find_edge(false, timer)? as i32;
let width = BEATING_PERIOD - (falling - rising);
let result = falling + width / 2;
tag_collector::set_tag_offset(result as u32);
info!(
"calibration successful, error zone: {} -> {}, width: {} ({}deg), middle of working region: {}",
rising,
falling,
width,
360 * width / BEATING_PERIOD,
result,
);
Ok(()) Ok(())
} }
pub fn select_recovered_clock(rc: bool, timer: &mut GlobalTimer) { pub fn select_recovered_clock(rc: bool, timer: &mut GlobalTimer) {
set_fiq(false); set_isr(false);
if rc { if rc {
tag_collector::reset(); tag_collector::reset();
reset_plls().expect("failed to reset main and helper PLL"); reset_plls(timer).expect("failed to reset main and helper PLL");
info!("warming up refclk..."); // get within capture range
// refclk need a couple seconds for freq counter to read it properly set_base_adpll().expect("failed to set base adpll");
// timer.delay_us(20_000_000);
set_base_adpll(timer).expect("failed to set base adpll");
let ppm = 0.0;
*BASE_ADPLL.lock() += (ppm / 0.0001164) as i32;
timer.delay_us(200);
info!("KP = {}, KI = {}", KP, KI);
info!("adding {}ppm to main & helper base adpll ({})", ppm, *BASE_ADPLL.lock());
// clear gateware pending flag // clear gateware pending flag
clear_pending(FIQ::RefTag); clear_pending(ISR::RefTag);
clear_pending(FIQ::MainTag); clear_pending(ISR::MainTag);
unsafe {
info!("ref tag = {} ", csr::wrpll::ref_tag_read());
info!("main tag = {} ", csr::wrpll::main_tag_read());
}
// use nFIQ to avoid IRQ being disabled by mutex lock and mess up PLL // use nFIQ to avoid IRQ being disabled by mutex lock and mess up PLL
set_fiq(true); set_isr(true);
info!("WRPLL interrupt enabled"); info!("WRPLL interrupt enabled");
timer.delay_ms(500); #[cfg(feature = "calibrate_wrpll_skew")]
unsafe { calibrate_skew(timer).expect("failed to set the correct skew");
info!("main_tag_ev_enable_read() = {}", csr::wrpll::main_tag_ev_enable_read());
info!("main_tag_ev_status_read() = {}", csr::wrpll::main_tag_ev_status_read());
info!("ref_tag_ev_enable_read() = {}", csr::wrpll::ref_tag_ev_enable_read());
info!("ref_tag_ev_status_read() = {}", csr::wrpll::ref_tag_ev_status_read());
// loop { #[cfg(wrpll_ref_clk = "GT_CDR")]
// if is_pending(FIQ::RefTag) { test_skew(timer).expect("skew test failed");
// info!("REF tag is pending")
// }
// if is_pending(FIQ::MainTag) {
// info!("Main tag is pending")
// }
// // info!("ref tag = {} ", csr::wrpll::ref_tag_read());
// // info!("main tag = {} ", csr::wrpll::main_tag_read());
// timer.delay_ms(500);
// }
}
} }
} }
} }
@ -649,12 +730,10 @@ pub mod wrpll_refclk {
pub filt_reg2: u16, //0x4F pub filt_reg2: u16, //0x4F
} }
fn one_clock_cycle(timer: &mut GlobalTimer) { fn one_clock_cycle() {
unsafe { unsafe {
csr::wrpll_refclk::mmcm_dclk_write(1); csr::wrpll_refclk::mmcm_dclk_write(1);
timer.delay_us(1);
csr::wrpll_refclk::mmcm_dclk_write(0); csr::wrpll_refclk::mmcm_dclk_write(0);
timer.delay_us(1);
} }
} }
@ -692,33 +771,34 @@ pub mod wrpll_refclk {
unsafe { csr::wrpll_refclk::mmcm_dready_read() == 1 } unsafe { csr::wrpll_refclk::mmcm_dready_read() == 1 }
} }
fn read(timer: &mut GlobalTimer, address: u8) -> u16 { #[allow(dead_code)]
fn read(address: u8) -> u16 {
set_addr(address); set_addr(address);
set_enable(true); set_enable(true);
// Set DADDR on the MMCM and assert DEN for one clock cycle // Set DADDR on the mmcm and assert DEN for one clock cycle
one_clock_cycle(timer); one_clock_cycle();
set_enable(false); set_enable(false);
while !drp_ready() { while !drp_ready() {
// keep the clock signal until data is ready // keep the clock signal until data is ready
one_clock_cycle(timer); one_clock_cycle();
} }
get_data() get_data()
} }
fn write(timer: &mut GlobalTimer, address: u8, value: u16) { fn write(address: u8, value: u16) {
set_addr(address); set_addr(address);
set_data(value); set_data(value);
set_write_enable(true); set_write_enable(true);
set_enable(true); set_enable(true);
// Set DADDR, DI on the MMCM and assert DWE, DEN for one clock cycle // Set DADDR, DI on the mmcm and assert DWE, DEN for one clock cycle
one_clock_cycle(timer); one_clock_cycle();
set_write_enable(false); set_write_enable(false);
set_enable(false); set_enable(false);
while !drp_ready() { while !drp_ready() {
// keep the clock signal until write is finished // keep the clock signal until write is finished
one_clock_cycle(timer); one_clock_cycle();
} }
} }
@ -729,49 +809,45 @@ pub mod wrpll_refclk {
} }
} }
pub fn setup(timer: &mut GlobalTimer, settings: MmcmSetting) -> Result<(), &'static str> { pub fn setup(timer: &mut GlobalTimer, settings: MmcmSetting, mmcm_bypass: bool) -> Result<(), &'static str> {
// Based on "DRP State Machine" from XAPP888 unsafe {
csr::wrpll_refclk::refclk_reset_write(1);
// hold reset HIGH during mmcm config
reset(true);
write(timer, 0x08, settings.clkout0_reg1);
write(timer, 0x09, settings.clkout0_reg2);
write(timer, 0x14, settings.clkfbout_reg1);
write(timer, 0x15, settings.clkfbout_reg2);
write(timer, 0x16, settings.div_reg);
write(timer, 0x18, settings.lock_reg1);
write(timer, 0x19, settings.lock_reg2);
write(timer, 0x1A, settings.lock_reg3);
write(timer, 0x28, settings.power_reg);
write(timer, 0x4E, settings.filt_reg1);
write(timer, 0x4F, settings.filt_reg2);
reset(false);
// wait for the mmcm to lock
timer.delay_us(100);
let locked = unsafe { csr::wrpll_refclk::mmcm_locked_read() == 1 };
if !locked {
return Err("failed to generate 125Mhz ref clock from SMA CLKIN");
} }
// const TIMER_WIDTH: u32 = 24; if mmcm_bypass {
// const COUNTER_DIV: u32 = 2; info!("Bypassing mmcm");
unsafe {
csr::wrpll_refclk::mmcm_bypass_write(1);
}
} else {
// Based on "DRP State Machine" from XAPP888
// hold reset HIGH during mmcm config
reset(true);
write(0x08, settings.clkout0_reg1);
write(0x09, settings.clkout0_reg2);
write(0x14, settings.clkfbout_reg1);
write(0x15, settings.clkfbout_reg2);
write(0x16, settings.div_reg);
write(0x18, settings.lock_reg1);
write(0x19, settings.lock_reg2);
write(0x1A, settings.lock_reg3);
write(0x28, settings.power_reg);
write(0x4E, settings.filt_reg1);
write(0x4F, settings.filt_reg2);
reset(false);
// let (ref_count, main_count) = wrpll::get_freq_counts(timer); // wait for the mmcm to lock
timer.delay_us(100);
// let f_sys = 125e6; let locked = unsafe { csr::wrpll_refclk::mmcm_locked_read() == 1 };
if !locked {
return Err("mmcm failed to generate 125MHz ref clock from SMA CLKIN");
}
}
// info!( unsafe {
// "ref counter = {} freq = {}", csr::wrpll_refclk::refclk_reset_write(0);
// ref_count, }
// (ref_count as f64 * f_sys) as f64 / (1 << (TIMER_WIDTH - COUNTER_DIV)) as f64
// );
// info!(
// "Main counter = {} freq = {}",
// main_count,
// (main_count as f64 * f_sys) as f64 / (1 << (TIMER_WIDTH - COUNTER_DIV)) as f64
// );
Ok(()) Ok(())
} }

View File

@ -10,7 +10,9 @@ SECTIONS
__text_start = .; __text_start = .;
.text : .text :
{ {
__exceptions_start = .;
KEEP(*(.text.exceptions)); KEEP(*(.text.exceptions));
__exceptions_end = .;
*(.text.boot); *(.text.boot);
*(.text .text.*); *(.text .text.*);
} > SDRAM } > SDRAM

View File

@ -45,7 +45,10 @@ impl<T: AsRef<[u8]>> Read for Cursor<T> {
fn read(&mut self, buf: &mut [u8]) -> Result<usize, IoError> { fn read(&mut self, buf: &mut [u8]) -> Result<usize, IoError> {
let data = &self.inner.as_ref()[self.pos..]; let data = &self.inner.as_ref()[self.pos..];
let len = buf.len().min(data.len()); let len = buf.len().min(data.len());
buf[..len].copy_from_slice(&data[..len]); // ``copy_from_slice`` generates AXI bursts, use a regular loop instead
for i in 0..len {
buf[i] = data[i];
}
self.pos += len; self.pos += len;
Ok(len) Ok(len)
} }
@ -55,7 +58,9 @@ impl Write for Cursor<&mut [u8]> {
fn write(&mut self, buf: &[u8]) -> Result<usize, IoError> { fn write(&mut self, buf: &[u8]) -> Result<usize, IoError> {
let data = &mut self.inner[self.pos..]; let data = &mut self.inner[self.pos..];
let len = buf.len().min(data.len()); let len = buf.len().min(data.len());
data[..len].copy_from_slice(&buf[..len]); for i in 0..len {
data[i] = buf[i];
}
self.pos += len; self.pos += len;
Ok(len) Ok(len)
} }
@ -68,7 +73,6 @@ impl Write for Cursor<&mut [u8]> {
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
impl Write for Cursor<Vec<u8>> { impl Write for Cursor<Vec<u8>> {
#[inline]
fn write(&mut self, buf: &[u8]) -> Result<usize, IoError> { fn write(&mut self, buf: &[u8]) -> Result<usize, IoError> {
self.inner.extend_from_slice(buf); self.inner.extend_from_slice(buf);
Ok(buf.len()) Ok(buf.len())

View File

@ -21,7 +21,6 @@ pub use pl::csr::rtio_core;
use void::Void; use void::Void;
pub mod eh_artiq; pub mod eh_artiq;
pub mod fiq;
pub mod i2c; pub mod i2c;
pub mod irq; pub mod irq;
pub mod kernel; pub mod kernel;

View File

@ -60,7 +60,7 @@ pub mod remote_analyzer {
routing_table: &drtio_routing::RoutingTable, routing_table: &drtio_routing::RoutingTable,
up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>, up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>,
timer: GlobalTimer, timer: GlobalTimer,
) -> Result<RemoteBuffer, &'static str> { ) -> Result<RemoteBuffer, drtio::Error> {
// gets data from satellites and returns consolidated data // gets data from satellites and returns consolidated data
let mut remote_data: Vec<u8> = Vec::new(); let mut remote_data: Vec<u8> = Vec::new();
let mut remote_error = false; let mut remote_error = false;

View File

@ -8,20 +8,20 @@
#[macro_use] #[macro_use]
extern crate alloc; extern crate alloc;
#[cfg(all(feature = "target_kasli_soc", has_drtio))] #[cfg(all(feature = "target_kasli_soc", has_virtual_leds))]
use core::cell::RefCell; use core::cell::RefCell;
use ksupport; use ksupport;
use libasync::task; use libasync::task;
#[cfg(has_drtio_eem)] #[cfg(has_drtio_eem)]
use libboard_artiq::drtio_eem; use libboard_artiq::drtio_eem;
#[cfg(all(feature = "target_kasli_soc", has_drtio))] #[cfg(feature = "target_kasli_soc")]
use libboard_artiq::io_expander; use libboard_artiq::io_expander;
use libboard_artiq::{identifier_read, logger, pl}; use libboard_artiq::{identifier_read, logger, pl};
use libboard_zynq::{gic, mpcore, timer::GlobalTimer}; use libboard_zynq::{gic, mpcore, timer::GlobalTimer};
use libconfig::Config; use libconfig::Config;
use libcortex_a9::l2c::enable_l2_cache; use libcortex_a9::l2c::enable_l2_cache;
use libsupport_zynq::ram; use libsupport_zynq::{exception_vectors, ram};
use log::{info, warn}; use log::{info, warn};
mod analyzer; mod analyzer;
@ -38,7 +38,12 @@ mod rtio_mgt;
#[cfg(has_drtio)] #[cfg(has_drtio)]
mod subkernel; mod subkernel;
#[cfg(all(feature = "target_kasli_soc", has_drtio))] // linker symbols
extern "C" {
static __exceptions_start: u32;
}
#[cfg(all(feature = "target_kasli_soc", has_virtual_leds))]
async fn io_expanders_service( async fn io_expanders_service(
i2c_bus: RefCell<&mut libboard_zynq::i2c::I2c>, i2c_bus: RefCell<&mut libboard_zynq::i2c::I2c>,
io_expander0: RefCell<io_expander::IoExpander>, io_expander0: RefCell<io_expander::IoExpander>,
@ -77,6 +82,9 @@ static mut LOG_BUFFER: [u8; 1 << 17] = [0; 1 << 17];
#[no_mangle] #[no_mangle]
pub fn main_core0() { pub fn main_core0() {
unsafe {
exception_vectors::set_vector_table(&__exceptions_start as *const u32 as u32);
}
enable_l2_cache(0x8); enable_l2_cache(0x8);
let mut timer = GlobalTimer::start(); let mut timer = GlobalTimer::start();
@ -93,7 +101,7 @@ pub fn main_core0() {
info!("gateware ident: {}", identifier_read(&mut [0; 64])); info!("gateware ident: {}", identifier_read(&mut [0; 64]));
ksupport::i2c::init(); ksupport::i2c::init();
#[cfg(all(feature = "target_kasli_soc", has_drtio))] #[cfg(feature = "target_kasli_soc")]
{ {
let i2c_bus = unsafe { (ksupport::i2c::I2C_BUS).as_mut().unwrap() }; let i2c_bus = unsafe { (ksupport::i2c::I2C_BUS).as_mut().unwrap() };
let mut io_expander0 = io_expander::IoExpander::new(i2c_bus, 0).unwrap(); let mut io_expander0 = io_expander::IoExpander::new(i2c_bus, 0).unwrap();
@ -116,6 +124,7 @@ pub fn main_core0() {
io_expander1.set(1, 1, false); io_expander1.set(1, 1, false);
io_expander0.service(i2c_bus).unwrap(); io_expander0.service(i2c_bus).unwrap();
io_expander1.service(i2c_bus).unwrap(); io_expander1.service(i2c_bus).unwrap();
#[cfg(has_virtual_leds)]
task::spawn(io_expanders_service( task::spawn(io_expanders_service(
RefCell::new(i2c_bus), RefCell::new(i2c_bus),
RefCell::new(io_expander0), RefCell::new(io_expander0),

View File

@ -58,10 +58,11 @@ mod remote_moninj {
use log::error; use log::error;
use super::*; use super::*;
use crate::rtio_mgt::drtio; use crate::rtio_mgt::{drtio, drtio::Error as DrtioError};
pub async fn read_probe( pub async fn read_probe(
aux_mutex: &Rc<Mutex<bool>>, aux_mutex: &Rc<Mutex<bool>>,
routing_table: &drtio_routing::RoutingTable,
timer: GlobalTimer, timer: GlobalTimer,
linkno: u8, linkno: u8,
destination: u8, destination: u8,
@ -71,6 +72,7 @@ mod remote_moninj {
let reply = drtio::aux_transact( let reply = drtio::aux_transact(
aux_mutex, aux_mutex,
linkno, linkno,
routing_table,
&drtioaux_async::Packet::MonitorRequest { &drtioaux_async::Packet::MonitorRequest {
destination: destination, destination: destination,
channel: channel as _, channel: channel as _,
@ -82,8 +84,8 @@ mod remote_moninj {
match reply { match reply {
Ok(drtioaux_async::Packet::MonitorReply { value }) => return value as i64, Ok(drtioaux_async::Packet::MonitorReply { value }) => return value as i64,
Ok(packet) => error!("received unexpected aux packet: {:?}", packet), Ok(packet) => error!("received unexpected aux packet: {:?}", packet),
Err("link went down") => { Err(DrtioError::LinkDown) => {
debug!("link is down"); warn!("link is down");
} }
Err(e) => error!("aux packet error ({})", e), Err(e) => error!("aux packet error ({})", e),
} }
@ -92,6 +94,7 @@ mod remote_moninj {
pub async fn inject( pub async fn inject(
aux_mutex: &Rc<Mutex<bool>>, aux_mutex: &Rc<Mutex<bool>>,
_routing_table: &drtio_routing::RoutingTable,
_timer: GlobalTimer, _timer: GlobalTimer,
linkno: u8, linkno: u8,
destination: u8, destination: u8,
@ -115,6 +118,7 @@ mod remote_moninj {
pub async fn read_injection_status( pub async fn read_injection_status(
aux_mutex: &Rc<Mutex<bool>>, aux_mutex: &Rc<Mutex<bool>>,
routing_table: &drtio_routing::RoutingTable,
timer: GlobalTimer, timer: GlobalTimer,
linkno: u8, linkno: u8,
destination: u8, destination: u8,
@ -124,6 +128,7 @@ mod remote_moninj {
let reply = drtio::aux_transact( let reply = drtio::aux_transact(
aux_mutex, aux_mutex,
linkno, linkno,
routing_table,
&drtioaux_async::Packet::InjectionStatusRequest { &drtioaux_async::Packet::InjectionStatusRequest {
destination: destination, destination: destination,
channel: channel as _, channel: channel as _,
@ -135,8 +140,8 @@ mod remote_moninj {
match reply { match reply {
Ok(drtioaux_async::Packet::InjectionStatusReply { value }) => return value as i8, Ok(drtioaux_async::Packet::InjectionStatusReply { value }) => return value as i8,
Ok(packet) => error!("received unexpected aux packet: {:?}", packet), Ok(packet) => error!("received unexpected aux packet: {:?}", packet),
Err("link went down") => { Err(DrtioError::LinkDown) => {
debug!("link is down"); warn!("link is down");
} }
Err(e) => error!("aux packet error ({})", e), Err(e) => error!("aux packet error ({})", e),
} }
@ -183,7 +188,7 @@ macro_rules! dispatch {
local_moninj::$func(channel.into(), $($param, )*) local_moninj::$func(channel.into(), $($param, )*)
} else { } else {
let linkno = hop - 1 as u8; let linkno = hop - 1 as u8;
remote_moninj::$func($aux_mutex, $timer, linkno, destination, channel, $($param, )*).await remote_moninj::$func($aux_mutex, $routing_table, $timer, linkno, destination, channel, $($param, )*).await
} }
}} }}
} }

View File

@ -6,8 +6,6 @@ use libboard_artiq::pl;
use libboard_artiq::si5324; use libboard_artiq::si5324;
#[cfg(has_si549)] #[cfg(has_si549)]
use libboard_artiq::si549; use libboard_artiq::si549;
#[cfg(has_wrpll)]
use libboard_artiq::si549::wrpll_refclk;
#[cfg(has_si5324)] #[cfg(has_si5324)]
use libboard_zynq::i2c::I2c; use libboard_zynq::i2c::I2c;
use libboard_zynq::timer::GlobalTimer; use libboard_zynq::timer::GlobalTimer;
@ -264,71 +262,87 @@ fn setup_si5324(i2c: &mut I2c, timer: &mut GlobalTimer, clk: RtioClock) {
si5324::setup(i2c, &si5324_settings, si5324_ref_input, timer).expect("cannot initialize Si5324"); si5324::setup(i2c, &si5324_settings, si5324_ref_input, timer).expect("cannot initialize Si5324");
} }
#[cfg(has_wrpll)] #[cfg(all(has_si549, has_wrpll))]
fn wrpll_setup(timer: &mut GlobalTimer, clk: RtioClock, si549_settings: si549::FrequencySetting) { fn wrpll_setup(timer: &mut GlobalTimer, clk: RtioClock, si549_settings: &si549::FrequencySetting) {
let mmcm_setting = match clk { // register values are directly copied from preconfigured mmcm
RtioClock::Ext0_Synth0_10to125 => si549::wrpll_refclk::MmcmSetting { let (mmcm_setting, mmcm_bypass) = match clk {
clkout0_reg1: 0x1083, RtioClock::Ext0_Synth0_10to125 => (
clkout0_reg2: 0x0080, si549::wrpll_refclk::MmcmSetting {
clkfbout_reg1: 0x179e, // CLKFBOUT_MULT = 62.5, DIVCLK_DIVIDE = 1 , CLKOUT0_DIVIDE = 5
clkfbout_reg2: 0x4c00, clkout0_reg1: 0x1083,
div_reg: 0x1041, clkout0_reg2: 0x0080,
lock_reg1: 0x00fa, clkfbout_reg1: 0x179e,
lock_reg2: 0x7c01, clkfbout_reg2: 0x4c00,
lock_reg3: 0xffe9, div_reg: 0x1041,
power_reg: 0x9900, lock_reg1: 0x00fa,
filt_reg1: 0x0808, lock_reg2: 0x7c01,
filt_reg2: 0x0800, lock_reg3: 0xffe9,
}, power_reg: 0x9900,
RtioClock::Ext0_Synth0_80to125 => si549::wrpll_refclk::MmcmSetting { filt_reg1: 0x1008,
clkout0_reg1: 0x1145, filt_reg2: 0x8800,
clkout0_reg2: 0x0000, },
clkfbout_reg1: 0x11c7, false,
clkfbout_reg2: 0x5880, ),
div_reg: 0x1041, RtioClock::Ext0_Synth0_80to125 => (
lock_reg1: 0x028a, si549::wrpll_refclk::MmcmSetting {
lock_reg2: 0x7c01, // CLKFBOUT_MULT = 15.625, DIVCLK_DIVIDE = 1 , CLKOUT0_DIVIDE = 10
lock_reg3: 0xffe9, clkout0_reg1: 0x1145,
power_reg: 0x9900, clkout0_reg2: 0x0000,
filt_reg1: 0x0808, clkfbout_reg1: 0x11c7,
filt_reg2: 0x9800, clkfbout_reg2: 0x5880,
}, div_reg: 0x1041,
RtioClock::Ext0_Synth0_100to125 => si549::wrpll_refclk::MmcmSetting { lock_reg1: 0x028a,
clkout0_reg1: 0x1145, lock_reg2: 0x7c01,
clkout0_reg2: 0x0000, lock_reg3: 0xffe9,
clkfbout_reg1: 0x1145, power_reg: 0x9900,
clkfbout_reg2: 0x4c00, filt_reg1: 0x9908,
div_reg: 0x1041, filt_reg2: 0x8100,
lock_reg1: 0x0339, },
lock_reg2: 0x7c01, false,
lock_reg3: 0xffe9, ),
power_reg: 0x9900, RtioClock::Ext0_Synth0_100to125 => (
filt_reg1: 0x0808, si549::wrpll_refclk::MmcmSetting {
filt_reg2: 0x9800, // CLKFBOUT_MULT = 12.5, DIVCLK_DIVIDE = 1 , CLKOUT0_DIVIDE = 10
}, clkout0_reg1: 0x1145,
RtioClock::Ext0_Synth0_125to125 => si549::wrpll_refclk::MmcmSetting { clkout0_reg2: 0x0000,
clkout0_reg1: 0x1145, clkfbout_reg1: 0x1145,
clkout0_reg2: 0x0000, clkfbout_reg2: 0x4c00,
clkfbout_reg1: 0x1145, div_reg: 0x1041,
clkfbout_reg2: 0x0000, lock_reg1: 0x0339,
div_reg: 0x1041, lock_reg2: 0x7c01,
lock_reg1: 0x03e8, lock_reg3: 0xffe9,
lock_reg2: 0x7001, power_reg: 0x9900,
lock_reg3: 0xf3e9, filt_reg1: 0x9108,
power_reg: 0x0100, filt_reg2: 0x0100,
filt_reg1: 0x0808, },
filt_reg2: 0x1100, false,
}, ),
RtioClock::Ext0_Synth0_125to125 => (
si549::wrpll_refclk::MmcmSetting {
// CLKFBOUT_MULT = 10, DIVCLK_DIVIDE = 1 , CLKOUT0_DIVIDE = 10
clkout0_reg1: 0x1145,
clkout0_reg2: 0x0000,
clkfbout_reg1: 0x1145,
clkfbout_reg2: 0x0000,
div_reg: 0x1041,
lock_reg1: 0x03e8,
lock_reg2: 0x7001,
lock_reg3: 0xf3e9,
power_reg: 0x0100,
filt_reg1: 0x9908,
filt_reg2: 0x1100,
},
true,
),
_ => unreachable!(), _ => unreachable!(),
}; };
si549::main_setup(timer, si549_settings).expect("cannot initialize main Si549"); si549::helper_setup(timer, &si549_settings).expect("cannot initialize helper Si549");
si549::wrpll::helper_setup(timer, si549_settings).expect("cannot initialize helper Si549"); si549::wrpll_refclk::setup(timer, mmcm_setting, mmcm_bypass).expect("cannot initialize ref clk for wrpll");
si549::wrpll::select_recovered_clock(true, timer);
si549::wrpll_refclk::setup(timer, mmcm_setting).expect("cannot initialize ref clk for wrpll");
// si549::wrpll::select_recovered_clock(true, timer);
} }
#[cfg(has_si549)]
fn get_si549_setting(clk: RtioClock) -> si549::FrequencySetting { fn get_si549_setting(clk: RtioClock) -> si549::FrequencySetting {
match clk { match clk {
RtioClock::Ext0_Synth0_10to125 => { RtioClock::Ext0_Synth0_10to125 => {
@ -343,9 +357,6 @@ fn get_si549_setting(clk: RtioClock) -> si549::FrequencySetting {
RtioClock::Ext0_Synth0_125to125 => { RtioClock::Ext0_Synth0_125to125 => {
info!("using 125MHz reference to make 125MHz RTIO clock with WRPLL"); info!("using 125MHz reference to make 125MHz RTIO clock with WRPLL");
} }
RtioClock::Int_150 => {
info!("using internal 150MHz RTIO clock");
}
RtioClock::Int_100 => { RtioClock::Int_100 => {
info!("using internal 100MHz RTIO clock"); info!("using internal 100MHz RTIO clock");
} }
@ -368,9 +379,8 @@ fn get_si549_setting(clk: RtioClock) -> si549::FrequencySetting {
lsdiv: 0, lsdiv: 0,
fbdiv: 0x046C5F49797, fbdiv: 0x046C5F49797,
}, },
#[cfg(has_wrpll)]
helper: si549::DividerConfig { helper: si549::DividerConfig {
// 100Mhz*32767/32768 // 100MHz*32767/32768
hsdiv: 0x06C, hsdiv: 0x06C,
lsdiv: 0, lsdiv: 0,
fbdiv: 0x046C5670BBD, fbdiv: 0x046C5670BBD,
@ -378,16 +388,15 @@ fn get_si549_setting(clk: RtioClock) -> si549::FrequencySetting {
} }
} }
_ => { _ => {
// Everything else use 125Mhz // Everything else use 125MHz
si549::FrequencySetting { si549::FrequencySetting {
main: si549::DividerConfig { main: si549::DividerConfig {
hsdiv: 0x058, hsdiv: 0x058,
lsdiv: 0, lsdiv: 0,
fbdiv: 0x04815791F25, fbdiv: 0x04815791F25,
}, },
#[cfg(has_wrpll)]
helper: si549::DividerConfig { helper: si549::DividerConfig {
// 125Mhz*32767/32768 // 125MHz*32767/32768
hsdiv: 0x058, hsdiv: 0x058,
lsdiv: 0, lsdiv: 0,
fbdiv: 0x04814E8F442, fbdiv: 0x04814E8F442,
@ -412,22 +421,10 @@ pub fn init(timer: &mut GlobalTimer, cfg: &Config) {
} }
#[cfg(has_si549)] #[cfg(has_si549)]
{ let si549_settings = get_si549_setting(clk);
let si549_settings = get_si549_setting(clk);
match clk { #[cfg(has_si549)]
RtioClock::Ext0_Synth0_10to125 si549::main_setup(timer, &si549_settings).expect("cannot initialize main Si549");
| RtioClock::Ext0_Synth0_80to125
| RtioClock::Ext0_Synth0_100to125
| RtioClock::Ext0_Synth0_125to125 => {
wrpll_setup(timer, clk, si549_settings);
}
_ => {
wrpll_setup(timer, RtioClock::Ext0_Synth0_125to125, si549_settings);
// si549::main_setup(timer, si549_settings).expect("cannot initialize main Si549");
}
}
}
#[cfg(has_drtio)] #[cfg(has_drtio)]
init_drtio(timer); init_drtio(timer);
@ -435,6 +432,17 @@ pub fn init(timer: &mut GlobalTimer, cfg: &Config) {
#[cfg(not(has_drtio))] #[cfg(not(has_drtio))]
init_rtio(timer); init_rtio(timer);
// !! move back to cfg after testing #[cfg(all(has_si549, has_wrpll))]
si549::wrpll::select_recovered_clock(true, timer); {
// SYS CLK switch will reset CSRs that are used by WRPLL
match clk {
RtioClock::Ext0_Synth0_10to125
| RtioClock::Ext0_Synth0_80to125
| RtioClock::Ext0_Synth0_100to125
| RtioClock::Ext0_Synth0_125to125 => {
wrpll_setup(timer, clk, &si549_settings);
}
_ => {}
}
}
} }

View File

@ -1,19 +1,20 @@
use alloc::rc::Rc; use alloc::rc::Rc;
use core::cell::RefCell; use core::cell::RefCell;
use libboard_artiq::{drtio_routing, pl::csr}; use libboard_artiq::{drtio_routing, drtio_routing::RoutingTable, pl::csr};
use libboard_zynq::timer::GlobalTimer; use libboard_zynq::timer::GlobalTimer;
use libcortex_a9::mutex::Mutex; use libcortex_a9::mutex::Mutex;
#[cfg(has_drtio)] #[cfg(has_drtio)]
pub mod drtio { pub mod drtio {
use alloc::vec::Vec; use alloc::vec::Vec;
use core::fmt;
use embedded_hal::blocking::delay::DelayMs; use embedded_hal::blocking::delay::DelayMs;
use ksupport::{resolve_channel_name, ASYNC_ERROR_BUSY, ASYNC_ERROR_COLLISION, ASYNC_ERROR_SEQUENCE_ERROR, use ksupport::{resolve_channel_name, ASYNC_ERROR_BUSY, ASYNC_ERROR_COLLISION, ASYNC_ERROR_SEQUENCE_ERROR,
SEEN_ASYNC_ERRORS}; SEEN_ASYNC_ERRORS};
use libasync::{delay, task}; use libasync::{delay, task};
use libboard_artiq::{drtioaux::Error, use libboard_artiq::{drtioaux::Error as DrtioError,
drtioaux_async, drtioaux_async,
drtioaux_async::Packet, drtioaux_async::Packet,
drtioaux_proto::{PayloadStatus, MASTER_PAYLOAD_MAX_SIZE}}; drtioaux_proto::{PayloadStatus, MASTER_PAYLOAD_MAX_SIZE}};
@ -23,9 +24,44 @@ pub mod drtio {
use super::*; use super::*;
use crate::{analyzer::remote_analyzer::RemoteBuffer, rtio_dma::remote_dma, subkernel}; use crate::{analyzer::remote_analyzer::RemoteBuffer, rtio_dma::remote_dma, subkernel};
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum Error {
Timeout,
AuxError,
LinkDown,
UnexpectedReply,
DmaAddTraceFail(u8),
DmaEraseFail(u8),
DmaPlaybackFail(u8),
SubkernelAddFail(u8),
SubkernelRunFail(u8),
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Error::Timeout => write!(f, "timed out"),
Error::AuxError => write!(f, "aux packet error"),
Error::LinkDown => write!(f, "link down"),
Error::UnexpectedReply => write!(f, "unexpected reply"),
Error::DmaAddTraceFail(dest) => write!(f, "error adding DMA trace on satellite #{}", dest),
Error::DmaEraseFail(dest) => write!(f, "error erasing DMA trace on satellite #{}", dest),
Error::DmaPlaybackFail(dest) => write!(f, "error playing back DMA trace on satellite #{}", dest),
Error::SubkernelAddFail(dest) => write!(f, "error adding subkernel on satellite #{}", dest),
Error::SubkernelRunFail(dest) => write!(f, "error on subkernel run request on satellite #{}", dest),
}
}
}
impl From<DrtioError> for Error {
fn from(_error: DrtioError) -> Self {
Error::AuxError
}
}
pub fn startup( pub fn startup(
aux_mutex: &Rc<Mutex<bool>>, aux_mutex: &Rc<Mutex<bool>>,
routing_table: &Rc<RefCell<drtio_routing::RoutingTable>>, routing_table: &Rc<RefCell<RoutingTable>>,
up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>, up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>,
timer: GlobalTimer, timer: GlobalTimer,
) { ) {
@ -43,128 +79,104 @@ pub mod drtio {
unsafe { (csr::DRTIO[linkno].rx_up_read)() == 1 } unsafe { (csr::DRTIO[linkno].rx_up_read)() == 1 }
} }
async fn link_has_async_ready(linkno: u8) -> bool { async fn process_async_packets(linkno: u8, routing_table: &RoutingTable, packet: Packet) -> Option<Packet> {
let linkno = linkno as usize; match packet {
let async_ready; Packet::DmaPlaybackStatus {
unsafe { id,
async_ready = (csr::DRTIO[linkno].async_messages_ready_read)() == 1; source,
(csr::DRTIO[linkno].async_messages_ready_write)(1); destination: 0,
} error,
async_ready channel,
} timestamp,
} => {
async fn process_async_packets( remote_dma::playback_done(id, source, error, channel, timestamp).await;
aux_mutex: &Mutex<bool>, None
linkno: u8, }
routing_table: &drtio_routing::RoutingTable, Packet::SubkernelFinished {
timer: GlobalTimer, id,
) { destination: 0,
if link_has_async_ready(linkno).await { with_exception,
loop { exception_src,
let reply = aux_transact(aux_mutex, linkno, &Packet::RoutingRetrievePackets, timer).await; } => {
if let Ok(packet) = reply { subkernel::subkernel_finished(id, with_exception, exception_src).await;
match packet { None
Packet::DmaPlaybackStatus { }
id, Packet::SubkernelMessage {
source, id,
destination: 0, source,
error, destination: 0,
channel, status,
timestamp, length,
} => { data,
remote_dma::playback_done(id, source, error, channel, timestamp).await; } => {
} subkernel::message_handle_incoming(id, status, length as usize, &data).await;
Packet::SubkernelFinished { // acknowledge receiving part of the message
id, drtioaux_async::send(linkno, &Packet::SubkernelMessageAck { destination: source })
destination: 0, .await
with_exception, .unwrap();
exception_src, None
} => { }
subkernel::subkernel_finished(id, with_exception, exception_src).await; // routable packets
} Packet::DmaAddTraceRequest { destination, .. }
Packet::SubkernelMessage { | Packet::DmaAddTraceReply { destination, .. }
id, | Packet::DmaRemoveTraceRequest { destination, .. }
source, | Packet::DmaRemoveTraceReply { destination, .. }
destination: 0, | Packet::DmaPlaybackRequest { destination, .. }
status, | Packet::DmaPlaybackReply { destination, .. }
length, | Packet::SubkernelLoadRunRequest { destination, .. }
data, | Packet::SubkernelLoadRunReply { destination, .. }
} => { | Packet::SubkernelMessage { destination, .. }
subkernel::message_handle_incoming(id, status, length as usize, &data).await; | Packet::SubkernelMessageAck { destination, .. }
// acknowledge receiving part of the message | Packet::DmaPlaybackStatus { destination, .. }
let _lock = aux_mutex.async_lock().await; | Packet::SubkernelFinished { destination, .. } => {
drtioaux_async::send(linkno, &Packet::SubkernelMessageAck { destination: source }) if destination == 0 {
.await Some(packet)
.unwrap();
let mut countdown = timer.countdown();
// give the satellites some time to process
delay(&mut countdown, Milliseconds(10)).await;
}
// routable packets
Packet::DmaAddTraceRequest { destination, .. }
| Packet::DmaAddTraceReply { destination, .. }
| Packet::DmaRemoveTraceRequest { destination, .. }
| Packet::DmaRemoveTraceReply { destination, .. }
| Packet::DmaPlaybackRequest { destination, .. }
| Packet::DmaPlaybackReply { destination, .. }
| Packet::SubkernelLoadRunRequest { destination, .. }
| Packet::SubkernelLoadRunReply { destination, .. }
| Packet::SubkernelMessage { destination, .. }
| Packet::SubkernelMessageAck { destination, .. }
| Packet::DmaPlaybackStatus { destination, .. }
| Packet::SubkernelFinished { destination, .. } => {
let dest_link = routing_table.0[destination as usize][0] - 1;
if dest_link == linkno {
warn!(
"[LINK#{}] Re-routed packet would return to the same link, dropping: {:?}",
linkno, packet
);
} else if destination == 0 {
warn!("[LINK#{}] Received invalid routable packet: {:?}", linkno, packet)
} else {
drtioaux_async::send(dest_link, &packet).await.unwrap();
}
}
Packet::RoutingNoPackets => break,
other => warn!("[LINK#{}] Received an unroutable packet: {:?}", linkno, other),
}
} else { } else {
warn!( let dest_link = routing_table.0[destination as usize][0] - 1;
"[LINK#{}] Error handling async packets ({})", if dest_link == linkno {
linkno, warn!(
reply.unwrap_err() "[LINK#{}] Re-routed packet would return to the same link, dropping: {:?}",
); linkno, packet
return; );
} else {
drtioaux_async::send(dest_link, &packet).await.unwrap();
}
None
} }
} }
other => Some(other),
} }
} }
async fn recv_aux_timeout(linkno: u8, timeout: u64, timer: GlobalTimer) -> Result<Packet, &'static str> { async fn recv_aux_timeout(linkno: u8, timeout: u64, timer: GlobalTimer) -> Result<Packet, Error> {
if !link_rx_up(linkno).await { if !link_rx_up(linkno).await {
return Err("link went down"); return Err(Error::LinkDown);
} }
match drtioaux_async::recv_timeout(linkno, Some(timeout), timer).await { match drtioaux_async::recv_timeout(linkno, Some(timeout), timer).await {
Ok(packet) => return Ok(packet), Ok(packet) => return Ok(packet),
Err(Error::TimedOut) => return Err("timed out"), Err(DrtioError::TimedOut) => return Err(Error::Timeout),
Err(_) => return Err("aux packet error"), Err(_) => return Err(Error::AuxError),
} }
} }
pub async fn aux_transact( pub async fn aux_transact(
aux_mutex: &Mutex<bool>, aux_mutex: &Mutex<bool>,
linkno: u8, linkno: u8,
routing_table: &RoutingTable,
request: &Packet, request: &Packet,
timer: GlobalTimer, timer: GlobalTimer,
) -> Result<Packet, &'static str> { ) -> Result<Packet, Error> {
if !link_rx_up(linkno).await { if !link_rx_up(linkno).await {
return Err("link went down"); return Err(Error::LinkDown);
} }
let _lock = aux_mutex.async_lock().await; let _lock = aux_mutex.async_lock().await;
drtioaux_async::send(linkno, request).await.unwrap(); drtioaux_async::send(linkno, request).await.unwrap();
Ok(recv_aux_timeout(linkno, 200, timer).await?) loop {
let packet = recv_aux_timeout(linkno, 200, timer).await?;
if let Some(packet) = process_async_packets(linkno, routing_table, packet).await {
return Ok(packet);
}
}
} }
async fn drain_buffer(linkno: u8, draining_time: Milliseconds, timer: GlobalTimer) { async fn drain_buffer(linkno: u8, draining_time: Milliseconds, timer: GlobalTimer) {
@ -172,12 +184,17 @@ pub mod drtio {
loop { loop {
if timer.get_time() > max_time { if timer.get_time() > max_time {
return; return;
} //could this be cut short? }
let _ = drtioaux_async::recv(linkno).await; let _ = drtioaux_async::recv(linkno).await;
} }
} }
async fn ping_remote(aux_mutex: &Rc<Mutex<bool>>, linkno: u8, timer: GlobalTimer) -> u32 { async fn ping_remote(
aux_mutex: &Rc<Mutex<bool>>,
linkno: u8,
routing_table: &RoutingTable,
timer: GlobalTimer,
) -> u32 {
let mut count = 0; let mut count = 0;
loop { loop {
if !link_rx_up(linkno).await { if !link_rx_up(linkno).await {
@ -187,7 +204,7 @@ pub mod drtio {
if count > 100 { if count > 100 {
return 0; return 0;
} }
let reply = aux_transact(aux_mutex, linkno, &Packet::EchoRequest, timer).await; let reply = aux_transact(aux_mutex, linkno, routing_table, &Packet::EchoRequest, timer).await;
match reply { match reply {
Ok(Packet::EchoReply) => { Ok(Packet::EchoReply) => {
// make sure receive buffer is drained // make sure receive buffer is drained
@ -200,7 +217,7 @@ pub mod drtio {
} }
} }
async fn sync_tsc(aux_mutex: &Rc<Mutex<bool>>, linkno: u8, timer: GlobalTimer) -> Result<(), &'static str> { async fn sync_tsc(aux_mutex: &Rc<Mutex<bool>>, linkno: u8, timer: GlobalTimer) -> Result<(), Error> {
let _lock = aux_mutex.async_lock().await; let _lock = aux_mutex.async_lock().await;
unsafe { unsafe {
@ -211,22 +228,23 @@ pub mod drtio {
// by the satellite, in response to a TSC set on the RT link. // by the satellite, in response to a TSC set on the RT link.
let reply = recv_aux_timeout(linkno, 10000, timer).await?; let reply = recv_aux_timeout(linkno, 10000, timer).await?;
if reply == Packet::TSCAck { if reply == Packet::TSCAck {
return Ok(()); Ok(())
} else { } else {
return Err("unexpected reply"); Err(Error::UnexpectedReply)
} }
} }
async fn load_routing_table( async fn load_routing_table(
aux_mutex: &Rc<Mutex<bool>>, aux_mutex: &Rc<Mutex<bool>>,
linkno: u8, linkno: u8,
routing_table: &drtio_routing::RoutingTable, routing_table: &RoutingTable,
timer: GlobalTimer, timer: GlobalTimer,
) -> Result<(), &'static str> { ) -> Result<(), Error> {
for i in 0..drtio_routing::DEST_COUNT { for i in 0..drtio_routing::DEST_COUNT {
let reply = aux_transact( let reply = aux_transact(
aux_mutex, aux_mutex,
linkno, linkno,
routing_table,
&Packet::RoutingSetPath { &Packet::RoutingSetPath {
destination: i as u8, destination: i as u8,
hops: routing_table.0[i], hops: routing_table.0[i],
@ -235,7 +253,7 @@ pub mod drtio {
) )
.await?; .await?;
if reply != Packet::RoutingAck { if reply != Packet::RoutingAck {
return Err("unexpected reply"); return Err(Error::UnexpectedReply);
} }
} }
Ok(()) Ok(())
@ -245,13 +263,21 @@ pub mod drtio {
aux_mutex: &Rc<Mutex<bool>>, aux_mutex: &Rc<Mutex<bool>>,
linkno: u8, linkno: u8,
rank: u8, rank: u8,
routing_table: &RoutingTable,
timer: GlobalTimer, timer: GlobalTimer,
) -> Result<(), &'static str> { ) -> Result<(), Error> {
let reply = aux_transact(aux_mutex, linkno, &Packet::RoutingSetRank { rank: rank }, timer).await?; let reply = aux_transact(
if reply != Packet::RoutingAck { aux_mutex,
return Err("unexpected reply"); linkno,
routing_table,
&Packet::RoutingSetRank { rank: rank },
timer,
)
.await?;
match reply {
Packet::RoutingAck => Ok(()),
_ => Err(Error::UnexpectedReply),
} }
Ok(())
} }
async fn init_buffer_space(destination: u8, linkno: u8) { async fn init_buffer_space(destination: u8, linkno: u8) {
@ -270,10 +296,14 @@ pub mod drtio {
} }
} }
async fn process_unsolicited_aux(aux_mutex: &Rc<Mutex<bool>>, linkno: u8) { async fn process_unsolicited_aux(aux_mutex: &Mutex<bool>, linkno: u8, routing_table: &RoutingTable) {
let _lock = aux_mutex.async_lock().await; let _lock = aux_mutex.async_lock().await;
match drtioaux_async::recv(linkno).await { match drtioaux_async::recv(linkno).await {
Ok(Some(packet)) => warn!("[LINK#{}] unsolicited aux packet: {:?}", linkno, packet), Ok(Some(packet)) => {
if let Some(packet) = process_async_packets(linkno, routing_table, packet).await {
warn!("[LINK#{}] unsolicited aux packet: {:?}", linkno, packet);
}
}
Ok(None) => (), Ok(None) => (),
Err(_) => warn!("[LINK#{}] aux packet error", linkno), Err(_) => warn!("[LINK#{}] aux packet error", linkno),
} }
@ -301,7 +331,7 @@ pub mod drtio {
} }
async fn destination_set_up( async fn destination_set_up(
routing_table: &drtio_routing::RoutingTable, routing_table: &RoutingTable,
up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>, up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>,
destination: u8, destination: u8,
up: bool, up: bool,
@ -324,7 +354,7 @@ pub mod drtio {
async fn destination_survey( async fn destination_survey(
aux_mutex: &Rc<Mutex<bool>>, aux_mutex: &Rc<Mutex<bool>>,
routing_table: &drtio_routing::RoutingTable, routing_table: &RoutingTable,
up_links: &[bool], up_links: &[bool],
up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>, up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>,
timer: GlobalTimer, timer: GlobalTimer,
@ -345,6 +375,7 @@ pub mod drtio {
let reply = aux_transact( let reply = aux_transact(
aux_mutex, aux_mutex,
linkno, linkno,
routing_table,
&Packet::DestinationStatusRequest { &Packet::DestinationStatusRequest {
destination: destination, destination: destination,
}, },
@ -400,6 +431,7 @@ pub mod drtio {
let reply = aux_transact( let reply = aux_transact(
aux_mutex, aux_mutex,
linkno, linkno,
routing_table,
&Packet::DestinationStatusRequest { &Packet::DestinationStatusRequest {
destination: destination, destination: destination,
}, },
@ -427,7 +459,7 @@ pub mod drtio {
pub async fn link_task( pub async fn link_task(
aux_mutex: &Rc<Mutex<bool>>, aux_mutex: &Rc<Mutex<bool>>,
routing_table: &drtio_routing::RoutingTable, routing_table: &RoutingTable,
up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>, up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>,
timer: GlobalTimer, timer: GlobalTimer,
) { ) {
@ -438,8 +470,7 @@ pub mod drtio {
if up_links[linkno as usize] { if up_links[linkno as usize] {
/* link was previously up */ /* link was previously up */
if link_rx_up(linkno).await { if link_rx_up(linkno).await {
process_async_packets(aux_mutex, linkno, routing_table, timer).await; process_unsolicited_aux(aux_mutex, linkno, routing_table).await;
process_unsolicited_aux(aux_mutex, linkno).await;
process_local_errors(linkno).await; process_local_errors(linkno).await;
} else { } else {
info!("[LINK#{}] link is down", linkno); info!("[LINK#{}] link is down", linkno);
@ -449,7 +480,7 @@ pub mod drtio {
/* link was previously down */ /* link was previously down */
if link_rx_up(linkno).await { if link_rx_up(linkno).await {
info!("[LINK#{}] link RX became up, pinging", linkno); info!("[LINK#{}] link RX became up, pinging", linkno);
let ping_count = ping_remote(aux_mutex, linkno, timer).await; let ping_count = ping_remote(aux_mutex, linkno, routing_table, timer).await;
if ping_count > 0 { if ping_count > 0 {
info!("[LINK#{}] remote replied after {} packets", linkno, ping_count); info!("[LINK#{}] remote replied after {} packets", linkno, ping_count);
up_links[linkno as usize] = true; up_links[linkno as usize] = true;
@ -459,7 +490,7 @@ pub mod drtio {
if let Err(e) = load_routing_table(aux_mutex, linkno, routing_table, timer).await { if let Err(e) = load_routing_table(aux_mutex, linkno, routing_table, timer).await {
error!("[LINK#{}] failed to load routing table ({})", linkno, e); error!("[LINK#{}] failed to load routing table ({})", linkno, e);
} }
if let Err(e) = set_rank(aux_mutex, linkno, 1 as u8, timer).await { if let Err(e) = set_rank(aux_mutex, linkno, 1 as u8, routing_table, timer).await {
error!("[LINK#{}] failed to set rank ({})", linkno, e); error!("[LINK#{}] failed to set rank ({})", linkno, e);
} }
info!("[LINK#{}] link initialization completed", linkno); info!("[LINK#{}] link initialization completed", linkno);
@ -476,7 +507,7 @@ pub mod drtio {
} }
#[allow(dead_code)] #[allow(dead_code)]
pub fn reset(aux_mutex: Rc<Mutex<bool>>, mut timer: GlobalTimer) { pub fn reset(aux_mutex: Rc<Mutex<bool>>, routing_table: &RoutingTable, mut timer: GlobalTimer) {
for linkno in 0..csr::DRTIO.len() { for linkno in 0..csr::DRTIO.len() {
unsafe { unsafe {
(csr::DRTIO[linkno].reset_write)(1); (csr::DRTIO[linkno].reset_write)(1);
@ -492,7 +523,13 @@ pub mod drtio {
for linkno in 0..csr::DRTIO.len() { for linkno in 0..csr::DRTIO.len() {
let linkno = linkno as u8; let linkno = linkno as u8;
if task::block_on(link_rx_up(linkno)) { if task::block_on(link_rx_up(linkno)) {
let reply = task::block_on(aux_transact(&aux_mutex, linkno, &Packet::ResetRequest, timer)); let reply = task::block_on(aux_transact(
&aux_mutex,
linkno,
routing_table,
&Packet::ResetRequest,
timer,
));
match reply { match reply {
Ok(Packet::ResetAck) => (), Ok(Packet::ResetAck) => (),
Ok(_) => error!("[LINK#{}] reset failed, received unexpected aux packet", linkno), Ok(_) => error!("[LINK#{}] reset failed, received unexpected aux packet", linkno),
@ -505,14 +542,15 @@ pub mod drtio {
async fn partition_data<PacketF, HandlerF>( async fn partition_data<PacketF, HandlerF>(
linkno: u8, linkno: u8,
aux_mutex: &Rc<Mutex<bool>>, aux_mutex: &Rc<Mutex<bool>>,
routing_table: &RoutingTable,
timer: GlobalTimer, timer: GlobalTimer,
data: &[u8], data: &[u8],
packet_f: PacketF, packet_f: PacketF,
reply_handler_f: HandlerF, reply_handler_f: HandlerF,
) -> Result<(), &'static str> ) -> Result<(), Error>
where where
PacketF: Fn(&[u8; MASTER_PAYLOAD_MAX_SIZE], PayloadStatus, usize) -> Packet, PacketF: Fn(&[u8; MASTER_PAYLOAD_MAX_SIZE], PayloadStatus, usize) -> Packet,
HandlerF: Fn(&Packet) -> Result<(), &'static str>, HandlerF: Fn(&Packet) -> Result<(), Error>,
{ {
let mut i = 0; let mut i = 0;
while i < data.len() { while i < data.len() {
@ -528,7 +566,7 @@ pub mod drtio {
i += len; i += len;
let status = PayloadStatus::from_status(first, last); let status = PayloadStatus::from_status(first, last);
let packet = packet_f(&slice, status, len); let packet = packet_f(&slice, status, len);
let reply = aux_transact(aux_mutex, linkno, &packet, timer).await?; let reply = aux_transact(aux_mutex, linkno, routing_table, &packet, timer).await?;
reply_handler_f(&reply)?; reply_handler_f(&reply)?;
} }
Ok(()) Ok(())
@ -536,16 +574,17 @@ pub mod drtio {
pub async fn ddma_upload_trace( pub async fn ddma_upload_trace(
aux_mutex: &Rc<Mutex<bool>>, aux_mutex: &Rc<Mutex<bool>>,
routing_table: &drtio_routing::RoutingTable, routing_table: &RoutingTable,
timer: GlobalTimer, timer: GlobalTimer,
id: u32, id: u32,
destination: u8, destination: u8,
trace: &Vec<u8>, trace: &Vec<u8>,
) -> Result<(), &'static str> { ) -> Result<(), Error> {
let linkno = routing_table.0[destination as usize][0] - 1; let linkno = routing_table.0[destination as usize][0] - 1;
partition_data( partition_data(
linkno, linkno,
aux_mutex, aux_mutex,
routing_table,
timer, timer,
trace, trace,
|slice, status, len| Packet::DmaAddTraceRequest { |slice, status, len| Packet::DmaAddTraceRequest {
@ -566,8 +605,8 @@ pub mod drtio {
destination: 0, destination: 0,
succeeded: false, succeeded: false,
.. ..
} => Err("error adding trace on satellite"), } => Err(Error::DmaAddTraceFail(destination)),
_ => Err("adding DMA trace failed, unexpected aux packet"), _ => Err(Error::UnexpectedReply),
}, },
) )
.await .await
@ -575,15 +614,16 @@ pub mod drtio {
pub async fn ddma_send_erase( pub async fn ddma_send_erase(
aux_mutex: &Rc<Mutex<bool>>, aux_mutex: &Rc<Mutex<bool>>,
routing_table: &drtio_routing::RoutingTable, routing_table: &RoutingTable,
timer: GlobalTimer, timer: GlobalTimer,
id: u32, id: u32,
destination: u8, destination: u8,
) -> Result<(), &'static str> { ) -> Result<(), Error> {
let linkno = routing_table.0[destination as usize][0] - 1; let linkno = routing_table.0[destination as usize][0] - 1;
let reply = aux_transact( let reply = aux_transact(
aux_mutex, aux_mutex,
linkno, linkno,
routing_table,
&Packet::DmaRemoveTraceRequest { &Packet::DmaRemoveTraceRequest {
id: id, id: id,
source: 0, source: 0,
@ -591,33 +631,33 @@ pub mod drtio {
}, },
timer, timer,
) )
.await; .await?;
match reply { match reply {
Ok(Packet::DmaRemoveTraceReply { Packet::DmaRemoveTraceReply {
destination: 0, destination: 0,
succeeded: true, succeeded: true,
}) => Ok(()), } => Ok(()),
Ok(Packet::DmaRemoveTraceReply { Packet::DmaRemoveTraceReply {
destination: 0, destination: 0,
succeeded: false, succeeded: false,
}) => Err("satellite DMA erase error"), } => Err(Error::DmaEraseFail(destination)),
Ok(_) => Err("adding trace failed, unexpected aux packet"), _ => Err(Error::UnexpectedReply),
Err(_) => Err("erasing trace failed, aux error"),
} }
} }
pub async fn ddma_send_playback( pub async fn ddma_send_playback(
aux_mutex: &Rc<Mutex<bool>>, aux_mutex: &Rc<Mutex<bool>>,
routing_table: &drtio_routing::RoutingTable, routing_table: &RoutingTable,
timer: GlobalTimer, timer: GlobalTimer,
id: u32, id: u32,
destination: u8, destination: u8,
timestamp: u64, timestamp: u64,
) -> Result<(), &'static str> { ) -> Result<(), Error> {
let linkno = routing_table.0[destination as usize][0] - 1; let linkno = routing_table.0[destination as usize][0] - 1;
let reply = aux_transact( let reply = aux_transact(
aux_mutex, aux_mutex,
linkno, linkno,
routing_table,
&Packet::DmaPlaybackRequest { &Packet::DmaPlaybackRequest {
id: id, id: id,
source: 0, source: 0,
@ -626,45 +666,44 @@ pub mod drtio {
}, },
timer, timer,
) )
.await; .await?;
match reply { match reply {
Ok(Packet::DmaPlaybackReply { Packet::DmaPlaybackReply {
destination: 0, destination: 0,
succeeded: true, succeeded: true,
}) => Ok(()), } => Ok(()),
Ok(Packet::DmaPlaybackReply { Packet::DmaPlaybackReply {
destination: 0, destination: 0,
succeeded: false, succeeded: false,
}) => Err("error on DMA playback request"), } => Err(Error::DmaPlaybackFail(destination)),
Ok(_) => Err("received unexpected aux packet during DMA playback"), _ => Err(Error::UnexpectedReply),
Err(_) => Err("aux error on DMA playback"),
} }
} }
async fn analyzer_get_data( async fn analyzer_get_data(
aux_mutex: &Rc<Mutex<bool>>, aux_mutex: &Rc<Mutex<bool>>,
routing_table: &drtio_routing::RoutingTable, routing_table: &RoutingTable,
timer: GlobalTimer, timer: GlobalTimer,
destination: u8, destination: u8,
) -> Result<RemoteBuffer, &'static str> { ) -> Result<RemoteBuffer, Error> {
let linkno = routing_table.0[destination as usize][0] - 1; let linkno = routing_table.0[destination as usize][0] - 1;
let reply = aux_transact( let reply = aux_transact(
aux_mutex, aux_mutex,
linkno, linkno,
routing_table,
&Packet::AnalyzerHeaderRequest { &Packet::AnalyzerHeaderRequest {
destination: destination, destination: destination,
}, },
timer, timer,
) )
.await; .await?;
let (sent, total, overflow) = match reply { let (sent, total, overflow) = match reply {
Ok(Packet::AnalyzerHeader { Packet::AnalyzerHeader {
sent_bytes, sent_bytes,
total_byte_count, total_byte_count,
overflow_occurred, overflow_occurred,
}) => (sent_bytes, total_byte_count, overflow_occurred), } => (sent_bytes, total_byte_count, overflow_occurred),
Ok(_) => return Err("received unexpected aux packet during remote analyzer header request"), _ => return Err(Error::UnexpectedReply),
Err(e) => return Err(e),
}; };
let mut remote_data: Vec<u8> = Vec::new(); let mut remote_data: Vec<u8> = Vec::new();
@ -674,19 +713,19 @@ pub mod drtio {
let reply = aux_transact( let reply = aux_transact(
aux_mutex, aux_mutex,
linkno, linkno,
routing_table,
&Packet::AnalyzerDataRequest { &Packet::AnalyzerDataRequest {
destination: destination, destination: destination,
}, },
timer, timer,
) )
.await; .await?;
match reply { match reply {
Ok(Packet::AnalyzerData { last, length, data }) => { Packet::AnalyzerData { last, length, data } => {
last_packet = last; last_packet = last;
remote_data.extend(&data[0..length as usize]); remote_data.extend(&data[0..length as usize]);
} }
Ok(_) => return Err("received unexpected aux packet during remote analyzer data request"), _ => return Err(Error::UnexpectedReply),
Err(e) => return Err(e),
} }
} }
} }
@ -701,10 +740,10 @@ pub mod drtio {
pub async fn analyzer_query( pub async fn analyzer_query(
aux_mutex: &Rc<Mutex<bool>>, aux_mutex: &Rc<Mutex<bool>>,
routing_table: &drtio_routing::RoutingTable, routing_table: &RoutingTable,
up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>, up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>,
timer: GlobalTimer, timer: GlobalTimer,
) -> Result<Vec<RemoteBuffer>, &'static str> { ) -> Result<Vec<RemoteBuffer>, Error> {
let mut remote_buffers: Vec<RemoteBuffer> = Vec::new(); let mut remote_buffers: Vec<RemoteBuffer> = Vec::new();
for i in 1..drtio_routing::DEST_COUNT { for i in 1..drtio_routing::DEST_COUNT {
if destination_up(up_destinations, i as u8).await { if destination_up(up_destinations, i as u8).await {
@ -716,16 +755,17 @@ pub mod drtio {
pub async fn subkernel_upload( pub async fn subkernel_upload(
aux_mutex: &Rc<Mutex<bool>>, aux_mutex: &Rc<Mutex<bool>>,
routing_table: &drtio_routing::RoutingTable, routing_table: &RoutingTable,
timer: GlobalTimer, timer: GlobalTimer,
id: u32, id: u32,
destination: u8, destination: u8,
data: &Vec<u8>, data: &Vec<u8>,
) -> Result<(), &'static str> { ) -> Result<(), Error> {
let linkno = routing_table.0[destination as usize][0] - 1; let linkno = routing_table.0[destination as usize][0] - 1;
partition_data( partition_data(
linkno, linkno,
aux_mutex, aux_mutex,
routing_table,
timer, timer,
data, data,
|slice, status, len| Packet::SubkernelAddDataRequest { |slice, status, len| Packet::SubkernelAddDataRequest {
@ -737,8 +777,8 @@ pub mod drtio {
}, },
|reply| match reply { |reply| match reply {
Packet::SubkernelAddDataReply { succeeded: true } => Ok(()), Packet::SubkernelAddDataReply { succeeded: true } => Ok(()),
Packet::SubkernelAddDataReply { succeeded: false } => Err("error adding subkernel on satellite"), Packet::SubkernelAddDataReply { succeeded: false } => Err(Error::SubkernelAddFail(destination)),
_ => Err("adding subkernel failed, unexpected aux packet"), _ => Err(Error::UnexpectedReply),
}, },
) )
.await .await
@ -746,16 +786,17 @@ pub mod drtio {
pub async fn subkernel_load( pub async fn subkernel_load(
aux_mutex: &Rc<Mutex<bool>>, aux_mutex: &Rc<Mutex<bool>>,
routing_table: &drtio_routing::RoutingTable, routing_table: &RoutingTable,
timer: GlobalTimer, timer: GlobalTimer,
id: u32, id: u32,
destination: u8, destination: u8,
run: bool, run: bool,
) -> Result<(), &'static str> { ) -> Result<(), Error> {
let linkno = routing_table.0[destination as usize][0] - 1; let linkno = routing_table.0[destination as usize][0] - 1;
let reply = aux_transact( let reply = aux_transact(
aux_mutex, aux_mutex,
linkno, linkno,
routing_table,
&Packet::SubkernelLoadRunRequest { &Packet::SubkernelLoadRunRequest {
id: id, id: id,
source: 0, source: 0,
@ -773,23 +814,24 @@ pub mod drtio {
Packet::SubkernelLoadRunReply { Packet::SubkernelLoadRunReply {
destination: 0, destination: 0,
succeeded: false, succeeded: false,
} => return Err("error on subkernel run request"), } => return Err(Error::SubkernelRunFail(destination)),
_ => return Err("received unexpected aux packet during subkernel run"), _ => Err(Error::UnexpectedReply),
} }
} }
pub async fn subkernel_retrieve_exception( pub async fn subkernel_retrieve_exception(
aux_mutex: &Rc<Mutex<bool>>, aux_mutex: &Rc<Mutex<bool>>,
routing_table: &drtio_routing::RoutingTable, routing_table: &RoutingTable,
timer: GlobalTimer, timer: GlobalTimer,
destination: u8, destination: u8,
) -> Result<Vec<u8>, &'static str> { ) -> Result<Vec<u8>, Error> {
let linkno = routing_table.0[destination as usize][0] - 1; let linkno = routing_table.0[destination as usize][0] - 1;
let mut remote_data: Vec<u8> = Vec::new(); let mut remote_data: Vec<u8> = Vec::new();
loop { loop {
let reply = aux_transact( let reply = aux_transact(
aux_mutex, aux_mutex,
linkno, linkno,
routing_table,
&Packet::SubkernelExceptionRequest { &Packet::SubkernelExceptionRequest {
destination: destination, destination: destination,
}, },
@ -803,23 +845,24 @@ pub mod drtio {
return Ok(remote_data); return Ok(remote_data);
} }
} }
_ => return Err("received unexpected aux packet during subkernel exception request"), _ => return Err(Error::UnexpectedReply),
} }
} }
} }
pub async fn subkernel_send_message( pub async fn subkernel_send_message(
aux_mutex: &Rc<Mutex<bool>>, aux_mutex: &Rc<Mutex<bool>>,
routing_table: &drtio_routing::RoutingTable, routing_table: &RoutingTable,
timer: GlobalTimer, timer: GlobalTimer,
id: u32, id: u32,
destination: u8, destination: u8,
message: &[u8], message: &[u8],
) -> Result<(), &'static str> { ) -> Result<(), Error> {
let linkno = routing_table.0[destination as usize][0] - 1; let linkno = routing_table.0[destination as usize][0] - 1;
partition_data( partition_data(
linkno, linkno,
aux_mutex, aux_mutex,
routing_table,
timer, timer,
message, message,
|slice, status, len| Packet::SubkernelMessage { |slice, status, len| Packet::SubkernelMessage {
@ -832,7 +875,7 @@ pub mod drtio {
}, },
|reply| match reply { |reply| match reply {
Packet::SubkernelMessageAck { .. } => Ok(()), Packet::SubkernelMessageAck { .. } => Ok(()),
_ => Err("sending message to subkernel failed, unexpected aux packet"), _ => Err(Error::UnexpectedReply),
}, },
) )
.await .await
@ -845,19 +888,19 @@ pub mod drtio {
pub fn startup( pub fn startup(
_aux_mutex: &Rc<Mutex<bool>>, _aux_mutex: &Rc<Mutex<bool>>,
_routing_table: &Rc<RefCell<drtio_routing::RoutingTable>>, _routing_table: &Rc<RefCell<RoutingTable>>,
_up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>, _up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>,
_timer: GlobalTimer, _timer: GlobalTimer,
) { ) {
} }
#[allow(dead_code)] #[allow(dead_code)]
pub fn reset(_aux_mutex: Rc<Mutex<bool>>, mut _timer: GlobalTimer) {} pub fn reset(_aux_mutex: Rc<Mutex<bool>>, _routing_table: &RoutingTable, mut _timer: GlobalTimer) {}
} }
pub fn startup( pub fn startup(
aux_mutex: &Rc<Mutex<bool>>, aux_mutex: &Rc<Mutex<bool>>,
routing_table: &Rc<RefCell<drtio_routing::RoutingTable>>, routing_table: &Rc<RefCell<RoutingTable>>,
up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>, up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>,
timer: GlobalTimer, timer: GlobalTimer,
) { ) {
@ -868,9 +911,9 @@ pub fn startup(
} }
#[allow(dead_code)] #[allow(dead_code)]
pub fn reset(aux_mutex: Rc<Mutex<bool>>, timer: GlobalTimer) { pub fn reset(aux_mutex: Rc<Mutex<bool>>, routing_table: &RoutingTable, timer: GlobalTimer) {
unsafe { unsafe {
csr::rtio_core::reset_write(1); csr::rtio_core::reset_write(1);
} }
drtio::reset(aux_mutex, timer) drtio::reset(aux_mutex, routing_table, timer)
} }

View File

@ -7,7 +7,7 @@ use libboard_zynq::{time::Milliseconds, timer::GlobalTimer};
use libcortex_a9::mutex::Mutex; use libcortex_a9::mutex::Mutex;
use log::{error, warn}; use log::{error, warn};
use crate::rtio_mgt::drtio; use crate::rtio_mgt::{drtio, drtio::Error as DrtioError};
#[derive(Debug, PartialEq, Clone, Copy)] #[derive(Debug, PartialEq, Clone, Copy)]
pub enum FinishStatus { pub enum FinishStatus {
@ -31,11 +31,11 @@ pub enum Error {
SubkernelNotFound, SubkernelNotFound,
SubkernelException, SubkernelException,
CommLost, CommLost,
DrtioError(&'static str), DrtioError(DrtioError),
} }
impl From<&'static str> for Error { impl From<DrtioError> for Error {
fn from(value: &'static str) -> Error { fn from(value: DrtioError) -> Error {
Error::DrtioError(value) Error::DrtioError(value)
} }
} }

View File

@ -7,6 +7,7 @@ build = "build.rs"
[features] [features]
target_zc706 = ["libboard_zynq/target_zc706", "libsupport_zynq/target_zc706", "libconfig/target_zc706", "libboard_artiq/target_zc706"] target_zc706 = ["libboard_zynq/target_zc706", "libsupport_zynq/target_zc706", "libconfig/target_zc706", "libboard_artiq/target_zc706"]
target_kasli_soc = ["libboard_zynq/target_kasli_soc", "libsupport_zynq/target_kasli_soc", "libconfig/target_kasli_soc", "libboard_artiq/target_kasli_soc"] target_kasli_soc = ["libboard_zynq/target_kasli_soc", "libsupport_zynq/target_kasli_soc", "libconfig/target_kasli_soc", "libboard_artiq/target_kasli_soc"]
calibrate_wrpll_skew = ["libboard_artiq/calibrate_wrpll_skew"]
default = ["target_zc706", ] default = ["target_zc706", ]
[build-dependencies] [build-dependencies]

View File

@ -40,7 +40,7 @@ use libboard_zynq::error_led::ErrorLED;
use libboard_zynq::{i2c::I2c, print, println, time::Milliseconds, timer::GlobalTimer}; use libboard_zynq::{i2c::I2c, print, println, time::Milliseconds, timer::GlobalTimer};
use libcortex_a9::{l2c::enable_l2_cache, regs::MPIDR}; use libcortex_a9::{l2c::enable_l2_cache, regs::MPIDR};
use libregister::RegisterR; use libregister::RegisterR;
use libsupport_zynq::ram; use libsupport_zynq::{exception_vectors, ram};
use routing::Router; use routing::Router;
use subkernel::Manager as KernelManager; use subkernel::Manager as KernelManager;
@ -50,6 +50,11 @@ mod repeater;
mod routing; mod routing;
mod subkernel; mod subkernel;
// linker symbols
extern "C" {
static __exceptions_start: u32;
}
fn drtiosat_reset(reset: bool) { fn drtiosat_reset(reset: bool) {
unsafe { unsafe {
csr::drtiosat::reset_write(if reset { 1 } else { 0 }); csr::drtiosat::reset_write(if reset { 1 } else { 0 });
@ -76,12 +81,6 @@ fn drtiosat_tsc_loaded() -> bool {
} }
} }
fn drtiosat_async_ready() {
unsafe {
csr::drtiosat::async_messages_ready_write(1);
}
}
#[cfg(has_drtio_routing)] #[cfg(has_drtio_routing)]
macro_rules! forward { macro_rules! forward {
($routing_table:expr, $destination:expr, $rank:expr, $repeaters:expr, $packet:expr, $timer:expr) => {{ ($routing_table:expr, $destination:expr, $rank:expr, $repeaters:expr, $packet:expr, $timer:expr) => {{
@ -240,14 +239,6 @@ fn process_aux_packet(
#[cfg(not(has_drtio_routing))] #[cfg(not(has_drtio_routing))]
drtioaux::Packet::RoutingSetRank { rank: _ } => drtioaux::send(0, &drtioaux::Packet::RoutingAck), drtioaux::Packet::RoutingSetRank { rank: _ } => drtioaux::send(0, &drtioaux::Packet::RoutingAck),
drtioaux::Packet::RoutingRetrievePackets => {
let packet = router
.get_upstream_packet()
.or(Some(drtioaux::Packet::RoutingNoPackets))
.unwrap();
drtioaux::send(0, &packet)
}
drtioaux::Packet::MonitorRequest { drtioaux::Packet::MonitorRequest {
destination: _destination, destination: _destination,
channel, channel,
@ -832,9 +823,8 @@ const SI549_SETTINGS: si549::FrequencySetting = si549::FrequencySetting {
lsdiv: 0, lsdiv: 0,
fbdiv: 0x04815791F25, fbdiv: 0x04815791F25,
}, },
#[cfg(has_wrpll)]
helper: si549::DividerConfig { helper: si549::DividerConfig {
// 125Mhz*32767/32768 // 125MHz*32767/32768
hsdiv: 0x058, hsdiv: 0x058,
lsdiv: 0, lsdiv: 0,
fbdiv: 0x04814E8F442, fbdiv: 0x04814E8F442,
@ -842,15 +832,14 @@ const SI549_SETTINGS: si549::FrequencySetting = si549::FrequencySetting {
}; };
#[cfg(all(has_si549, rtio_frequency = "100.0"))] #[cfg(all(has_si549, rtio_frequency = "100.0"))]
pub const SI549_SETTINGS: si549::FrequencySetting = si549::FrequencySetting { const SI549_SETTINGS: si549::FrequencySetting = si549::FrequencySetting {
main: si549::DividerConfig { main: si549::DividerConfig {
hsdiv: 0x06C, hsdiv: 0x06C,
lsdiv: 0, lsdiv: 0,
fbdiv: 0x046C5F49797, fbdiv: 0x046C5F49797,
}, },
#[cfg(has_wrpll)]
helper: si549::DividerConfig { helper: si549::DividerConfig {
// 100Mhz*32767/32768 // 100MHz*32767/32768
hsdiv: 0x06C, hsdiv: 0x06C,
lsdiv: 0, lsdiv: 0,
fbdiv: 0x046C5670BBD, fbdiv: 0x046C5670BBD,
@ -861,6 +850,9 @@ static mut LOG_BUFFER: [u8; 1 << 17] = [0; 1 << 17];
#[no_mangle] #[no_mangle]
pub extern "C" fn main_core0() -> i32 { pub extern "C" fn main_core0() -> i32 {
unsafe {
exception_vectors::set_vector_table(&__exceptions_start as *const u32 as u32);
}
enable_l2_cache(0x8); enable_l2_cache(0x8);
let mut timer = GlobalTimer::start(); let mut timer = GlobalTimer::start();
@ -907,7 +899,7 @@ pub extern "C" fn main_core0() -> i32 {
#[cfg(has_si5324)] #[cfg(has_si5324)]
si5324::setup(&mut i2c, &SI5324_SETTINGS, si5324::Input::Ckin1, &mut timer).expect("cannot initialize Si5324"); si5324::setup(&mut i2c, &SI5324_SETTINGS, si5324::Input::Ckin1, &mut timer).expect("cannot initialize Si5324");
#[cfg(has_si549)] #[cfg(has_si549)]
si549::main_setup(&mut timer, SI549_SETTINGS).expect("cannot initialize main Si549"); si549::main_setup(&mut timer, &SI549_SETTINGS).expect("cannot initialize main Si549");
timer.delay_us(100_000); timer.delay_us(100_000);
info!("Switching SYS clocks..."); info!("Switching SYS clocks...");
@ -925,8 +917,8 @@ pub extern "C" fn main_core0() -> i32 {
unsafe { unsafe {
csr::gt_drtio::txenable_write(0xffffffffu32 as _); csr::gt_drtio::txenable_write(0xffffffffu32 as _);
} }
#[cfg(has_wrpll)] #[cfg(has_si549)]
si549::wrpll::helper_setup(&mut timer, SI549_SETTINGS).expect("cannot initialize helper Si549"); si549::helper_setup(&mut timer, &SI549_SETTINGS).expect("cannot initialize helper Si549");
#[cfg(has_drtio_routing)] #[cfg(has_drtio_routing)]
let mut repeaters = [repeater::Repeater::default(); csr::DRTIOREP.len()]; let mut repeaters = [repeater::Repeater::default(); csr::DRTIOREP.len()];
@ -1061,8 +1053,8 @@ pub extern "C" fn main_core0() -> i32 {
} }
} }
if router.any_upstream_waiting() { if let Some(packet) = router.get_upstream_packet() {
drtiosat_async_ready(); drtioaux::send(0, &packet).unwrap();
} }
} }

View File

@ -119,16 +119,11 @@ impl Repeater {
} }
} }
RepeaterState::Up => { RepeaterState::Up => {
self.process_unsolicited_aux(); self.process_unsolicited_aux(routing_table, rank, destination, router);
if !rep_link_rx_up(self.repno) { if !rep_link_rx_up(self.repno) {
info!("[REP#{}] link is down", self.repno); info!("[REP#{}] link is down", self.repno);
self.state = RepeaterState::Down; self.state = RepeaterState::Down;
} }
if self.async_messages_ready() {
if let Err(e) = self.handle_async(routing_table, rank, destination, router, timer) {
warn!("[REP#{}] Error handling async messages ({:?})", self.repno, e);
}
}
} }
RepeaterState::Failed => { RepeaterState::Failed => {
if !rep_link_rx_up(self.repno) { if !rep_link_rx_up(self.repno) {
@ -139,9 +134,15 @@ impl Repeater {
} }
} }
fn process_unsolicited_aux(&self) { fn process_unsolicited_aux(
&self,
routing_table: &drtio_routing::RoutingTable,
rank: u8,
destination: u8,
router: &mut Router,
) {
match drtioaux::recv(self.auxno) { match drtioaux::recv(self.auxno) {
Ok(Some(packet)) => warn!("[REP#{}] unsolicited aux packet: {:?}", self.repno, packet), Ok(Some(packet)) => router.route(packet, routing_table, rank, destination),
Ok(None) => (), Ok(None) => (),
Err(_) => warn!("[REP#{}] aux packet error", self.repno), Err(_) => warn!("[REP#{}] aux packet error", self.repno),
} }
@ -186,34 +187,6 @@ impl Repeater {
} }
} }
fn async_messages_ready(&self) -> bool {
let async_rdy;
unsafe {
async_rdy = (csr::DRTIOREP[self.repno as usize].async_messages_ready_read)();
(csr::DRTIOREP[self.repno as usize].async_messages_ready_write)(0);
}
async_rdy == 1
}
fn handle_async(
&self,
routing_table: &drtio_routing::RoutingTable,
rank: u8,
self_destination: u8,
router: &mut Router,
timer: &mut GlobalTimer,
) -> Result<(), drtioaux::Error> {
loop {
drtioaux::send(self.auxno, &drtioaux::Packet::RoutingRetrievePackets).unwrap();
let reply = self.recv_aux_timeout(200, timer)?;
match reply {
drtioaux::Packet::RoutingNoPackets => break,
packet => router.route(packet, routing_table, rank, self_destination),
}
}
Ok(())
}
fn recv_aux_timeout(&self, timeout: u32, timer: &mut GlobalTimer) -> Result<drtioaux::Packet, drtioaux::Error> { fn recv_aux_timeout(&self, timeout: u32, timer: &mut GlobalTimer) -> Result<drtioaux::Packet, drtioaux::Error> {
let max_time = timer.get_time() + Milliseconds(timeout.into()); let max_time = timer.get_time() + Milliseconds(timeout.into());
loop { loop {

View File

@ -75,7 +75,6 @@ pub struct Router {
local_queue: VecDeque<drtioaux::Packet>, local_queue: VecDeque<drtioaux::Packet>,
#[cfg(has_drtio_routing)] #[cfg(has_drtio_routing)]
downstream_queue: VecDeque<(usize, drtioaux::Packet)>, downstream_queue: VecDeque<(usize, drtioaux::Packet)>,
upstream_notified: bool,
} }
impl Router { impl Router {
@ -85,7 +84,6 @@ impl Router {
local_queue: VecDeque::new(), local_queue: VecDeque::new(),
#[cfg(has_drtio_routing)] #[cfg(has_drtio_routing)]
downstream_queue: VecDeque::new(), downstream_queue: VecDeque::new(),
upstream_notified: false,
} }
} }
@ -161,22 +159,8 @@ impl Router {
} }
} }
pub fn any_upstream_waiting(&mut self) -> bool {
let empty = self.upstream_queue.is_empty();
if !empty && !self.upstream_notified {
self.upstream_notified = true; // so upstream will not get spammed with notifications
true
} else {
false
}
}
pub fn get_upstream_packet(&mut self) -> Option<drtioaux::Packet> { pub fn get_upstream_packet(&mut self) -> Option<drtioaux::Packet> {
let packet = self.upstream_queue.pop_front(); self.upstream_queue.pop_front()
if packet.is_none() {
self.upstream_notified = false;
}
packet
} }
#[cfg(has_drtio_routing)] #[cfg(has_drtio_routing)]