forked from M-Labs/artiq-zynq
Compare commits
No commits in common. "586fd2f17e53634f265681b024768751fc02c766" and "c261897658098f70bf18c10aab9b8ad9f941db53" have entirely different histories.
586fd2f17e
...
c261897658
48
flake.lock
48
flake.lock
|
@ -11,11 +11,11 @@
|
||||||
"src-pythonparser": "src-pythonparser"
|
"src-pythonparser": "src-pythonparser"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1716972728,
|
"lastModified": 1714013217,
|
||||||
"narHash": "sha256-88J+eckZamtwhcCQkPpKLu6R1hmgj5+C9n2U5i+sHUE=",
|
"narHash": "sha256-P0pVHTSgAkTYWFPjddcPhufe5oH8mjJAsxG8x8mo4NA=",
|
||||||
"ref": "refs/heads/master",
|
"ref": "master",
|
||||||
"rev": "49e402780bebba437c6098047ab1dc68eaf5a17c",
|
"rev": "7204feae1f504e4a1dcd54b95c59e8f36c62b701",
|
||||||
"revCount": 8808,
|
"revCount": 8776,
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/m-labs/artiq.git"
|
"url": "https://github.com/m-labs/artiq.git"
|
||||||
},
|
},
|
||||||
|
@ -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": 1711668574,
|
||||||
"narHash": "sha256-0Y9fRr0CUqWT4KgBITmaGwlnNIGMYuydu2L8iLTfHU4=",
|
"narHash": "sha256-u1dfs0ASQIEr1icTVrsKwg2xToIpn7ZXxW3RHfHxshg=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "d12251ef6e8e6a46e05689eeccd595bdbd3c9e60",
|
"rev": "219951b495fc2eac67b1456824cc1ec1fd2ee659",
|
||||||
"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"
|
||||||
}
|
}
|
||||||
|
@ -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": 1711358419,
|
||||||
"narHash": "sha256-vgKBJCQRPCutJ4n+FtJNczMZULWW7J3B8icf/PUothw=",
|
"narHash": "sha256-LzetYaLsnov9pHVWSCTSowXUAXkxemAa61CIMY98xsc=",
|
||||||
"ref": "refs/heads/master",
|
"ref": "master",
|
||||||
"rev": "46dc25b89e46b9043129d77e3c9348916748e325",
|
"rev": "195a21fe78e4dde1fd705cb2899ab5d2763ae037",
|
||||||
"revCount": 645,
|
"revCount": 643,
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://git.m-labs.hk/m-labs/zynq-rs"
|
"url": "https://git.m-labs.hk/m-labs/zynq-rs"
|
||||||
},
|
},
|
||||||
|
|
13
flake.nix
13
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;
|
||||||
|
@ -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}
|
||||||
|
@ -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,7 +384,7 @@
|
||||||
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}";
|
||||||
|
|
|
@ -20,13 +20,13 @@ from artiq.gateware.drtio.transceiver import gtx_7series, eem_serdes
|
||||||
from artiq.gateware.drtio.siphaser import SiPhaser7Series
|
from artiq.gateware.drtio.siphaser import SiPhaser7Series
|
||||||
from artiq.gateware.drtio.rx_synchronizer import XilinxRXSynchronizer
|
from artiq.gateware.drtio.rx_synchronizer import XilinxRXSynchronizer
|
||||||
from artiq.gateware.drtio import *
|
from artiq.gateware.drtio import *
|
||||||
from artiq.gateware.wrpll import wrpll
|
|
||||||
|
|
||||||
import dma
|
import dma
|
||||||
import analyzer
|
import analyzer
|
||||||
import acpki
|
import acpki
|
||||||
import drtio_aux_controller
|
import drtio_aux_controller
|
||||||
import zynq_clocking
|
import zynq_clocking
|
||||||
|
import wrpll
|
||||||
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 = {
|
||||||
|
@ -135,7 +135,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)
|
||||||
|
@ -146,7 +145,7 @@ class GenericStandalone(SoCCore):
|
||||||
self.crg.cd_sys = self.sys_crg.cd_sys
|
self.crg.cd_sys = self.sys_crg.cd_sys
|
||||||
|
|
||||||
if with_wrpll:
|
if with_wrpll:
|
||||||
self.submodules.wrpll_refclk = wrpll.FrequencyMultiplier(platform.request("sma_clkin"))
|
self.submodules.wrpll_refclk = wrpll.SMAFrequencyMultiplier(platform.request("sma_clkin"))
|
||||||
self.submodules.wrpll = wrpll.WRPLL(
|
self.submodules.wrpll = wrpll.WRPLL(
|
||||||
platform=self.platform,
|
platform=self.platform,
|
||||||
cd_ref=self.wrpll_refclk.cd_ref,
|
cd_ref=self.wrpll_refclk.cd_ref,
|
||||||
|
@ -243,7 +242,6 @@ class GenericMaster(SoCCore):
|
||||||
pads=data_pads,
|
pads=data_pads,
|
||||||
clk_freq=clk_freq)
|
clk_freq=clk_freq)
|
||||||
self.csr_devices.append("gt_drtio")
|
self.csr_devices.append("gt_drtio")
|
||||||
self.config["RTIO_FREQUENCY"] = str(clk_freq/1e6)
|
|
||||||
self.config["CLOCK_FREQUENCY"] = int(clk_freq)
|
self.config["CLOCK_FREQUENCY"] = int(clk_freq)
|
||||||
|
|
||||||
txout_buf = Signal()
|
txout_buf = Signal()
|
||||||
|
@ -275,7 +273,7 @@ class GenericMaster(SoCCore):
|
||||||
clk_synth_se = Signal()
|
clk_synth_se = Signal()
|
||||||
platform.add_period_constraint(clk_synth.p, 8.0)
|
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.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_refclk = wrpll.SMAFrequencyMultiplier(platform.request("sma_clkin"))
|
||||||
self.submodules.wrpll = wrpll.WRPLL(
|
self.submodules.wrpll = wrpll.WRPLL(
|
||||||
platform=self.platform,
|
platform=self.platform,
|
||||||
cd_ref=self.wrpll_refclk.cd_ref,
|
cd_ref=self.wrpll_refclk.cd_ref,
|
||||||
|
|
|
@ -0,0 +1,277 @@
|
||||||
|
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
|
||||||
|
|
||||||
|
fsm.act("IDLE",
|
||||||
|
If(self.stb,
|
||||||
|
NextValue(self.nack, 0),
|
||||||
|
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(
|
||||||
|
NextValue(self.nack, 1),
|
||||||
|
NextState("STOP")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
fsm.act("DATA0",
|
||||||
|
master.data.eq(self.adpll[0:8]),
|
||||||
|
master.write.eq(1),
|
||||||
|
If(master.ready,
|
||||||
|
If(master.ack,
|
||||||
|
NextState("DATA1")
|
||||||
|
).Else(
|
||||||
|
NextValue(self.nack, 1),
|
||||||
|
NextState("STOP")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
fsm.act("DATA1",
|
||||||
|
master.data.eq(self.adpll[8:16]),
|
||||||
|
master.write.eq(1),
|
||||||
|
If(master.ready,
|
||||||
|
If(master.ack,
|
||||||
|
NextState("DATA2")
|
||||||
|
).Else(
|
||||||
|
NextValue(self.nack, 1),
|
||||||
|
NextState("STOP")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
fsm.act("DATA2",
|
||||||
|
master.data.eq(self.adpll[16:24]),
|
||||||
|
master.write.eq(1),
|
||||||
|
If(master.ready,
|
||||||
|
If(~master.ack, NextValue(self.nack, 1)),
|
||||||
|
NextState("STOP")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
fsm.act("STOP",
|
||||||
|
master.stop.eq(1),
|
||||||
|
If(master.ready,
|
||||||
|
If(~master.ack, NextValue(self.nack, 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 = CSR()
|
||||||
|
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.sync += self.programmer.stb.eq(self.adpll_stb.re)
|
||||||
|
|
||||||
|
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.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,237 @@
|
||||||
|
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
|
||||||
|
from si549 import Si549
|
||||||
|
|
||||||
|
class FrequencyCounter(Module, AutoCSR):
|
||||||
|
def __init__(self, domains, counter_width=24):
|
||||||
|
self.update = CSR()
|
||||||
|
self.busy = CSRStatus()
|
||||||
|
|
||||||
|
counter_reset = Signal()
|
||||||
|
counter_stb = Signal()
|
||||||
|
timer = Signal(counter_width)
|
||||||
|
|
||||||
|
# # #
|
||||||
|
|
||||||
|
fsm = FSM()
|
||||||
|
self.submodules += fsm
|
||||||
|
|
||||||
|
fsm.act("IDLE",
|
||||||
|
counter_reset.eq(1),
|
||||||
|
If(self.update.re,
|
||||||
|
NextValue(timer, 2**counter_width - 1),
|
||||||
|
NextState("COUNTING")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
fsm.act("COUNTING",
|
||||||
|
self.busy.status.eq(1),
|
||||||
|
If(timer != 0,
|
||||||
|
NextValue(timer, timer - 1)
|
||||||
|
).Else(
|
||||||
|
counter_stb.eq(1),
|
||||||
|
NextState("IDLE")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
for domain in domains:
|
||||||
|
name = "counter_" + domain
|
||||||
|
counter_csr = CSRStatus(counter_width, name=name)
|
||||||
|
setattr(self, name, counter_csr)
|
||||||
|
|
||||||
|
divider = Signal(2)
|
||||||
|
divided = Signal()
|
||||||
|
divided_sys = Signal()
|
||||||
|
divided_sys_r = Signal()
|
||||||
|
divided_tick = Signal()
|
||||||
|
counter = Signal(counter_width)
|
||||||
|
|
||||||
|
# # #
|
||||||
|
|
||||||
|
sync_domain = getattr(self.sync, domain)
|
||||||
|
sync_domain +=[
|
||||||
|
divider.eq(divider + 1),
|
||||||
|
divided.eq(divider[-1])
|
||||||
|
]
|
||||||
|
self.specials += MultiReg(divided, divided_sys)
|
||||||
|
self.sync += divided_sys_r.eq(divided_sys)
|
||||||
|
self.comb += divided_tick.eq(divided_sys & ~divided_sys_r)
|
||||||
|
|
||||||
|
self.sync += [
|
||||||
|
If(counter_stb, counter_csr.status.eq(counter)),
|
||||||
|
If(divided_tick, counter.eq(counter + 1)),
|
||||||
|
If(counter_reset, counter.eq(0))
|
||||||
|
]
|
||||||
|
|
||||||
|
class SkewTester(Module, AutoCSR):
|
||||||
|
def __init__(self, rx_synchronizer):
|
||||||
|
self.error = CSR()
|
||||||
|
|
||||||
|
# # #
|
||||||
|
|
||||||
|
# The RX synchronizer is tested for setup/hold violations by feeding it a
|
||||||
|
# toggling pattern and checking that the same toggling pattern comes out.
|
||||||
|
toggle_in = Signal()
|
||||||
|
self.sync.rtio_rx0 += toggle_in.eq(~toggle_in)
|
||||||
|
toggle_out = rx_synchronizer.resync(toggle_in)
|
||||||
|
|
||||||
|
toggle_out_expected = Signal()
|
||||||
|
self.sync += toggle_out_expected.eq(~toggle_out)
|
||||||
|
|
||||||
|
error = Signal()
|
||||||
|
self.sync += [
|
||||||
|
If(toggle_out != toggle_out_expected, error.eq(1)),
|
||||||
|
If(self.error.re, error.eq(0))
|
||||||
|
]
|
||||||
|
self.specials += MultiReg(error, self.error.w)
|
||||||
|
|
||||||
|
|
||||||
|
class WRPLL(Module, AutoCSR):
|
||||||
|
def __init__(self, platform, cd_ref, main_clk_se, COUNTER_BIT=32):
|
||||||
|
self.helper_reset = CSRStorage(reset=1)
|
||||||
|
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.submodules.main_dcxo = Si549(platform.request("ddmtd_main_dcxo_i2c"))
|
||||||
|
self.submodules.helper_dcxo = Si549(platform.request("ddmtd_helper_dcxo_i2c"))
|
||||||
|
|
||||||
|
helper_dcxo_pads = platform.request("ddmtd_helper_clk")
|
||||||
|
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_clk_se)
|
||||||
|
|
||||||
|
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)
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
|
# EventMangers for firmware 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):
|
||||||
|
sma_clkin_se = Signal()
|
||||||
|
mmcm_locked = Signal()
|
||||||
|
mmcm_fb_clk = Signal()
|
||||||
|
ref_clk = Signal()
|
||||||
|
self.clock_domains.cd_ref = ClockDomain()
|
||||||
|
self.refclk_reset = CSRStorage(reset=1)
|
||||||
|
|
||||||
|
self.mmcm_bypass = CSRStorage()
|
||||||
|
self.mmcm_locked = CSRStatus()
|
||||||
|
self.mmcm_reset = CSRStorage(reset=1)
|
||||||
|
|
||||||
|
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)
|
||||||
|
# The MMCME2 can be reconfiged during runtime using the Dynamic Reconfiguration Ports
|
||||||
|
Instance("MMCME2_ADV",
|
||||||
|
p_BANDWIDTH="HIGH", # lower output jitter (see https://support.xilinx.com/s/question/0D52E00006iHqRqSAK)
|
||||||
|
o_LOCKED=self.mmcm_locked.status,
|
||||||
|
i_RST=self.mmcm_reset.storage,
|
||||||
|
|
||||||
|
p_CLKIN1_PERIOD=8, # ns
|
||||||
|
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 Ports
|
||||||
|
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("BUFGMUX",
|
||||||
|
i_I0=ref_clk,
|
||||||
|
i_I1=sma_clkin_se,
|
||||||
|
i_S=self.mmcm_bypass.storage,
|
||||||
|
o_O=self.cd_ref.clk
|
||||||
|
),
|
||||||
|
AsyncResetSynchronizer(self.cd_ref, self.refclk_reset.storage),
|
||||||
|
]
|
|
@ -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,6 +56,19 @@ 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;
|
||||||
|
@ -64,7 +76,13 @@ where F: FnOnce(&[u8]) -> Result<T, Error> {
|
||||||
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 read_ptr = (DRTIOAUX[linkidx].aux_read_pointer_read)() as usize;
|
||||||
let ptr = (DRTIOAUX_MEM[linkidx].base + DRTIOAUX_MEM[linkidx].size / 2 + read_ptr * 0x400) as *mut u32;
|
let ptr = (DRTIOAUX_MEM[linkidx].base + DRTIOAUX_MEM[linkidx].size / 2 + read_ptr * 0x400) as *mut u32;
|
||||||
let result = f(slice::from_raw_parts(ptr as *mut u8, 0x400 as usize));
|
// work buffer to accomodate axi burst reads
|
||||||
|
// buffer at maximum proto packet size, not maximum gateware supported size
|
||||||
|
// to minimize copying time
|
||||||
|
const LEN: usize = 512;
|
||||||
|
let mut buf: [u8; LEN] = [0; LEN];
|
||||||
|
copy_work_buffer(ptr, buf.as_mut_ptr() as *mut u32, LEN as isize);
|
||||||
|
let result = f(&buf);
|
||||||
(DRTIOAUX[linkidx].aux_rx_present_write)(1);
|
(DRTIOAUX[linkidx].aux_rx_present_write)(1);
|
||||||
Ok(Some(result?))
|
Ok(Some(result?))
|
||||||
} else {
|
} else {
|
||||||
|
@ -115,7 +133,10 @@ 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))?;
|
// work buffer, works with unaligned mem access
|
||||||
|
let mut buf: [u8; 1024] = [0; 1024];
|
||||||
|
let len = f(&mut buf)?;
|
||||||
|
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};
|
||||||
|
|
||||||
|
@ -42,7 +40,13 @@ where F: FnOnce(&[u8]) -> Result<T, Error> {
|
||||||
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 read_ptr = (DRTIOAUX[linkidx].aux_read_pointer_read)() as usize;
|
||||||
let ptr = (DRTIOAUX_MEM[linkidx].base + DRTIOAUX_MEM[linkidx].size / 2 + read_ptr * 0x400) as *mut u32;
|
let ptr = (DRTIOAUX_MEM[linkidx].base + DRTIOAUX_MEM[linkidx].size / 2 + read_ptr * 0x400) as *mut u32;
|
||||||
let result = f(slice::from_raw_parts(ptr as *mut u8, 0x400 as usize));
|
// work buffer to accomodate axi burst reads
|
||||||
|
// buffer at maximum proto packet size, not maximum gateware supported size
|
||||||
|
// to minimize required copying time
|
||||||
|
const LEN: usize = 512;
|
||||||
|
let mut buf: [u8; LEN] = [0; LEN];
|
||||||
|
copy_work_buffer(ptr, buf.as_mut_ptr() as *mut u32, LEN as isize);
|
||||||
|
let result = f(&buf);
|
||||||
(DRTIOAUX[linkidx].aux_rx_present_write)(1);
|
(DRTIOAUX[linkidx].aux_rx_present_write)(1);
|
||||||
Ok(Some(result?))
|
Ok(Some(result?))
|
||||||
} else {
|
} else {
|
||||||
|
@ -102,7 +106,10 @@ 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))?;
|
// work buffer, works with unaligned mem access
|
||||||
|
let mut buf: [u8; 1024] = [0; 1024];
|
||||||
|
let len = f(&mut buf)?;
|
||||||
|
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;
|
||||||
|
|
||||||
|
|
|
@ -335,44 +335,16 @@ pub mod wrpll {
|
||||||
const COUNTER_WIDTH: u32 = 24;
|
const COUNTER_WIDTH: u32 = 24;
|
||||||
const DIV_WIDTH: u32 = 2;
|
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 KP: i32 = 6;
|
||||||
struct FilterParameters {
|
const KI: i32 = 2;
|
||||||
pub b0: f64,
|
// 4 ppm capture range
|
||||||
pub b1: f64,
|
const ADPLL_LIM: i32 = (4.0 / 0.0001164) as i32;
|
||||||
pub b2: f64,
|
|
||||||
pub a1: f64,
|
|
||||||
pub a2: f64,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(rtio_frequency = "100.0")]
|
|
||||||
const LPF: FilterParameters = FilterParameters {
|
|
||||||
b0: 0.03967479060647884,
|
|
||||||
b1: 0.07934958121295768,
|
|
||||||
b2: 0.03967479060647884,
|
|
||||||
a1: -1.3865593741228928,
|
|
||||||
a2: 0.5452585365488082,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[cfg(rtio_frequency = "125.0")]
|
|
||||||
const LPF: FilterParameters = FilterParameters {
|
|
||||||
b0: 0.07209205036273991,
|
|
||||||
b1: 0.14418410072547982,
|
|
||||||
b2: 0.07209205036273991,
|
|
||||||
a1: -0.6114078511562919,
|
|
||||||
a2: -0.10022394739274834,
|
|
||||||
};
|
|
||||||
|
|
||||||
static mut H_ADPLL1: i32 = 0;
|
|
||||||
static mut H_ADPLL2: i32 = 0;
|
|
||||||
static mut PERIOD_ERR1: i32 = 0;
|
|
||||||
static mut PERIOD_ERR2: i32 = 0;
|
|
||||||
|
|
||||||
static mut M_ADPLL1: i32 = 0;
|
|
||||||
static mut M_ADPLL2: i32 = 0;
|
|
||||||
static mut PHASE_ERR1: i32 = 0;
|
|
||||||
static mut PHASE_ERR2: i32 = 0;
|
|
||||||
|
|
||||||
static mut BASE_ADPLL: i32 = 0;
|
static mut BASE_ADPLL: i32 = 0;
|
||||||
|
static mut H_LAST_ADPLL: i32 = 0;
|
||||||
|
static mut LAST_PERIOD_ERR: i32 = 0;
|
||||||
|
static mut M_LAST_ADPLL: i32 = 0;
|
||||||
|
static mut LAST_PHASE_ERR: i32 = 0;
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub enum ISR {
|
pub enum ISR {
|
||||||
|
@ -500,14 +472,10 @@ pub mod wrpll {
|
||||||
|
|
||||||
fn reset_plls(timer: &mut GlobalTimer) -> Result<(), &'static str> {
|
fn reset_plls(timer: &mut GlobalTimer) -> Result<(), &'static str> {
|
||||||
unsafe {
|
unsafe {
|
||||||
H_ADPLL1 = 0;
|
H_LAST_ADPLL = 0;
|
||||||
H_ADPLL2 = 0;
|
LAST_PERIOD_ERR = 0;
|
||||||
PERIOD_ERR1 = 0;
|
M_LAST_ADPLL = 0;
|
||||||
PERIOD_ERR2 = 0;
|
LAST_PHASE_ERR = 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)?;
|
||||||
|
@ -551,14 +519,11 @@ pub mod wrpll {
|
||||||
fn helper_pll() -> Result<(), &'static str> {
|
fn helper_pll() -> Result<(), &'static str> {
|
||||||
let period_err = tag_collector::get_period_error();
|
let period_err = tag_collector::get_period_error();
|
||||||
unsafe {
|
unsafe {
|
||||||
let adpll = ((LPF.b0 * period_err as f64) + (LPF.b1 * PERIOD_ERR1 as f64) + (LPF.b2 * PERIOD_ERR2 as f64)
|
// Based on https://hackmd.io/IACbwcOTSt6Adj3_F9bKuw?view#Integral-wind-up-and-output-limiting
|
||||||
- (LPF.a1 * H_ADPLL1 as f64)
|
let adpll = (H_LAST_ADPLL + (KP + KI) * period_err - KP * LAST_PERIOD_ERR).clamp(-ADPLL_LIM, ADPLL_LIM);
|
||||||
- (LPF.a2 * H_ADPLL2 as f64)) as i32;
|
|
||||||
set_adpll(i2c::DCXO::Helper, BASE_ADPLL + adpll)?;
|
set_adpll(i2c::DCXO::Helper, BASE_ADPLL + adpll)?;
|
||||||
H_ADPLL2 = H_ADPLL1;
|
H_LAST_ADPLL = adpll;
|
||||||
PERIOD_ERR2 = PERIOD_ERR1;
|
LAST_PERIOD_ERR = period_err;
|
||||||
H_ADPLL1 = adpll;
|
|
||||||
PERIOD_ERR1 = period_err;
|
|
||||||
};
|
};
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -566,14 +531,11 @@ pub mod wrpll {
|
||||||
fn main_pll() -> Result<(), &'static str> {
|
fn main_pll() -> Result<(), &'static str> {
|
||||||
let phase_err = tag_collector::get_phase_error();
|
let phase_err = tag_collector::get_phase_error();
|
||||||
unsafe {
|
unsafe {
|
||||||
let adpll = ((LPF.b0 * phase_err as f64) + (LPF.b1 * PHASE_ERR1 as f64) + (LPF.b2 * PHASE_ERR2 as f64)
|
// Based on https://hackmd.io/IACbwcOTSt6Adj3_F9bKuw?view#Integral-wind-up-and-output-limiting
|
||||||
- (LPF.a1 * M_ADPLL1 as f64)
|
let adpll = (M_LAST_ADPLL + (KP + KI) * phase_err - KP * LAST_PHASE_ERR).clamp(-ADPLL_LIM, ADPLL_LIM);
|
||||||
- (LPF.a2 * M_ADPLL2 as f64)) as i32;
|
|
||||||
set_adpll(i2c::DCXO::Main, BASE_ADPLL + adpll)?;
|
set_adpll(i2c::DCXO::Main, BASE_ADPLL + adpll)?;
|
||||||
M_ADPLL2 = M_ADPLL1;
|
M_LAST_ADPLL = adpll;
|
||||||
PHASE_ERR2 = PHASE_ERR1;
|
LAST_PHASE_ERR = phase_err;
|
||||||
M_ADPLL1 = adpll;
|
|
||||||
PHASE_ERR1 = phase_err;
|
|
||||||
};
|
};
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -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())
|
||||||
|
|
Loading…
Reference in New Issue