forked from M-Labs/artiq-zynq
Compare commits
13 Commits
Author | SHA1 | Date |
---|---|---|
morgan | bfbea2d0b8 | |
morgan | f8f6dcef14 | |
morgan | 30392c9ca8 | |
morgan | 963a4822c4 | |
morgan | 5aade6abb2 | |
morgan | 7300ecce25 | |
morgan | 0c8ec61527 | |
morgan | c7df09b6a3 | |
morgan | 9d5d883b1b | |
morgan | d00a9afdcc | |
morgan | f1a4a2f97f | |
morgan | 90890e39e0 | |
morgan | 3972efc61e |
|
@ -62,7 +62,7 @@ Notes:
|
||||||
License
|
License
|
||||||
-------
|
-------
|
||||||
|
|
||||||
Copyright (C) 2019-2024 M-Labs Limited.
|
Copyright (C) 2019-2023 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
56
flake.lock
|
@ -11,11 +11,11 @@
|
||||||
"src-pythonparser": "src-pythonparser"
|
"src-pythonparser": "src-pythonparser"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1716972728,
|
"lastModified": 1706785107,
|
||||||
"narHash": "sha256-88J+eckZamtwhcCQkPpKLu6R1hmgj5+C9n2U5i+sHUE=",
|
"narHash": "sha256-Uj72tqigiOCdewSSBBMg6zUpVKhwjAo1HeLJgvyZ3oc=",
|
||||||
"ref": "refs/heads/master",
|
"ref": "refs/heads/master",
|
||||||
"rev": "49e402780bebba437c6098047ab1dc68eaf5a17c",
|
"rev": "3aaa7e04f26a495e8847e47424bfc16d76d82bf8",
|
||||||
"revCount": 8808,
|
"revCount": 8672,
|
||||||
"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": 1707216368,
|
"lastModified": 1701573753,
|
||||||
"narHash": "sha256-ZXoqzG2QsVsybALLYXs473avXcyKSZNh2kIgcPo60XQ=",
|
"narHash": "sha256-vhEtXjb9AM6/HnsgfVmhJQeqQ9JqysUm7iWNzTIbexs=",
|
||||||
"owner": "m-labs",
|
"owner": "m-labs",
|
||||||
"repo": "artiq-comtools",
|
"repo": "artiq-comtools",
|
||||||
"rev": "e5d0204490bccc07ef9141b0d7c405ab01cb8273",
|
"rev": "199bdabf4de49cb7ada8a4ac7133008e0f8434b7",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -103,11 +103,11 @@
|
||||||
"mozilla-overlay_3": {
|
"mozilla-overlay_3": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1704373101,
|
"lastModified": 1695805681,
|
||||||
"narHash": "sha256-+gi59LRWRQmwROrmE1E2b3mtocwueCQqZ60CwLG+gbg=",
|
"narHash": "sha256-1ElPLD8eFfnuIk0G52HGGpRtQZ4QPCjChRlEOfkZ5ro=",
|
||||||
"owner": "mozilla",
|
"owner": "mozilla",
|
||||||
"repo": "nixpkgs-mozilla",
|
"repo": "nixpkgs-mozilla",
|
||||||
"rev": "9b11a87c0cc54e308fa83aac5b4ee1816d5418a2",
|
"rev": "6eabade97bc28d707a8b9d82ad13ef143836736e",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -118,16 +118,16 @@
|
||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1716542732,
|
"lastModified": 1706515015,
|
||||||
"narHash": "sha256-0Y9fRr0CUqWT4KgBITmaGwlnNIGMYuydu2L8iLTfHU4=",
|
"narHash": "sha256-eFfY5A7wlYy3jD/75lx6IJRueg4noE+jowl0a8lIlVo=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "d12251ef6e8e6a46e05689eeccd595bdbd3c9e60",
|
"rev": "f4a8d6d5324c327dcc2d863eb7f3cc06ad630df4",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"ref": "nixos-24.05",
|
"ref": "nixos-23.11",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
|
@ -147,11 +147,11 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1708937641,
|
"lastModified": 1701572254,
|
||||||
"narHash": "sha256-Hkb9VYFzFgkYxfbh4kYcDSn7DbMUYehoQDeTALrxo2Q=",
|
"narHash": "sha256-ixq8dlpyOytDr+d/OmW8v1Ioy9V2G2ibOlNj8GFDSq4=",
|
||||||
"owner": "m-labs",
|
"owner": "m-labs",
|
||||||
"repo": "sipyco",
|
"repo": "sipyco",
|
||||||
"rev": "4a28b311ce0069454b4e8fe1e6049db11b9f1296",
|
"rev": "cceac0df537887135f99aa6b1bdd82853f16b4d6",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -163,11 +163,11 @@
|
||||||
"src-migen": {
|
"src-migen": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1715484909,
|
"lastModified": 1702942348,
|
||||||
"narHash": "sha256-4DCHBUBfc/VA+7NW2Hr0+JP4NnKPru2uVJyZjCCk0Ws=",
|
"narHash": "sha256-gKIfHZxsv+jcgDFRW9mPqmwqbZXuRvXefkZcSFjOGHw=",
|
||||||
"owner": "m-labs",
|
"owner": "m-labs",
|
||||||
"repo": "migen",
|
"repo": "migen",
|
||||||
"rev": "4790bb577681a8c3a8d226bc196a4e5deb39e4df",
|
"rev": "50934ad10a87ade47219b796535978b9bdf24023",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -179,11 +179,11 @@
|
||||||
"src-misoc": {
|
"src-misoc": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1715647536,
|
"lastModified": 1699352904,
|
||||||
"narHash": "sha256-q+USDcaKHABwW56Jzq8u94iGPWlyLXMyVt0j/Gyg+IE=",
|
"narHash": "sha256-SglyTmXOPv8jJOjwAjJrj/WhAkItQfUbvKfUqrynwRg=",
|
||||||
"ref": "refs/heads/master",
|
"ref": "refs/heads/master",
|
||||||
"rev": "fea9de558c730bc394a5936094ae95bb9d6fa726",
|
"rev": "a53859f2167c31ab5225b6c09f30cf05527b94f4",
|
||||||
"revCount": 2455,
|
"revCount": 2452,
|
||||||
"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": 1716519432,
|
"lastModified": 1702982463,
|
||||||
"narHash": "sha256-vgKBJCQRPCutJ4n+FtJNczMZULWW7J3B8icf/PUothw=",
|
"narHash": "sha256-jKR3drE2rsTaYGEgIdv5kUo2LOb1JyIb4tJhVuCXTTc=",
|
||||||
"ref": "refs/heads/master",
|
"ref": "refs/heads/master",
|
||||||
"rev": "46dc25b89e46b9043129d77e3c9348916748e325",
|
"rev": "4168eb63a7e846863331ae4e656cfd82a867cca8",
|
||||||
"revCount": 645,
|
"revCount": 636,
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://git.m-labs.hk/m-labs/zynq-rs"
|
"url": "https://git.m-labs.hk/m-labs/zynq-rs"
|
||||||
},
|
},
|
||||||
|
|
65
flake.nix
65
flake.nix
|
@ -11,7 +11,6 @@
|
||||||
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;
|
||||||
|
@ -114,7 +113,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"
|
||||||
];
|
];
|
||||||
board-package-set = { target, variant, json ? null }: let
|
build = { 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";
|
||||||
|
@ -133,12 +132,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
|
||||||
llvmPackages_11.llvm
|
pkgs.llvmPackages_9.llvm
|
||||||
llvmPackages_11.clang-unwrapped
|
pkgs.llvmPackages_9.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="${llvmPackages_11.clang-unwrapped.lib}/lib/clang/11.1.0/include"
|
export CLANG_EXTRA_INCLUDE_DIR="${pkgs.llvmPackages_9.clang-unwrapped.lib}/lib/clang/9.0.1/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}
|
||||||
|
@ -274,7 +273,7 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
# for hitl-tests
|
# for hitl-tests
|
||||||
zc706-nist_qc2 = (board-package-set { target = "zc706"; variant = "nist_qc2"; });
|
zc706-nist_qc2 = (build { 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";
|
||||||
|
|
||||||
|
@ -341,29 +340,29 @@
|
||||||
{
|
{
|
||||||
inherit fastnumbers artiq-netboot ramda migen-axi binutils-arm;
|
inherit fastnumbers artiq-netboot ramda migen-axi binutils-arm;
|
||||||
} //
|
} //
|
||||||
(board-package-set { target = "zc706"; variant = "nist_clock"; }) //
|
(build { target = "zc706"; variant = "nist_clock"; }) //
|
||||||
(board-package-set { target = "zc706"; variant = "nist_clock_master"; }) //
|
(build { target = "zc706"; variant = "nist_clock_master"; }) //
|
||||||
(board-package-set { target = "zc706"; variant = "nist_clock_master_100mhz"; }) //
|
(build { target = "zc706"; variant = "nist_clock_master_100mhz"; }) //
|
||||||
(board-package-set { target = "zc706"; variant = "nist_clock_satellite"; }) //
|
(build { target = "zc706"; variant = "nist_clock_satellite"; }) //
|
||||||
(board-package-set { target = "zc706"; variant = "nist_clock_satellite_100mhz"; }) //
|
(build { target = "zc706"; variant = "nist_clock_satellite_100mhz"; }) //
|
||||||
(board-package-set { target = "zc706"; variant = "nist_qc2"; }) //
|
(build { target = "zc706"; variant = "nist_qc2"; }) //
|
||||||
(board-package-set { target = "zc706"; variant = "nist_qc2_master"; }) //
|
(build { target = "zc706"; variant = "nist_qc2_master"; }) //
|
||||||
(board-package-set { target = "zc706"; variant = "nist_qc2_master_100mhz"; }) //
|
(build { target = "zc706"; variant = "nist_qc2_master_100mhz"; }) //
|
||||||
(board-package-set { target = "zc706"; variant = "nist_qc2_satellite"; }) //
|
(build { target = "zc706"; variant = "nist_qc2_satellite"; }) //
|
||||||
(board-package-set { target = "zc706"; variant = "nist_qc2_satellite_100mhz"; }) //
|
(build { target = "zc706"; variant = "nist_qc2_satellite_100mhz"; }) //
|
||||||
(board-package-set { target = "zc706"; variant = "acpki_nist_clock"; }) //
|
(build { target = "zc706"; variant = "acpki_nist_clock"; }) //
|
||||||
(board-package-set { target = "zc706"; variant = "acpki_nist_clock_master"; }) //
|
(build { target = "zc706"; variant = "acpki_nist_clock_master"; }) //
|
||||||
(board-package-set { target = "zc706"; variant = "acpki_nist_clock_master_100mhz"; }) //
|
(build { target = "zc706"; variant = "acpki_nist_clock_master_100mhz"; }) //
|
||||||
(board-package-set { target = "zc706"; variant = "acpki_nist_clock_satellite"; }) //
|
(build { target = "zc706"; variant = "acpki_nist_clock_satellite"; }) //
|
||||||
(board-package-set { target = "zc706"; variant = "acpki_nist_clock_satellite_100mhz"; }) //
|
(build { target = "zc706"; variant = "acpki_nist_clock_satellite_100mhz"; }) //
|
||||||
(board-package-set { target = "zc706"; variant = "acpki_nist_qc2"; }) //
|
(build { target = "zc706"; variant = "acpki_nist_qc2"; }) //
|
||||||
(board-package-set { target = "zc706"; variant = "acpki_nist_qc2_master"; }) //
|
(build { target = "zc706"; variant = "acpki_nist_qc2_master"; }) //
|
||||||
(board-package-set { target = "zc706"; variant = "acpki_nist_qc2_master_100mhz"; }) //
|
(build { target = "zc706"; variant = "acpki_nist_qc2_master_100mhz"; }) //
|
||||||
(board-package-set { target = "zc706"; variant = "acpki_nist_qc2_satellite"; }) //
|
(build { target = "zc706"; variant = "acpki_nist_qc2_satellite"; }) //
|
||||||
(board-package-set { target = "zc706"; variant = "acpki_nist_qc2_satellite_100mhz"; }) //
|
(build { target = "zc706"; variant = "acpki_nist_qc2_satellite_100mhz"; }) //
|
||||||
(board-package-set { target = "kasli_soc"; variant = "demo"; json = ./demo.json; }) //
|
(build { target = "kasli_soc"; variant = "demo"; json = ./demo.json; }) //
|
||||||
(board-package-set { target = "kasli_soc"; variant = "master"; json = ./kasli-soc-master.json; }) //
|
(build { target = "kasli_soc"; variant = "master"; json = ./kasli-soc-master.json; }) //
|
||||||
(board-package-set { target = "kasli_soc"; variant = "satellite"; json = ./kasli-soc-satellite.json; });
|
(build { 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; };
|
||||||
|
|
||||||
|
@ -371,8 +370,8 @@
|
||||||
name = "artiq-zynq-dev-shell";
|
name = "artiq-zynq-dev-shell";
|
||||||
buildInputs = with pkgs; [
|
buildInputs = with pkgs; [
|
||||||
rust
|
rust
|
||||||
llvmPackages_11.llvm
|
llvmPackages_9.llvm
|
||||||
llvmPackages_11.clang-unwrapped
|
llvmPackages_9.clang-unwrapped
|
||||||
gnumake
|
gnumake
|
||||||
cacert
|
cacert
|
||||||
zynqpkgs.cargo-xbuild
|
zynqpkgs.cargo-xbuild
|
||||||
|
@ -385,13 +384,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 = "${llvmPackages_11.clang-unwrapped.lib}/lib/clang/11.1.0/include";
|
CLANG_EXTRA_INCLUDE_DIR = "${pkgs.llvmPackages_9.clang-unwrapped.lib}/lib/clang/9.0.1/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 = board-package-set;
|
makeArtiqZynqPackage = build;
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,98 +4,50 @@ from misoc.interconnect.csr import *
|
||||||
|
|
||||||
|
|
||||||
class DDMTDSampler(Module):
|
class DDMTDSampler(Module):
|
||||||
def __init__(self, cd_ref, main_clk_se):
|
def __init__(self, cd_ref, main_dcxo_pads):
|
||||||
self.ref_beating = Signal()
|
self.ref_beating = Signal()
|
||||||
self.main_beating = Signal()
|
self.main_beating = Signal()
|
||||||
|
|
||||||
# # #
|
# # #
|
||||||
|
|
||||||
ref_clk = Signal()
|
main_clk_se = Signal()
|
||||||
|
ref_beating_FF = Signal()
|
||||||
|
main_beating_FF = Signal()
|
||||||
self.specials += [
|
self.specials += [
|
||||||
# ISERDESE2 can only be driven from fabric via IDELAYE2 (see UG471)
|
Instance("IBUFDS",
|
||||||
Instance("IDELAYE2",
|
i_I=main_dcxo_pads.p, i_IB=main_dcxo_pads.n,
|
||||||
p_DELAY_SRC="DATAIN",
|
o_O=main_clk_se),
|
||||||
p_HIGH_PERFORMANCE_MODE="TRUE",
|
# Two back to back FFs are used to prevent metastability
|
||||||
p_REFCLK_FREQUENCY=208.3, # REFCLK frequency from IDELAYCTRL
|
Instance("FD", i_C=ClockSignal("helper"),
|
||||||
p_IDELAY_VALUE=0,
|
i_D=cd_ref.clk, o_Q=ref_beating_FF),
|
||||||
|
Instance("FD", i_C=ClockSignal("helper"),
|
||||||
i_DATAIN=cd_ref.clk,
|
i_D=ref_beating_FF, o_Q=self.ref_beating),
|
||||||
|
Instance("FD", i_C=ClockSignal("helper"),
|
||||||
o_DATAOUT=ref_clk
|
i_D=main_clk_se, o_Q=main_beating_FF),
|
||||||
),
|
Instance("FD", i_C=ClockSignal("helper"),
|
||||||
Instance("ISERDESE2",
|
i_D=main_beating_FF, o_Q=self.main_beating)
|
||||||
p_IOBDELAY="IFD", # use DDLY as input
|
|
||||||
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 DDMTDDeglitcherMedianEdge(Module):
|
class DDMTDDeglitcherFirstEdge(Module):
|
||||||
def __init__(self, counter, input_signal, stable_0_period=100, stable_1_period=100):
|
def __init__(self, input_signal, blind_period=300):
|
||||||
self.tag = Signal(len(counter))
|
|
||||||
self.detect = Signal()
|
self.detect = Signal()
|
||||||
|
rising = Signal()
|
||||||
stable_0_counter = Signal(reset=stable_0_period - 1, max=stable_0_period)
|
input_signal_r = Signal()
|
||||||
stable_1_counter = Signal(reset=stable_1_period - 1, max=stable_1_period)
|
|
||||||
|
|
||||||
# # #
|
# # #
|
||||||
|
|
||||||
# Based on CERN's median edge deglitcher FSM
|
self.sync.helper += [
|
||||||
# https://white-rabbit.web.cern.ch/documents/Precise_time_and_frequency_transfer_in_a_White_Rabbit_network.pdf (p.72)
|
input_signal_r.eq(input_signal),
|
||||||
fsm = ClockDomainsRenamer("helper")(FSM(reset_state="WAIT_STABLE_0"))
|
rising.eq(input_signal & ~input_signal_r)
|
||||||
self.submodules += fsm
|
]
|
||||||
|
|
||||||
fsm.act("WAIT_STABLE_0",
|
blind_counter = Signal(max=blind_period)
|
||||||
If(stable_0_counter != 0,
|
self.sync.helper += [
|
||||||
NextValue(stable_0_counter, stable_0_counter - 1)
|
If(blind_counter != 0, blind_counter.eq(blind_counter - 1)),
|
||||||
).Else(
|
If(input_signal_r, blind_counter.eq(blind_period - 1)),
|
||||||
NextValue(stable_0_counter, stable_0_period - 1),
|
self.detect.eq(rising & (blind_counter == 0))
|
||||||
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):
|
||||||
|
@ -107,13 +59,13 @@ class DDMTD(Module):
|
||||||
|
|
||||||
# # #
|
# # #
|
||||||
|
|
||||||
deglitcher = DDMTDDeglitcherMedianEdge(counter, input_signal)
|
deglitcher = DDMTDDeglitcherFirstEdge(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(deglitcher.tag)
|
self.h_tag.eq(counter)
|
||||||
)
|
)
|
||||||
]
|
]
|
|
@ -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 (max_packet, aux_buffer_count,
|
from artiq.gateware.drtio.aux_controller import Transmitter, Receiver
|
||||||
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*aux_buffer_count)] == 0, tx_sdram_if.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)] == 1, rx_sdram_if.bus.aw)],
|
(lambda a: a[log2_int(max_packet)] == 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*aux_buffer_count)] == 0, tx_sdram_if.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)] == 1, rx_sdram_if.bus.ar)],
|
(lambda a: a[log2_int(max_packet)] == 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*aux_buffer_count
|
return max_packet
|
||||||
|
|
|
@ -20,13 +20,14 @@ 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 = {
|
||||||
|
@ -106,10 +107,9 @@ class GTPBootstrapClock(Module):
|
||||||
|
|
||||||
|
|
||||||
class GenericStandalone(SoCCore):
|
class GenericStandalone(SoCCore):
|
||||||
def __init__(self, description, acpki=False):
|
def __init__(self, description, acpki=False, with_wrpll=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,6 +121,13 @@ 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()
|
||||||
|
@ -135,7 +142,6 @@ 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)
|
||||||
|
@ -145,23 +151,6 @@ 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:
|
||||||
|
@ -218,9 +207,8 @@ class GenericStandalone(SoCCore):
|
||||||
|
|
||||||
|
|
||||||
class GenericMaster(SoCCore):
|
class GenericMaster(SoCCore):
|
||||||
def __init__(self, description, acpki=False):
|
def __init__(self, description, acpki=False, with_wrpll=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
|
||||||
|
@ -271,16 +259,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:
|
||||||
clk_synth = platform.request("cdr_clk_clean_fabric")
|
self.submodules.wrpll_refclk = wrpll.SMAFrequencyMultiplier(platform.request("sma_clkin"))
|
||||||
clk_synth_se = Signal()
|
self.submodules.main_dcxo = si549.Si549(platform.request("ddmtd_main_dcxo_i2c"))
|
||||||
platform.add_period_constraint(clk_synth.p, 8.0)
|
self.submodules.helper_dcxo = si549.Si549(platform.request("ddmtd_helper_dcxo_i2c"))
|
||||||
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_clk_se=clk_synth_se)
|
main_dcxo_pads=platform.request("cdr_clk_clean_fabric"),
|
||||||
|
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
|
||||||
|
@ -428,9 +416,8 @@ class GenericMaster(SoCCore):
|
||||||
|
|
||||||
|
|
||||||
class GenericSatellite(SoCCore):
|
class GenericSatellite(SoCCore):
|
||||||
def __init__(self, description, acpki=False):
|
def __init__(self, description, acpki=False, with_wrpll=False):
|
||||||
clk_freq = description["rtio_frequency"]
|
clk_freq = description["rtio_frequency"]
|
||||||
with_wrpll = description["enable_wrpll"]
|
|
||||||
|
|
||||||
self.acpki = acpki
|
self.acpki = acpki
|
||||||
|
|
||||||
|
@ -583,20 +570,18 @@ class GenericSatellite(SoCCore):
|
||||||
self.config["CLOCK_FREQUENCY"] = int(clk_freq)
|
self.config["CLOCK_FREQUENCY"] = int(clk_freq)
|
||||||
|
|
||||||
if with_wrpll:
|
if with_wrpll:
|
||||||
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 = 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_clk_se=clk_synth_se)
|
main_dcxo_pads=platform.request("cdr_clk_clean_fabric"),
|
||||||
self.submodules.wrpll_skewtester = wrpll.SkewTester(self.rx_synchronizer)
|
helper_dcxo_pads=platform.request("ddmtd_helper_clk"))
|
||||||
self.csr_devices.append("wrpll_skewtester")
|
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
|
||||||
self.config["WRPLL_REF_CLK"] = "GT_CDR"
|
self.config["WRPLL_REF_CLK"] = "GTX_CDR"
|
||||||
else:
|
else:
|
||||||
self.submodules.siphaser = SiPhaser7Series(
|
self.submodules.siphaser = SiPhaser7Series(
|
||||||
si5324_clkin=platform.request("cdr_clk"),
|
si5324_clkin=platform.request("cdr_clk"),
|
||||||
|
@ -635,6 +620,8 @@ 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()
|
||||||
|
@ -652,7 +639,7 @@ def main():
|
||||||
else:
|
else:
|
||||||
raise ValueError("Invalid DRTIO role")
|
raise ValueError("Invalid DRTIO role")
|
||||||
|
|
||||||
soc = cls(description, acpki=args.acpki)
|
soc = cls(description, acpki=args.acpki, with_wrpll=args.with_wrpll)
|
||||||
soc.finalize()
|
soc.finalize()
|
||||||
|
|
||||||
if args.r is not None:
|
if args.r is not None:
|
||||||
|
|
|
@ -0,0 +1,278 @@
|
||||||
|
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),
|
||||||
|
)
|
||||||
|
]
|
|
@ -0,0 +1,185 @@
|
||||||
|
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),
|
||||||
|
]
|
|
@ -10,7 +10,6 @@ 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" }
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
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};
|
||||||
|
@ -57,14 +56,30 @@ 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 read_ptr = (DRTIOAUX[linkidx].aux_read_pointer_read)() as usize;
|
let ptr = (DRTIOAUX_MEM[linkidx].base + DRTIOAUX_MEM[linkidx].size / 2) as *mut u32;
|
||||||
let ptr = (DRTIOAUX_MEM[linkidx].base + DRTIOAUX_MEM[linkidx].size / 2 + read_ptr * 0x400) as *mut u32;
|
let len = (DRTIOAUX[linkidx].aux_rx_length_read)() as usize;
|
||||||
let result = f(slice::from_raw_parts(ptr as *mut u8, 0x400 as usize));
|
// work buffer to accomodate axi burst reads
|
||||||
|
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 {
|
||||||
|
@ -85,15 +100,15 @@ pub fn recv(linkno: u8) -> Result<Option<Packet>, Error> {
|
||||||
|
|
||||||
let mut reader = Cursor::new(buffer);
|
let mut reader = Cursor::new(buffer);
|
||||||
|
|
||||||
let packet = Packet::read_from(&mut reader)?;
|
let checksum_at = buffer.len() - 4;
|
||||||
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);
|
||||||
}
|
}
|
||||||
Ok(packet)
|
reader.set_position(0);
|
||||||
|
|
||||||
|
Ok(Packet::read_from(&mut reader)?)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,7 +130,11 @@ 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 = f(slice::from_raw_parts_mut(ptr as *mut u8, 0x400 as usize))?;
|
let len = DRTIOAUX_MEM[linkno].size / 2;
|
||||||
|
// 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(())
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
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},
|
||||||
|
@ -10,7 +8,7 @@ use nb;
|
||||||
use void::Void;
|
use void::Void;
|
||||||
|
|
||||||
pub use crate::drtioaux_proto::Packet;
|
pub use crate::drtioaux_proto::Packet;
|
||||||
use crate::{drtioaux::{has_rx_error, Error},
|
use crate::{drtioaux::{copy_work_buffer, has_rx_error, Error},
|
||||||
mem::mem::DRTIOAUX_MEM,
|
mem::mem::DRTIOAUX_MEM,
|
||||||
pl::csr::DRTIOAUX};
|
pl::csr::DRTIOAUX};
|
||||||
|
|
||||||
|
@ -40,9 +38,12 @@ 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 read_ptr = (DRTIOAUX[linkidx].aux_read_pointer_read)() as usize;
|
let ptr = (DRTIOAUX_MEM[linkidx].base + DRTIOAUX_MEM[linkidx].size / 2) as *mut u32;
|
||||||
let ptr = (DRTIOAUX_MEM[linkidx].base + DRTIOAUX_MEM[linkidx].size / 2 + read_ptr * 0x400) as *mut u32;
|
let len = (DRTIOAUX[linkidx].aux_rx_length_read)() as usize;
|
||||||
let result = f(slice::from_raw_parts(ptr as *mut u8, 0x400 as usize));
|
// work buffer to accomodate axi burst reads
|
||||||
|
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 {
|
||||||
|
@ -63,15 +64,15 @@ pub async fn recv(linkno: u8) -> Result<Option<Packet>, Error> {
|
||||||
|
|
||||||
let mut reader = Cursor::new(buffer);
|
let mut reader = Cursor::new(buffer);
|
||||||
|
|
||||||
let packet = Packet::read_from(&mut reader)?;
|
let checksum_at = buffer.len() - 4;
|
||||||
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);
|
||||||
}
|
}
|
||||||
Ok(packet)
|
reader.set_position(0);
|
||||||
|
|
||||||
|
Ok(Packet::read_from(&mut reader)?)
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
@ -102,7 +103,11 @@ 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 = f(slice::from_raw_parts_mut(ptr as *mut u8, 0x400 as usize))?;
|
let len = DRTIOAUX_MEM[linkno].size / 2;
|
||||||
|
// 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(())
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
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*/MAX_PACKET - /*CRC*/4 - /*packet ID*/1 - /*last*/1 - /*length*/2;
|
pub const SAT_PAYLOAD_MAX_SIZE: usize = /*max size*/512 - /*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;
|
||||||
|
|
||||||
|
@ -91,6 +89,8 @@ pub enum Packet {
|
||||||
RoutingSetRank {
|
RoutingSetRank {
|
||||||
rank: u8,
|
rank: u8,
|
||||||
},
|
},
|
||||||
|
RoutingRetrievePackets,
|
||||||
|
RoutingNoPackets,
|
||||||
RoutingAck,
|
RoutingAck,
|
||||||
|
|
||||||
MonitorRequest {
|
MonitorRequest {
|
||||||
|
@ -325,6 +325,8 @@ 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()?,
|
||||||
|
@ -600,6 +602,8 @@ 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,
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
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.
|
||||||
|
@ -38,7 +37,6 @@ 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],
|
||||||
|
@ -48,18 +46,17 @@ 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(all(hw_rev = "v1.0", has_virtual_leds))]
|
#[cfg(hw_rev = "v1.0")]
|
||||||
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(all(hw_rev = "v1.1", has_virtual_leds))]
|
#[cfg(hw_rev = "v1.1")]
|
||||||
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],
|
||||||
|
@ -73,7 +70,6 @@ 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],
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
#![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;
|
||||||
|
@ -21,8 +19,7 @@ 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;
|
||||||
pub mod fiq;
|
#[cfg(all(feature = "target_kasli_soc", has_drtio))]
|
||||||
#[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)]
|
||||||
|
|
|
@ -7,16 +7,17 @@ use crate::pl::csr;
|
||||||
#[cfg(feature = "target_kasli_soc")]
|
#[cfg(feature = "target_kasli_soc")]
|
||||||
const ADDRESS: u8 = 0x67;
|
const ADDRESS: u8 = 0x67;
|
||||||
|
|
||||||
const ADPLL_MAX: i32 = (950.0 / 0.0001164) as i32;
|
#[derive(Clone, Copy)]
|
||||||
|
|
||||||
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,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,6 +27,7 @@ mod i2c {
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub enum DCXO {
|
pub enum DCXO {
|
||||||
Main,
|
Main,
|
||||||
|
#[cfg(has_wrpll)]
|
||||||
Helper,
|
Helper,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,40 +37,45 @@ mod i2c {
|
||||||
|
|
||||||
fn sda_i(dcxo: DCXO) -> bool {
|
fn sda_i(dcxo: DCXO) -> bool {
|
||||||
match dcxo {
|
match dcxo {
|
||||||
DCXO::Main => unsafe { csr::wrpll::main_dcxo_sda_in_read() == 1 },
|
DCXO::Main => unsafe { csr::main_dcxo::sda_in_read() == 1 },
|
||||||
DCXO::Helper => unsafe { csr::wrpll::helper_dcxo_sda_in_read() == 1 },
|
#[cfg(has_wrpll)]
|
||||||
|
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::wrpll::main_dcxo_sda_oe_write(val) },
|
DCXO::Main => unsafe { csr::main_dcxo::sda_oe_write(val) },
|
||||||
DCXO::Helper => unsafe { csr::wrpll::helper_dcxo_sda_oe_write(val) },
|
#[cfg(has_wrpll)]
|
||||||
|
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::wrpll::main_dcxo_sda_out_write(val) },
|
DCXO::Main => unsafe { csr::main_dcxo::sda_out_write(val) },
|
||||||
DCXO::Helper => unsafe { csr::wrpll::helper_dcxo_sda_out_write(val) },
|
#[cfg(has_wrpll)]
|
||||||
|
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::wrpll::main_dcxo_scl_oe_write(val) },
|
DCXO::Main => unsafe { csr::main_dcxo::scl_oe_write(val) },
|
||||||
DCXO::Helper => unsafe { csr::wrpll::helper_dcxo_scl_oe_write(val) },
|
#[cfg(has_wrpll)]
|
||||||
|
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::wrpll::main_dcxo_scl_out_write(val) },
|
DCXO::Main => unsafe { csr::main_dcxo::scl_out_write(val) },
|
||||||
DCXO::Helper => unsafe { csr::wrpll::helper_dcxo_scl_out_write(val) },
|
#[cfg(has_wrpll)]
|
||||||
|
DCXO::Helper => unsafe { csr::helper_dcxo::scl_out_write(val) },
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -212,7 +219,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
|
||||||
|
@ -245,137 +252,47 @@ fn setup(dcxo: i2c::DCXO, config: &DividerConfig, timer: &mut GlobalTimer) -> Re
|
||||||
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::wrpll::main_dcxo_bitbang_enable_write(1);
|
csr::main_dcxo::bitbang_enable_write(1);
|
||||||
csr::wrpll::main_dcxo_i2c_address_write(ADDRESS);
|
csr::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::wrpll::main_dcxo_bitbang_enable_write(0);
|
csr::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 BEATING_PERIOD: i32 = 0x8000;
|
const TIMER_WIDTH: u32 = 24;
|
||||||
const BEATING_HALFPERIOD: i32 = 0x4000;
|
const COUNTER_DIV: u32 = 2;
|
||||||
const COUNTER_WIDTH: u32 = 24;
|
|
||||||
const DIV_WIDTH: u32 = 2;
|
|
||||||
|
|
||||||
// y[n] = b0*x[n] + b1*x[n-1] + b2*x[n-2] - a1*y[n-1] - a2*y[n-2]
|
const ADPLL_MAX: i32 = (950.0 / 0.0001164) as i32;
|
||||||
struct FilterParameters {
|
|
||||||
pub b0: f64,
|
|
||||||
pub b1: f64,
|
|
||||||
pub b2: f64,
|
|
||||||
pub a1: f64,
|
|
||||||
pub a2: f64,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(rtio_frequency = "100.0")]
|
const KP: i32 = 6;
|
||||||
const LPF: FilterParameters = FilterParameters {
|
const KI: i32 = 2;
|
||||||
b0: 0.03967479060647884,
|
|
||||||
b1: 0.07934958121295768,
|
|
||||||
b2: 0.03967479060647884,
|
|
||||||
a1: -1.3865593741228928,
|
|
||||||
a2: 0.5452585365488082,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[cfg(rtio_frequency = "125.0")]
|
static BASE_ADPLL: Mutex<i32> = Mutex::new(0);
|
||||||
const LPF: FilterParameters = FilterParameters {
|
static H_INTEGRATOR: Mutex<i32> = Mutex::new(0);
|
||||||
b0: 0.07209205036273991,
|
static M_INTEGRATOR: Mutex<i32> = Mutex::new(0);
|
||||||
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 ISR {
|
pub enum FIQ {
|
||||||
RefTag,
|
RefTag,
|
||||||
MainTag,
|
MainTag,
|
||||||
}
|
}
|
||||||
|
@ -383,62 +300,46 @@ pub mod wrpll {
|
||||||
mod tag_collector {
|
mod tag_collector {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[cfg(wrpll_ref_clk = "GT_CDR")]
|
const BEATING_PERIOD: i32 = 0x8000;
|
||||||
static mut TAG_OFFSET: u32 = 8382;
|
const BEATING_HALFPERIOD: i32 = 0x4000;
|
||||||
#[cfg(wrpll_ref_clk = "SMA_CLKIN")]
|
|
||||||
static mut TAG_OFFSET: u32 = 0;
|
static REF_TAG: Mutex<u32> = Mutex::new(0);
|
||||||
static mut REF_TAG: u32 = 0;
|
static REF_TAG_READY: Mutex<bool> = Mutex::new(false);
|
||||||
static mut REF_TAG_READY: bool = false;
|
static MAIN_TAG: Mutex<u32> = Mutex::new(0);
|
||||||
static mut MAIN_TAG: u32 = 0;
|
static MAIN_TAG_READY: Mutex<bool> = Mutex::new(false);
|
||||||
static mut MAIN_TAG_READY: bool = false;
|
|
||||||
|
|
||||||
pub fn reset() {
|
pub fn reset() {
|
||||||
clear_phase_diff_ready();
|
clear_phase_diff_ready();
|
||||||
unsafe {
|
*REF_TAG.lock() = 0;
|
||||||
REF_TAG = 0;
|
*MAIN_TAG.lock() = 0;
|
||||||
MAIN_TAG = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clear_phase_diff_ready() {
|
pub fn clear_phase_diff_ready() {
|
||||||
unsafe {
|
*REF_TAG_READY.lock() = false;
|
||||||
REF_TAG_READY = false;
|
*MAIN_TAG_READY.lock() = false;
|
||||||
MAIN_TAG_READY = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn collect_tags(interrupt: ISR) {
|
pub fn collect_tags(interrupt: FIQ) {
|
||||||
match interrupt {
|
match interrupt {
|
||||||
ISR::RefTag => unsafe {
|
FIQ::RefTag => {
|
||||||
REF_TAG = csr::wrpll::ref_tag_read();
|
*REF_TAG.lock() = unsafe { csr::wrpll::ref_tag_read() };
|
||||||
REF_TAG_READY = true;
|
*REF_TAG_READY.lock() = true;
|
||||||
},
|
}
|
||||||
ISR::MainTag => unsafe {
|
FIQ::MainTag => {
|
||||||
MAIN_TAG = csr::wrpll::main_tag_read();
|
*MAIN_TAG.lock() = unsafe { csr::wrpll::main_tag_read() };
|
||||||
MAIN_TAG_READY = true;
|
*MAIN_TAG_READY.lock() = true;
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn phase_diff_ready() -> bool {
|
pub fn phase_diff_ready() -> bool {
|
||||||
unsafe { REF_TAG_READY && MAIN_TAG_READY }
|
*REF_TAG_READY.lock() && *MAIN_TAG_READY.lock()
|
||||||
}
|
|
||||||
|
|
||||||
#[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 = unsafe { REF_TAG.overflowing_neg().0.rem_euclid(BEATING_PERIOD as u32) as i32 };
|
let mut period_error = (*REF_TAG.lock()).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
|
||||||
|
@ -447,13 +348,11 @@ pub mod wrpll {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_phase_error() -> i32 {
|
pub fn get_phase_error() -> i32 {
|
||||||
// MAIN_TAG(n) - REF_TAG(n) - TAG_OFFSET mod BEATING_PERIOD
|
// MAIN_TAG(n) - REF_TAG(n) mod BEATING_PERIOD
|
||||||
let mut phase_error = unsafe {
|
let mut phase_error = (*MAIN_TAG.lock())
|
||||||
MAIN_TAG
|
.overflowing_sub(*REF_TAG.lock())
|
||||||
.overflowing_sub(REF_TAG + TAG_OFFSET)
|
|
||||||
.0
|
.0
|
||||||
.rem_euclid(BEATING_PERIOD as u32) as i32
|
.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 {
|
||||||
|
@ -463,7 +362,29 @@ pub mod wrpll {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_isr(en: bool) {
|
pub fn helper_setup(timer: &mut GlobalTimer, settings: FrequencySetting) -> Result<(), &'static str> {
|
||||||
|
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);
|
||||||
|
@ -471,24 +392,71 @@ pub mod wrpll {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_base_adpll() -> Result<(), &'static str> {
|
/// set adpll using gateware i2c
|
||||||
let count2adpll =
|
/// Note: disable main/helper i2c bitbang before using this function
|
||||||
|error: i32| ((error as f64 * 1e6) / (0.0001164 * (1 << (COUNTER_WIDTH - DIV_WIDTH)) as f64)) as i32;
|
fn set_adpll(dcxo: i2c::DCXO, adpll: i32) -> Result<(), &'static str> {
|
||||||
|
if adpll.abs() > ADPLL_MAX {
|
||||||
let (ref_count, main_count) = get_freq_counts();
|
return Err("adpll is too large");
|
||||||
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)?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_freq_counts() -> (u32, u32) {
|
/// To get within capture range
|
||||||
|
fn set_base_adpll(timer: &mut GlobalTimer) -> Result<(), &'static str> {
|
||||||
|
let count2adpll =
|
||||||
|
|error: i32| (((error) as f64 * 1e6) / (0.0001164 * (1 << (TIMER_WIDTH - COUNTER_DIV)) 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)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_freq_counts(timer: &mut GlobalTimer) -> (u32, u32) {
|
||||||
unsafe {
|
unsafe {
|
||||||
csr::wrpll::frequency_counter_update_write(1);
|
csr::wrpll::frequency_counter_update_en_write(1);
|
||||||
while csr::wrpll::frequency_counter_busy_read() == 1 {}
|
timer.delay_us(150_000); // 8ns << TIMER_WIDTH
|
||||||
#[cfg(wrpll_ref_clk = "GT_CDR")]
|
csr::wrpll::frequency_counter_update_en_write(0);
|
||||||
|
#[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();
|
||||||
|
@ -498,48 +466,39 @@ pub mod wrpll {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reset_plls(timer: &mut GlobalTimer) -> Result<(), &'static str> {
|
fn reset_plls() -> Result<(), &'static str> {
|
||||||
unsafe {
|
*H_INTEGRATOR.lock() = 0;
|
||||||
H_ADPLL1 = 0;
|
*M_INTEGRATOR.lock() = 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: ISR) {
|
fn clear_pending(interrupt: FIQ) {
|
||||||
match interrupt {
|
match interrupt {
|
||||||
ISR::RefTag => unsafe { csr::wrpll::ref_tag_ev_pending_write(1) },
|
FIQ::RefTag => unsafe { csr::wrpll::ref_tag_ev_pending_write(1) },
|
||||||
ISR::MainTag => unsafe { csr::wrpll::main_tag_ev_pending_write(1) },
|
FIQ::MainTag => unsafe { csr::wrpll::main_tag_ev_pending_write(1) },
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_pending(interrupt: ISR) -> bool {
|
fn is_pending(interrupt: FIQ) -> bool {
|
||||||
match interrupt {
|
match interrupt {
|
||||||
ISR::RefTag => unsafe { csr::wrpll::ref_tag_ev_pending_read() == 1 },
|
FIQ::RefTag => unsafe { csr::wrpll::ref_tag_ev_pending_read() == 1 },
|
||||||
ISR::MainTag => unsafe { csr::wrpll::main_tag_ev_pending_read() == 1 },
|
FIQ::MainTag => unsafe { csr::wrpll::main_tag_ev_pending_read() == 1 },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn interrupt_handler() {
|
pub fn interrupt_handler() {
|
||||||
if is_pending(ISR::RefTag) {
|
if is_pending(FIQ::RefTag) {
|
||||||
tag_collector::collect_tags(ISR::RefTag);
|
tag_collector::collect_tags(FIQ::RefTag);
|
||||||
clear_pending(ISR::RefTag);
|
clear_pending(FIQ::RefTag);
|
||||||
|
|
||||||
helper_pll().expect("failed to run helper DCXO PLL");
|
helper_pll().expect("failed to run helper DCXO PLL");
|
||||||
}
|
}
|
||||||
|
|
||||||
if is_pending(ISR::MainTag) {
|
if is_pending(FIQ::MainTag) {
|
||||||
tag_collector::collect_tags(ISR::MainTag);
|
tag_collector::collect_tags(FIQ::MainTag);
|
||||||
clear_pending(ISR::MainTag);
|
clear_pending(FIQ::MainTag);
|
||||||
}
|
}
|
||||||
|
|
||||||
if tag_collector::phase_diff_ready() {
|
if tag_collector::phase_diff_ready() {
|
||||||
|
@ -549,165 +508,125 @@ 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();
|
||||||
unsafe {
|
let mut integrator_lock = H_INTEGRATOR.lock();
|
||||||
let adpll = ((LPF.b0 * period_err as f64) + (LPF.b1 * PERIOD_ERR1 as f64) + (LPF.b2 * PERIOD_ERR2 as f64)
|
|
||||||
- (LPF.a1 * H_ADPLL1 as f64)
|
*integrator_lock += period_err * KI;
|
||||||
- (LPF.a2 * H_ADPLL2 as f64)) as i32;
|
let mut h_adpll = *BASE_ADPLL.lock() + period_err * KP + *integrator_lock;
|
||||||
set_adpll(i2c::DCXO::Helper, BASE_ADPLL + adpll)?;
|
|
||||||
H_ADPLL2 = H_ADPLL1;
|
h_adpll = h_adpll.clamp(-ADPLL_MAX, ADPLL_MAX);
|
||||||
PERIOD_ERR2 = PERIOD_ERR1;
|
set_adpll(i2c::DCXO::Helper, h_adpll)?;
|
||||||
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 {
|
||||||
let adpll = ((LPF.b0 * phase_err as f64) + (LPF.b1 * PHASE_ERR1 as f64) + (LPF.b2 * PHASE_ERR2 as f64)
|
if ERR_ARR[COUNTER] == 0 {
|
||||||
- (LPF.a1 * M_ADPLL1 as f64)
|
FIN_ADPLL = m_adpll;
|
||||||
- (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_isr(false);
|
set_fiq(false);
|
||||||
|
|
||||||
if rc {
|
if rc {
|
||||||
tag_collector::reset();
|
tag_collector::reset();
|
||||||
reset_plls(timer).expect("failed to reset main and helper PLL");
|
reset_plls().expect("failed to reset main and helper PLL");
|
||||||
|
|
||||||
// get within capture range
|
info!("warming up refclk...");
|
||||||
set_base_adpll().expect("failed to set base adpll");
|
// refclk need a couple seconds for freq counter to read it properly
|
||||||
|
// 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(ISR::RefTag);
|
clear_pending(FIQ::RefTag);
|
||||||
clear_pending(ISR::MainTag);
|
clear_pending(FIQ::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_isr(true);
|
set_fiq(true);
|
||||||
info!("WRPLL interrupt enabled");
|
info!("WRPLL interrupt enabled");
|
||||||
|
|
||||||
#[cfg(feature = "calibrate_wrpll_skew")]
|
timer.delay_ms(500);
|
||||||
calibrate_skew(timer).expect("failed to set the correct skew");
|
unsafe {
|
||||||
|
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());
|
||||||
|
|
||||||
#[cfg(wrpll_ref_clk = "GT_CDR")]
|
// loop {
|
||||||
test_skew(timer).expect("skew test failed");
|
// if is_pending(FIQ::RefTag) {
|
||||||
|
// 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);
|
||||||
|
// }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -730,10 +649,12 @@ pub mod wrpll_refclk {
|
||||||
pub filt_reg2: u16, //0x4F
|
pub filt_reg2: u16, //0x4F
|
||||||
}
|
}
|
||||||
|
|
||||||
fn one_clock_cycle() {
|
fn one_clock_cycle(timer: &mut GlobalTimer) {
|
||||||
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -771,34 +692,33 @@ pub mod wrpll_refclk {
|
||||||
unsafe { csr::wrpll_refclk::mmcm_dready_read() == 1 }
|
unsafe { csr::wrpll_refclk::mmcm_dready_read() == 1 }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
fn read(timer: &mut GlobalTimer, address: u8) -> u16 {
|
||||||
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();
|
one_clock_cycle(timer);
|
||||||
|
|
||||||
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();
|
one_clock_cycle(timer);
|
||||||
}
|
}
|
||||||
get_data()
|
get_data()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write(address: u8, value: u16) {
|
fn write(timer: &mut GlobalTimer, 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();
|
one_clock_cycle(timer);
|
||||||
|
|
||||||
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();
|
one_clock_cycle(timer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -809,31 +729,22 @@ pub mod wrpll_refclk {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setup(timer: &mut GlobalTimer, settings: MmcmSetting, mmcm_bypass: bool) -> Result<(), &'static str> {
|
pub fn setup(timer: &mut GlobalTimer, settings: MmcmSetting) -> Result<(), &'static str> {
|
||||||
unsafe {
|
|
||||||
csr::wrpll_refclk::refclk_reset_write(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if mmcm_bypass {
|
|
||||||
info!("Bypassing mmcm");
|
|
||||||
unsafe {
|
|
||||||
csr::wrpll_refclk::mmcm_bypass_write(1);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Based on "DRP State Machine" from XAPP888
|
// Based on "DRP State Machine" from XAPP888
|
||||||
|
|
||||||
// hold reset HIGH during mmcm config
|
// hold reset HIGH during mmcm config
|
||||||
reset(true);
|
reset(true);
|
||||||
write(0x08, settings.clkout0_reg1);
|
write(timer, 0x08, settings.clkout0_reg1);
|
||||||
write(0x09, settings.clkout0_reg2);
|
write(timer, 0x09, settings.clkout0_reg2);
|
||||||
write(0x14, settings.clkfbout_reg1);
|
write(timer, 0x14, settings.clkfbout_reg1);
|
||||||
write(0x15, settings.clkfbout_reg2);
|
write(timer, 0x15, settings.clkfbout_reg2);
|
||||||
write(0x16, settings.div_reg);
|
write(timer, 0x16, settings.div_reg);
|
||||||
write(0x18, settings.lock_reg1);
|
write(timer, 0x18, settings.lock_reg1);
|
||||||
write(0x19, settings.lock_reg2);
|
write(timer, 0x19, settings.lock_reg2);
|
||||||
write(0x1A, settings.lock_reg3);
|
write(timer, 0x1A, settings.lock_reg3);
|
||||||
write(0x28, settings.power_reg);
|
write(timer, 0x28, settings.power_reg);
|
||||||
write(0x4E, settings.filt_reg1);
|
write(timer, 0x4E, settings.filt_reg1);
|
||||||
write(0x4F, settings.filt_reg2);
|
write(timer, 0x4F, settings.filt_reg2);
|
||||||
reset(false);
|
reset(false);
|
||||||
|
|
||||||
// wait for the mmcm to lock
|
// wait for the mmcm to lock
|
||||||
|
@ -841,13 +752,26 @@ pub mod wrpll_refclk {
|
||||||
|
|
||||||
let locked = unsafe { csr::wrpll_refclk::mmcm_locked_read() == 1 };
|
let locked = unsafe { csr::wrpll_refclk::mmcm_locked_read() == 1 };
|
||||||
if !locked {
|
if !locked {
|
||||||
return Err("mmcm failed to generate 125MHz ref clock from SMA CLKIN");
|
return Err("failed to generate 125Mhz ref clock from SMA CLKIN");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe {
|
// const TIMER_WIDTH: u32 = 24;
|
||||||
csr::wrpll_refclk::refclk_reset_write(0);
|
// const COUNTER_DIV: u32 = 2;
|
||||||
}
|
|
||||||
|
// let (ref_count, main_count) = wrpll::get_freq_counts(timer);
|
||||||
|
|
||||||
|
// let f_sys = 125e6;
|
||||||
|
|
||||||
|
// info!(
|
||||||
|
// "ref counter = {} freq = {}",
|
||||||
|
// 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(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,9 +10,7 @@ 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
|
||||||
|
|
|
@ -45,10 +45,7 @@ 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());
|
||||||
// ``copy_from_slice`` generates AXI bursts, use a regular loop instead
|
buf[..len].copy_from_slice(&data[..len]);
|
||||||
for i in 0..len {
|
|
||||||
buf[i] = data[i];
|
|
||||||
}
|
|
||||||
self.pos += len;
|
self.pos += len;
|
||||||
Ok(len)
|
Ok(len)
|
||||||
}
|
}
|
||||||
|
@ -58,9 +55,7 @@ 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());
|
||||||
for i in 0..len {
|
data[..len].copy_from_slice(&buf[..len]);
|
||||||
data[i] = buf[i];
|
|
||||||
}
|
|
||||||
self.pos += len;
|
self.pos += len;
|
||||||
Ok(len)
|
Ok(len)
|
||||||
}
|
}
|
||||||
|
@ -73,6 +68,7 @@ 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())
|
||||||
|
|
|
@ -1,15 +1,14 @@
|
||||||
|
#[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, {
|
||||||
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_si549)]
|
#[cfg(has_wrpll)]
|
||||||
si549::wrpll::interrupt_handler();
|
si549::wrpll::interrupt_handler();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
|
@ -21,6 +21,7 @@ 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;
|
||||||
|
|
|
@ -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, drtio::Error> {
|
) -> Result<RemoteBuffer, &'static str> {
|
||||||
// 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;
|
||||||
|
|
|
@ -8,20 +8,20 @@
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
#[cfg(all(feature = "target_kasli_soc", has_virtual_leds))]
|
#[cfg(all(feature = "target_kasli_soc", has_drtio))]
|
||||||
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(feature = "target_kasli_soc")]
|
#[cfg(all(feature = "target_kasli_soc", has_drtio))]
|
||||||
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::{exception_vectors, ram};
|
use libsupport_zynq::ram;
|
||||||
use log::{info, warn};
|
use log::{info, warn};
|
||||||
|
|
||||||
mod analyzer;
|
mod analyzer;
|
||||||
|
@ -38,12 +38,7 @@ mod rtio_mgt;
|
||||||
#[cfg(has_drtio)]
|
#[cfg(has_drtio)]
|
||||||
mod subkernel;
|
mod subkernel;
|
||||||
|
|
||||||
// linker symbols
|
#[cfg(all(feature = "target_kasli_soc", has_drtio))]
|
||||||
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>,
|
||||||
|
@ -82,9 +77,6 @@ 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();
|
||||||
|
|
||||||
|
@ -101,7 +93,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(feature = "target_kasli_soc")]
|
#[cfg(all(feature = "target_kasli_soc", has_drtio))]
|
||||||
{
|
{
|
||||||
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();
|
||||||
|
@ -124,7 +116,6 @@ 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),
|
||||||
|
|
|
@ -58,11 +58,10 @@ mod remote_moninj {
|
||||||
use log::error;
|
use log::error;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::rtio_mgt::{drtio, drtio::Error as DrtioError};
|
use crate::rtio_mgt::drtio;
|
||||||
|
|
||||||
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,
|
||||||
|
@ -72,7 +71,6 @@ 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 _,
|
||||||
|
@ -84,8 +82,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(DrtioError::LinkDown) => {
|
Err("link went down") => {
|
||||||
warn!("link is down");
|
debug!("link is down");
|
||||||
}
|
}
|
||||||
Err(e) => error!("aux packet error ({})", e),
|
Err(e) => error!("aux packet error ({})", e),
|
||||||
}
|
}
|
||||||
|
@ -94,7 +92,6 @@ 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,
|
||||||
|
@ -118,7 +115,6 @@ 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,
|
||||||
|
@ -128,7 +124,6 @@ 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 _,
|
||||||
|
@ -140,8 +135,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(DrtioError::LinkDown) => {
|
Err("link went down") => {
|
||||||
warn!("link is down");
|
debug!("link is down");
|
||||||
}
|
}
|
||||||
Err(e) => error!("aux packet error ({})", e),
|
Err(e) => error!("aux packet error ({})", e),
|
||||||
}
|
}
|
||||||
|
@ -188,7 +183,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, $routing_table, $timer, linkno, destination, channel, $($param, )*).await
|
remote_moninj::$func($aux_mutex, $timer, linkno, destination, channel, $($param, )*).await
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,8 @@ 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;
|
||||||
|
@ -262,13 +264,10 @@ 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(all(has_si549, has_wrpll))]
|
#[cfg(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) {
|
||||||
// register values are directly copied from preconfigured mmcm
|
let mmcm_setting = match clk {
|
||||||
let (mmcm_setting, mmcm_bypass) = match clk {
|
RtioClock::Ext0_Synth0_10to125 => si549::wrpll_refclk::MmcmSetting {
|
||||||
RtioClock::Ext0_Synth0_10to125 => (
|
|
||||||
si549::wrpll_refclk::MmcmSetting {
|
|
||||||
// CLKFBOUT_MULT = 62.5, DIVCLK_DIVIDE = 1 , CLKOUT0_DIVIDE = 5
|
|
||||||
clkout0_reg1: 0x1083,
|
clkout0_reg1: 0x1083,
|
||||||
clkout0_reg2: 0x0080,
|
clkout0_reg2: 0x0080,
|
||||||
clkfbout_reg1: 0x179e,
|
clkfbout_reg1: 0x179e,
|
||||||
|
@ -278,14 +277,10 @@ fn wrpll_setup(timer: &mut GlobalTimer, clk: RtioClock, si549_settings: &si549::
|
||||||
lock_reg2: 0x7c01,
|
lock_reg2: 0x7c01,
|
||||||
lock_reg3: 0xffe9,
|
lock_reg3: 0xffe9,
|
||||||
power_reg: 0x9900,
|
power_reg: 0x9900,
|
||||||
filt_reg1: 0x1008,
|
filt_reg1: 0x0808,
|
||||||
filt_reg2: 0x8800,
|
filt_reg2: 0x0800,
|
||||||
},
|
},
|
||||||
false,
|
RtioClock::Ext0_Synth0_80to125 => si549::wrpll_refclk::MmcmSetting {
|
||||||
),
|
|
||||||
RtioClock::Ext0_Synth0_80to125 => (
|
|
||||||
si549::wrpll_refclk::MmcmSetting {
|
|
||||||
// CLKFBOUT_MULT = 15.625, DIVCLK_DIVIDE = 1 , CLKOUT0_DIVIDE = 10
|
|
||||||
clkout0_reg1: 0x1145,
|
clkout0_reg1: 0x1145,
|
||||||
clkout0_reg2: 0x0000,
|
clkout0_reg2: 0x0000,
|
||||||
clkfbout_reg1: 0x11c7,
|
clkfbout_reg1: 0x11c7,
|
||||||
|
@ -295,14 +290,10 @@ fn wrpll_setup(timer: &mut GlobalTimer, clk: RtioClock, si549_settings: &si549::
|
||||||
lock_reg2: 0x7c01,
|
lock_reg2: 0x7c01,
|
||||||
lock_reg3: 0xffe9,
|
lock_reg3: 0xffe9,
|
||||||
power_reg: 0x9900,
|
power_reg: 0x9900,
|
||||||
filt_reg1: 0x9908,
|
filt_reg1: 0x0808,
|
||||||
filt_reg2: 0x8100,
|
filt_reg2: 0x9800,
|
||||||
},
|
},
|
||||||
false,
|
RtioClock::Ext0_Synth0_100to125 => si549::wrpll_refclk::MmcmSetting {
|
||||||
),
|
|
||||||
RtioClock::Ext0_Synth0_100to125 => (
|
|
||||||
si549::wrpll_refclk::MmcmSetting {
|
|
||||||
// CLKFBOUT_MULT = 12.5, DIVCLK_DIVIDE = 1 , CLKOUT0_DIVIDE = 10
|
|
||||||
clkout0_reg1: 0x1145,
|
clkout0_reg1: 0x1145,
|
||||||
clkout0_reg2: 0x0000,
|
clkout0_reg2: 0x0000,
|
||||||
clkfbout_reg1: 0x1145,
|
clkfbout_reg1: 0x1145,
|
||||||
|
@ -312,14 +303,10 @@ fn wrpll_setup(timer: &mut GlobalTimer, clk: RtioClock, si549_settings: &si549::
|
||||||
lock_reg2: 0x7c01,
|
lock_reg2: 0x7c01,
|
||||||
lock_reg3: 0xffe9,
|
lock_reg3: 0xffe9,
|
||||||
power_reg: 0x9900,
|
power_reg: 0x9900,
|
||||||
filt_reg1: 0x9108,
|
filt_reg1: 0x0808,
|
||||||
filt_reg2: 0x0100,
|
filt_reg2: 0x9800,
|
||||||
},
|
},
|
||||||
false,
|
RtioClock::Ext0_Synth0_125to125 => si549::wrpll_refclk::MmcmSetting {
|
||||||
),
|
|
||||||
RtioClock::Ext0_Synth0_125to125 => (
|
|
||||||
si549::wrpll_refclk::MmcmSetting {
|
|
||||||
// CLKFBOUT_MULT = 10, DIVCLK_DIVIDE = 1 , CLKOUT0_DIVIDE = 10
|
|
||||||
clkout0_reg1: 0x1145,
|
clkout0_reg1: 0x1145,
|
||||||
clkout0_reg2: 0x0000,
|
clkout0_reg2: 0x0000,
|
||||||
clkfbout_reg1: 0x1145,
|
clkfbout_reg1: 0x1145,
|
||||||
|
@ -329,20 +316,19 @@ fn wrpll_setup(timer: &mut GlobalTimer, clk: RtioClock, si549_settings: &si549::
|
||||||
lock_reg2: 0x7001,
|
lock_reg2: 0x7001,
|
||||||
lock_reg3: 0xf3e9,
|
lock_reg3: 0xf3e9,
|
||||||
power_reg: 0x0100,
|
power_reg: 0x0100,
|
||||||
filt_reg1: 0x9908,
|
filt_reg1: 0x0808,
|
||||||
filt_reg2: 0x1100,
|
filt_reg2: 0x1100,
|
||||||
},
|
},
|
||||||
true,
|
|
||||||
),
|
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
si549::helper_setup(timer, &si549_settings).expect("cannot initialize helper Si549");
|
si549::main_setup(timer, si549_settings).expect("cannot initialize main Si549");
|
||||||
si549::wrpll_refclk::setup(timer, mmcm_setting, mmcm_bypass).expect("cannot initialize ref clk for wrpll");
|
si549::wrpll::helper_setup(timer, si549_settings).expect("cannot initialize helper Si549");
|
||||||
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 => {
|
||||||
|
@ -357,6 +343,9 @@ 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");
|
||||||
}
|
}
|
||||||
|
@ -379,8 +368,9 @@ 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,
|
||||||
|
@ -388,15 +378,16 @@ 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,
|
||||||
|
@ -421,10 +412,22 @@ 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);
|
||||||
|
|
||||||
#[cfg(has_si549)]
|
match clk {
|
||||||
si549::main_setup(timer, &si549_settings).expect("cannot initialize main Si549");
|
RtioClock::Ext0_Synth0_10to125
|
||||||
|
| 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);
|
||||||
|
@ -432,17 +435,8 @@ pub fn init(timer: &mut GlobalTimer, cfg: &Config) {
|
||||||
#[cfg(not(has_drtio))]
|
#[cfg(not(has_drtio))]
|
||||||
init_rtio(timer);
|
init_rtio(timer);
|
||||||
|
|
||||||
#[cfg(all(has_si549, has_wrpll))]
|
// no error here :v hmmm...
|
||||||
{
|
// !! sys clock need to switch for freq_counter to work properly
|
||||||
// SYS CLK switch will reset CSRs that are used by WRPLL
|
// !! helper reset after sys clock switch :V -> not ddmtd at all
|
||||||
match clk {
|
si549::wrpll::select_recovered_clock(true, timer);
|
||||||
RtioClock::Ext0_Synth0_10to125
|
|
||||||
| RtioClock::Ext0_Synth0_80to125
|
|
||||||
| RtioClock::Ext0_Synth0_100to125
|
|
||||||
| RtioClock::Ext0_Synth0_125to125 => {
|
|
||||||
wrpll_setup(timer, clk, &si549_settings);
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,20 +1,19 @@
|
||||||
use alloc::rc::Rc;
|
use alloc::rc::Rc;
|
||||||
use core::cell::RefCell;
|
use core::cell::RefCell;
|
||||||
|
|
||||||
use libboard_artiq::{drtio_routing, drtio_routing::RoutingTable, pl::csr};
|
use libboard_artiq::{drtio_routing, 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 as DrtioError,
|
use libboard_artiq::{drtioaux::Error,
|
||||||
drtioaux_async,
|
drtioaux_async,
|
||||||
drtioaux_async::Packet,
|
drtioaux_async::Packet,
|
||||||
drtioaux_proto::{PayloadStatus, MASTER_PAYLOAD_MAX_SIZE}};
|
drtioaux_proto::{PayloadStatus, MASTER_PAYLOAD_MAX_SIZE}};
|
||||||
|
@ -24,44 +23,9 @@ 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<RoutingTable>>,
|
routing_table: &Rc<RefCell<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,
|
||||||
) {
|
) {
|
||||||
|
@ -79,7 +43,26 @@ pub mod drtio {
|
||||||
unsafe { (csr::DRTIO[linkno].rx_up_read)() == 1 }
|
unsafe { (csr::DRTIO[linkno].rx_up_read)() == 1 }
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn process_async_packets(linkno: u8, routing_table: &RoutingTable, packet: Packet) -> Option<Packet> {
|
async fn link_has_async_ready(linkno: u8) -> bool {
|
||||||
|
let linkno = linkno as usize;
|
||||||
|
let async_ready;
|
||||||
|
unsafe {
|
||||||
|
async_ready = (csr::DRTIO[linkno].async_messages_ready_read)() == 1;
|
||||||
|
(csr::DRTIO[linkno].async_messages_ready_write)(1);
|
||||||
|
}
|
||||||
|
async_ready
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn process_async_packets(
|
||||||
|
aux_mutex: &Mutex<bool>,
|
||||||
|
linkno: u8,
|
||||||
|
routing_table: &drtio_routing::RoutingTable,
|
||||||
|
timer: GlobalTimer,
|
||||||
|
) {
|
||||||
|
if link_has_async_ready(linkno).await {
|
||||||
|
loop {
|
||||||
|
let reply = aux_transact(aux_mutex, linkno, &Packet::RoutingRetrievePackets, timer).await;
|
||||||
|
if let Ok(packet) = reply {
|
||||||
match packet {
|
match packet {
|
||||||
Packet::DmaPlaybackStatus {
|
Packet::DmaPlaybackStatus {
|
||||||
id,
|
id,
|
||||||
|
@ -90,7 +73,6 @@ pub mod drtio {
|
||||||
timestamp,
|
timestamp,
|
||||||
} => {
|
} => {
|
||||||
remote_dma::playback_done(id, source, error, channel, timestamp).await;
|
remote_dma::playback_done(id, source, error, channel, timestamp).await;
|
||||||
None
|
|
||||||
}
|
}
|
||||||
Packet::SubkernelFinished {
|
Packet::SubkernelFinished {
|
||||||
id,
|
id,
|
||||||
|
@ -99,7 +81,6 @@ pub mod drtio {
|
||||||
exception_src,
|
exception_src,
|
||||||
} => {
|
} => {
|
||||||
subkernel::subkernel_finished(id, with_exception, exception_src).await;
|
subkernel::subkernel_finished(id, with_exception, exception_src).await;
|
||||||
None
|
|
||||||
}
|
}
|
||||||
Packet::SubkernelMessage {
|
Packet::SubkernelMessage {
|
||||||
id,
|
id,
|
||||||
|
@ -111,10 +92,13 @@ pub mod drtio {
|
||||||
} => {
|
} => {
|
||||||
subkernel::message_handle_incoming(id, status, length as usize, &data).await;
|
subkernel::message_handle_incoming(id, status, length as usize, &data).await;
|
||||||
// acknowledge receiving part of the message
|
// acknowledge receiving part of the message
|
||||||
|
let _lock = aux_mutex.async_lock().await;
|
||||||
drtioaux_async::send(linkno, &Packet::SubkernelMessageAck { destination: source })
|
drtioaux_async::send(linkno, &Packet::SubkernelMessageAck { destination: source })
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
None
|
let mut countdown = timer.countdown();
|
||||||
|
// give the satellites some time to process
|
||||||
|
delay(&mut countdown, Milliseconds(10)).await;
|
||||||
}
|
}
|
||||||
// routable packets
|
// routable packets
|
||||||
Packet::DmaAddTraceRequest { destination, .. }
|
Packet::DmaAddTraceRequest { destination, .. }
|
||||||
|
@ -129,54 +113,58 @@ pub mod drtio {
|
||||||
| Packet::SubkernelMessageAck { destination, .. }
|
| Packet::SubkernelMessageAck { destination, .. }
|
||||||
| Packet::DmaPlaybackStatus { destination, .. }
|
| Packet::DmaPlaybackStatus { destination, .. }
|
||||||
| Packet::SubkernelFinished { destination, .. } => {
|
| Packet::SubkernelFinished { destination, .. } => {
|
||||||
if destination == 0 {
|
|
||||||
Some(packet)
|
|
||||||
} else {
|
|
||||||
let dest_link = routing_table.0[destination as usize][0] - 1;
|
let dest_link = routing_table.0[destination as usize][0] - 1;
|
||||||
if dest_link == linkno {
|
if dest_link == linkno {
|
||||||
warn!(
|
warn!(
|
||||||
"[LINK#{}] Re-routed packet would return to the same link, dropping: {:?}",
|
"[LINK#{}] Re-routed packet would return to the same link, dropping: {:?}",
|
||||||
linkno, packet
|
linkno, packet
|
||||||
);
|
);
|
||||||
|
} else if destination == 0 {
|
||||||
|
warn!("[LINK#{}] Received invalid routable packet: {:?}", linkno, packet)
|
||||||
} else {
|
} else {
|
||||||
drtioaux_async::send(dest_link, &packet).await.unwrap();
|
drtioaux_async::send(dest_link, &packet).await.unwrap();
|
||||||
}
|
}
|
||||||
None
|
}
|
||||||
|
|
||||||
|
Packet::RoutingNoPackets => break,
|
||||||
|
|
||||||
|
other => warn!("[LINK#{}] Received an unroutable packet: {:?}", linkno, other),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
warn!(
|
||||||
|
"[LINK#{}] Error handling async packets ({})",
|
||||||
|
linkno,
|
||||||
|
reply.unwrap_err()
|
||||||
|
);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
other => Some(other),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn recv_aux_timeout(linkno: u8, timeout: u64, timer: GlobalTimer) -> Result<Packet, Error> {
|
async fn recv_aux_timeout(linkno: u8, timeout: u64, timer: GlobalTimer) -> Result<Packet, &'static str> {
|
||||||
if !link_rx_up(linkno).await {
|
if !link_rx_up(linkno).await {
|
||||||
return Err(Error::LinkDown);
|
return Err("link went down");
|
||||||
}
|
}
|
||||||
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(DrtioError::TimedOut) => return Err(Error::Timeout),
|
Err(Error::TimedOut) => return Err("timed out"),
|
||||||
Err(_) => return Err(Error::AuxError),
|
Err(_) => return Err("aux packet error"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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, Error> {
|
) -> Result<Packet, &'static str> {
|
||||||
if !link_rx_up(linkno).await {
|
if !link_rx_up(linkno).await {
|
||||||
return Err(Error::LinkDown);
|
return Err("link went down");
|
||||||
}
|
}
|
||||||
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();
|
||||||
loop {
|
Ok(recv_aux_timeout(linkno, 200, timer).await?)
|
||||||
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) {
|
||||||
|
@ -184,17 +172,12 @@ 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(
|
async fn ping_remote(aux_mutex: &Rc<Mutex<bool>>, linkno: u8, timer: GlobalTimer) -> u32 {
|
||||||
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 {
|
||||||
|
@ -204,7 +187,7 @@ pub mod drtio {
|
||||||
if count > 100 {
|
if count > 100 {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
let reply = aux_transact(aux_mutex, linkno, routing_table, &Packet::EchoRequest, timer).await;
|
let reply = aux_transact(aux_mutex, linkno, &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
|
||||||
|
@ -217,7 +200,7 @@ pub mod drtio {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn sync_tsc(aux_mutex: &Rc<Mutex<bool>>, linkno: u8, timer: GlobalTimer) -> Result<(), Error> {
|
async fn sync_tsc(aux_mutex: &Rc<Mutex<bool>>, linkno: u8, timer: GlobalTimer) -> Result<(), &'static str> {
|
||||||
let _lock = aux_mutex.async_lock().await;
|
let _lock = aux_mutex.async_lock().await;
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -228,23 +211,22 @@ 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 {
|
||||||
Ok(())
|
return Ok(());
|
||||||
} else {
|
} else {
|
||||||
Err(Error::UnexpectedReply)
|
return Err("unexpected reply");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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: &RoutingTable,
|
routing_table: &drtio_routing::RoutingTable,
|
||||||
timer: GlobalTimer,
|
timer: GlobalTimer,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), &'static str> {
|
||||||
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],
|
||||||
|
@ -253,7 +235,7 @@ pub mod drtio {
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
if reply != Packet::RoutingAck {
|
if reply != Packet::RoutingAck {
|
||||||
return Err(Error::UnexpectedReply);
|
return Err("unexpected reply");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -263,21 +245,13 @@ 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<(), Error> {
|
) -> Result<(), &'static str> {
|
||||||
let reply = aux_transact(
|
let reply = aux_transact(aux_mutex, linkno, &Packet::RoutingSetRank { rank: rank }, timer).await?;
|
||||||
aux_mutex,
|
if reply != Packet::RoutingAck {
|
||||||
linkno,
|
return Err("unexpected reply");
|
||||||
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) {
|
||||||
|
@ -296,14 +270,10 @@ pub mod drtio {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn process_unsolicited_aux(aux_mutex: &Mutex<bool>, linkno: u8, routing_table: &RoutingTable) {
|
async fn process_unsolicited_aux(aux_mutex: &Rc<Mutex<bool>>, linkno: u8) {
|
||||||
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)) => {
|
Ok(Some(packet)) => warn!("[LINK#{}] unsolicited aux packet: {:?}", linkno, 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),
|
||||||
}
|
}
|
||||||
|
@ -331,7 +301,7 @@ pub mod drtio {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn destination_set_up(
|
async fn destination_set_up(
|
||||||
routing_table: &RoutingTable,
|
routing_table: &drtio_routing::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,
|
||||||
|
@ -354,7 +324,7 @@ pub mod drtio {
|
||||||
|
|
||||||
async fn destination_survey(
|
async fn destination_survey(
|
||||||
aux_mutex: &Rc<Mutex<bool>>,
|
aux_mutex: &Rc<Mutex<bool>>,
|
||||||
routing_table: &RoutingTable,
|
routing_table: &drtio_routing::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,
|
||||||
|
@ -375,7 +345,6 @@ 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,
|
||||||
},
|
},
|
||||||
|
@ -431,7 +400,6 @@ 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,
|
||||||
},
|
},
|
||||||
|
@ -459,7 +427,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: &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,
|
||||||
) {
|
) {
|
||||||
|
@ -470,7 +438,8 @@ 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_unsolicited_aux(aux_mutex, linkno, routing_table).await;
|
process_async_packets(aux_mutex, linkno, routing_table, timer).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);
|
||||||
|
@ -480,7 +449,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, routing_table, timer).await;
|
let ping_count = ping_remote(aux_mutex, linkno, 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;
|
||||||
|
@ -490,7 +459,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, routing_table, timer).await {
|
if let Err(e) = set_rank(aux_mutex, linkno, 1 as u8, 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);
|
||||||
|
@ -507,7 +476,7 @@ pub mod drtio {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn reset(aux_mutex: Rc<Mutex<bool>>, routing_table: &RoutingTable, mut timer: GlobalTimer) {
|
pub fn reset(aux_mutex: Rc<Mutex<bool>>, 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);
|
||||||
|
@ -523,13 +492,7 @@ 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(
|
let reply = task::block_on(aux_transact(&aux_mutex, linkno, &Packet::ResetRequest, timer));
|
||||||
&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),
|
||||||
|
@ -542,15 +505,14 @@ 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<(), Error>
|
) -> Result<(), &'static str>
|
||||||
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<(), Error>,
|
HandlerF: Fn(&Packet) -> Result<(), &'static str>,
|
||||||
{
|
{
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
while i < data.len() {
|
while i < data.len() {
|
||||||
|
@ -566,7 +528,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, routing_table, &packet, timer).await?;
|
let reply = aux_transact(aux_mutex, linkno, &packet, timer).await?;
|
||||||
reply_handler_f(&reply)?;
|
reply_handler_f(&reply)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -574,17 +536,16 @@ 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: &RoutingTable,
|
routing_table: &drtio_routing::RoutingTable,
|
||||||
timer: GlobalTimer,
|
timer: GlobalTimer,
|
||||||
id: u32,
|
id: u32,
|
||||||
destination: u8,
|
destination: u8,
|
||||||
trace: &Vec<u8>,
|
trace: &Vec<u8>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), &'static str> {
|
||||||
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 {
|
||||||
|
@ -605,8 +566,8 @@ pub mod drtio {
|
||||||
destination: 0,
|
destination: 0,
|
||||||
succeeded: false,
|
succeeded: false,
|
||||||
..
|
..
|
||||||
} => Err(Error::DmaAddTraceFail(destination)),
|
} => Err("error adding trace on satellite"),
|
||||||
_ => Err(Error::UnexpectedReply),
|
_ => Err("adding DMA trace failed, unexpected aux packet"),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
|
@ -614,16 +575,15 @@ 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: &RoutingTable,
|
routing_table: &drtio_routing::RoutingTable,
|
||||||
timer: GlobalTimer,
|
timer: GlobalTimer,
|
||||||
id: u32,
|
id: u32,
|
||||||
destination: u8,
|
destination: u8,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), &'static str> {
|
||||||
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,
|
||||||
|
@ -631,33 +591,33 @@ pub mod drtio {
|
||||||
},
|
},
|
||||||
timer,
|
timer,
|
||||||
)
|
)
|
||||||
.await?;
|
.await;
|
||||||
match reply {
|
match reply {
|
||||||
Packet::DmaRemoveTraceReply {
|
Ok(Packet::DmaRemoveTraceReply {
|
||||||
destination: 0,
|
destination: 0,
|
||||||
succeeded: true,
|
succeeded: true,
|
||||||
} => Ok(()),
|
}) => Ok(()),
|
||||||
Packet::DmaRemoveTraceReply {
|
Ok(Packet::DmaRemoveTraceReply {
|
||||||
destination: 0,
|
destination: 0,
|
||||||
succeeded: false,
|
succeeded: false,
|
||||||
} => Err(Error::DmaEraseFail(destination)),
|
}) => Err("satellite DMA erase error"),
|
||||||
_ => Err(Error::UnexpectedReply),
|
Ok(_) => Err("adding trace failed, unexpected aux packet"),
|
||||||
|
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: &RoutingTable,
|
routing_table: &drtio_routing::RoutingTable,
|
||||||
timer: GlobalTimer,
|
timer: GlobalTimer,
|
||||||
id: u32,
|
id: u32,
|
||||||
destination: u8,
|
destination: u8,
|
||||||
timestamp: u64,
|
timestamp: u64,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), &'static str> {
|
||||||
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,
|
||||||
|
@ -666,44 +626,45 @@ pub mod drtio {
|
||||||
},
|
},
|
||||||
timer,
|
timer,
|
||||||
)
|
)
|
||||||
.await?;
|
.await;
|
||||||
match reply {
|
match reply {
|
||||||
Packet::DmaPlaybackReply {
|
Ok(Packet::DmaPlaybackReply {
|
||||||
destination: 0,
|
destination: 0,
|
||||||
succeeded: true,
|
succeeded: true,
|
||||||
} => Ok(()),
|
}) => Ok(()),
|
||||||
Packet::DmaPlaybackReply {
|
Ok(Packet::DmaPlaybackReply {
|
||||||
destination: 0,
|
destination: 0,
|
||||||
succeeded: false,
|
succeeded: false,
|
||||||
} => Err(Error::DmaPlaybackFail(destination)),
|
}) => Err("error on DMA playback request"),
|
||||||
_ => Err(Error::UnexpectedReply),
|
Ok(_) => Err("received unexpected aux packet during DMA playback"),
|
||||||
|
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: &RoutingTable,
|
routing_table: &drtio_routing::RoutingTable,
|
||||||
timer: GlobalTimer,
|
timer: GlobalTimer,
|
||||||
destination: u8,
|
destination: u8,
|
||||||
) -> Result<RemoteBuffer, Error> {
|
) -> Result<RemoteBuffer, &'static str> {
|
||||||
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 {
|
||||||
Packet::AnalyzerHeader {
|
Ok(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),
|
||||||
_ => return Err(Error::UnexpectedReply),
|
Ok(_) => return Err("received unexpected aux packet during remote analyzer header request"),
|
||||||
|
Err(e) => return Err(e),
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut remote_data: Vec<u8> = Vec::new();
|
let mut remote_data: Vec<u8> = Vec::new();
|
||||||
|
@ -713,19 +674,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 {
|
||||||
Packet::AnalyzerData { last, length, data } => {
|
Ok(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]);
|
||||||
}
|
}
|
||||||
_ => return Err(Error::UnexpectedReply),
|
Ok(_) => return Err("received unexpected aux packet during remote analyzer data request"),
|
||||||
|
Err(e) => return Err(e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -740,10 +701,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: &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<Vec<RemoteBuffer>, Error> {
|
) -> Result<Vec<RemoteBuffer>, &'static str> {
|
||||||
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 {
|
||||||
|
@ -755,17 +716,16 @@ 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: &RoutingTable,
|
routing_table: &drtio_routing::RoutingTable,
|
||||||
timer: GlobalTimer,
|
timer: GlobalTimer,
|
||||||
id: u32,
|
id: u32,
|
||||||
destination: u8,
|
destination: u8,
|
||||||
data: &Vec<u8>,
|
data: &Vec<u8>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), &'static str> {
|
||||||
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 {
|
||||||
|
@ -777,8 +737,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::SubkernelAddFail(destination)),
|
Packet::SubkernelAddDataReply { succeeded: false } => Err("error adding subkernel on satellite"),
|
||||||
_ => Err(Error::UnexpectedReply),
|
_ => Err("adding subkernel failed, unexpected aux packet"),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
|
@ -786,17 +746,16 @@ 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: &RoutingTable,
|
routing_table: &drtio_routing::RoutingTable,
|
||||||
timer: GlobalTimer,
|
timer: GlobalTimer,
|
||||||
id: u32,
|
id: u32,
|
||||||
destination: u8,
|
destination: u8,
|
||||||
run: bool,
|
run: bool,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), &'static str> {
|
||||||
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,
|
||||||
|
@ -814,24 +773,23 @@ pub mod drtio {
|
||||||
Packet::SubkernelLoadRunReply {
|
Packet::SubkernelLoadRunReply {
|
||||||
destination: 0,
|
destination: 0,
|
||||||
succeeded: false,
|
succeeded: false,
|
||||||
} => return Err(Error::SubkernelRunFail(destination)),
|
} => return Err("error on subkernel run request"),
|
||||||
_ => Err(Error::UnexpectedReply),
|
_ => return Err("received unexpected aux packet during subkernel run"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn subkernel_retrieve_exception(
|
pub async fn subkernel_retrieve_exception(
|
||||||
aux_mutex: &Rc<Mutex<bool>>,
|
aux_mutex: &Rc<Mutex<bool>>,
|
||||||
routing_table: &RoutingTable,
|
routing_table: &drtio_routing::RoutingTable,
|
||||||
timer: GlobalTimer,
|
timer: GlobalTimer,
|
||||||
destination: u8,
|
destination: u8,
|
||||||
) -> Result<Vec<u8>, Error> {
|
) -> Result<Vec<u8>, &'static str> {
|
||||||
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,
|
||||||
},
|
},
|
||||||
|
@ -845,24 +803,23 @@ pub mod drtio {
|
||||||
return Ok(remote_data);
|
return Ok(remote_data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => return Err(Error::UnexpectedReply),
|
_ => return Err("received unexpected aux packet during subkernel exception request"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn subkernel_send_message(
|
pub async fn subkernel_send_message(
|
||||||
aux_mutex: &Rc<Mutex<bool>>,
|
aux_mutex: &Rc<Mutex<bool>>,
|
||||||
routing_table: &RoutingTable,
|
routing_table: &drtio_routing::RoutingTable,
|
||||||
timer: GlobalTimer,
|
timer: GlobalTimer,
|
||||||
id: u32,
|
id: u32,
|
||||||
destination: u8,
|
destination: u8,
|
||||||
message: &[u8],
|
message: &[u8],
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), &'static str> {
|
||||||
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 {
|
||||||
|
@ -875,7 +832,7 @@ pub mod drtio {
|
||||||
},
|
},
|
||||||
|reply| match reply {
|
|reply| match reply {
|
||||||
Packet::SubkernelMessageAck { .. } => Ok(()),
|
Packet::SubkernelMessageAck { .. } => Ok(()),
|
||||||
_ => Err(Error::UnexpectedReply),
|
_ => Err("sending message to subkernel failed, unexpected aux packet"),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
|
@ -888,19 +845,19 @@ pub mod drtio {
|
||||||
|
|
||||||
pub fn startup(
|
pub fn startup(
|
||||||
_aux_mutex: &Rc<Mutex<bool>>,
|
_aux_mutex: &Rc<Mutex<bool>>,
|
||||||
_routing_table: &Rc<RefCell<RoutingTable>>,
|
_routing_table: &Rc<RefCell<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,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn reset(_aux_mutex: Rc<Mutex<bool>>, _routing_table: &RoutingTable, mut _timer: GlobalTimer) {}
|
pub fn reset(_aux_mutex: Rc<Mutex<bool>>, mut _timer: GlobalTimer) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn startup(
|
pub fn startup(
|
||||||
aux_mutex: &Rc<Mutex<bool>>,
|
aux_mutex: &Rc<Mutex<bool>>,
|
||||||
routing_table: &Rc<RefCell<RoutingTable>>,
|
routing_table: &Rc<RefCell<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,
|
||||||
) {
|
) {
|
||||||
|
@ -911,9 +868,9 @@ pub fn startup(
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn reset(aux_mutex: Rc<Mutex<bool>>, routing_table: &RoutingTable, timer: GlobalTimer) {
|
pub fn reset(aux_mutex: Rc<Mutex<bool>>, timer: GlobalTimer) {
|
||||||
unsafe {
|
unsafe {
|
||||||
csr::rtio_core::reset_write(1);
|
csr::rtio_core::reset_write(1);
|
||||||
}
|
}
|
||||||
drtio::reset(aux_mutex, routing_table, timer)
|
drtio::reset(aux_mutex, timer)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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, drtio::Error as DrtioError};
|
use crate::rtio_mgt::drtio;
|
||||||
|
|
||||||
#[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(DrtioError),
|
DrtioError(&'static str),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<DrtioError> for Error {
|
impl From<&'static str> for Error {
|
||||||
fn from(value: DrtioError) -> Error {
|
fn from(value: &'static str) -> Error {
|
||||||
Error::DrtioError(value)
|
Error::DrtioError(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,6 @@ 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]
|
||||||
|
|
|
@ -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::{exception_vectors, ram};
|
use libsupport_zynq::ram;
|
||||||
use routing::Router;
|
use routing::Router;
|
||||||
use subkernel::Manager as KernelManager;
|
use subkernel::Manager as KernelManager;
|
||||||
|
|
||||||
|
@ -50,11 +50,6 @@ 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 });
|
||||||
|
@ -81,6 +76,12 @@ 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) => {{
|
||||||
|
@ -239,6 +240,14 @@ 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,
|
||||||
|
@ -823,8 +832,9 @@ 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,
|
||||||
|
@ -832,14 +842,15 @@ const SI549_SETTINGS: si549::FrequencySetting = si549::FrequencySetting {
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(all(has_si549, rtio_frequency = "100.0"))]
|
#[cfg(all(has_si549, rtio_frequency = "100.0"))]
|
||||||
const SI549_SETTINGS: si549::FrequencySetting = si549::FrequencySetting {
|
pub 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,
|
||||||
|
@ -850,9 +861,6 @@ 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();
|
||||||
|
@ -899,7 +907,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...");
|
||||||
|
@ -917,8 +925,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_si549)]
|
#[cfg(has_wrpll)]
|
||||||
si549::helper_setup(&mut timer, &SI549_SETTINGS).expect("cannot initialize helper Si549");
|
si549::wrpll::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()];
|
||||||
|
@ -1053,8 +1061,8 @@ pub extern "C" fn main_core0() -> i32 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(packet) = router.get_upstream_packet() {
|
if router.any_upstream_waiting() {
|
||||||
drtioaux::send(0, &packet).unwrap();
|
drtiosat_async_ready();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -119,11 +119,16 @@ impl Repeater {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
RepeaterState::Up => {
|
RepeaterState::Up => {
|
||||||
self.process_unsolicited_aux(routing_table, rank, destination, router);
|
self.process_unsolicited_aux();
|
||||||
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) {
|
||||||
|
@ -134,15 +139,9 @@ impl Repeater {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_unsolicited_aux(
|
fn process_unsolicited_aux(&self) {
|
||||||
&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)) => router.route(packet, routing_table, rank, destination),
|
Ok(Some(packet)) => warn!("[REP#{}] unsolicited aux packet: {:?}", self.repno, packet),
|
||||||
Ok(None) => (),
|
Ok(None) => (),
|
||||||
Err(_) => warn!("[REP#{}] aux packet error", self.repno),
|
Err(_) => warn!("[REP#{}] aux packet error", self.repno),
|
||||||
}
|
}
|
||||||
|
@ -187,6 +186,34 @@ 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 {
|
||||||
|
|
|
@ -75,6 +75,7 @@ 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 {
|
||||||
|
@ -84,6 +85,7 @@ 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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -159,8 +161,22 @@ 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> {
|
||||||
self.upstream_queue.pop_front()
|
let packet = self.upstream_queue.pop_front();
|
||||||
|
if packet.is_none() {
|
||||||
|
self.upstream_notified = false;
|
||||||
|
}
|
||||||
|
packet
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(has_drtio_routing)]
|
#[cfg(has_drtio_routing)]
|
||||||
|
|
Loading…
Reference in New Issue