forked from M-Labs/artiq-zynq
Compare commits
14 Commits
c261897658
...
586fd2f17e
Author | SHA1 | Date |
---|---|---|
morgan | 586fd2f17e | |
morgan | 377f8779a0 | |
morgan | 1fbaacfc43 | |
Sebastien Bourdeauducq | 127ea9ea4d | |
Simon Renblad | 174c301d7d | |
Sebastien Bourdeauducq | 52defff000 | |
mwojcik | 2b2ebb5354 | |
Sebastien Bourdeauducq | 4341d2d2a5 | |
Sebastien Bourdeauducq | 57b885ed99 | |
Sebastien Bourdeauducq | e922543855 | |
morgan | 35ea0ed2ca | |
morgan | cdf4ff24c0 | |
morgan | 285b02c4b1 | |
morgan | 53cb592d19 |
48
flake.lock
48
flake.lock
|
@ -11,11 +11,11 @@
|
||||||
"src-pythonparser": "src-pythonparser"
|
"src-pythonparser": "src-pythonparser"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1714013217,
|
"lastModified": 1716972728,
|
||||||
"narHash": "sha256-P0pVHTSgAkTYWFPjddcPhufe5oH8mjJAsxG8x8mo4NA=",
|
"narHash": "sha256-88J+eckZamtwhcCQkPpKLu6R1hmgj5+C9n2U5i+sHUE=",
|
||||||
"ref": "master",
|
"ref": "refs/heads/master",
|
||||||
"rev": "7204feae1f504e4a1dcd54b95c59e8f36c62b701",
|
"rev": "49e402780bebba437c6098047ab1dc68eaf5a17c",
|
||||||
"revCount": 8776,
|
"revCount": 8808,
|
||||||
"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": 1695805681,
|
"lastModified": 1704373101,
|
||||||
"narHash": "sha256-1ElPLD8eFfnuIk0G52HGGpRtQZ4QPCjChRlEOfkZ5ro=",
|
"narHash": "sha256-+gi59LRWRQmwROrmE1E2b3mtocwueCQqZ60CwLG+gbg=",
|
||||||
"owner": "mozilla",
|
"owner": "mozilla",
|
||||||
"repo": "nixpkgs-mozilla",
|
"repo": "nixpkgs-mozilla",
|
||||||
"rev": "6eabade97bc28d707a8b9d82ad13ef143836736e",
|
"rev": "9b11a87c0cc54e308fa83aac5b4ee1816d5418a2",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -118,16 +118,16 @@
|
||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1711668574,
|
"lastModified": 1716542732,
|
||||||
"narHash": "sha256-u1dfs0ASQIEr1icTVrsKwg2xToIpn7ZXxW3RHfHxshg=",
|
"narHash": "sha256-0Y9fRr0CUqWT4KgBITmaGwlnNIGMYuydu2L8iLTfHU4=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "219951b495fc2eac67b1456824cc1ec1fd2ee659",
|
"rev": "d12251ef6e8e6a46e05689eeccd595bdbd3c9e60",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"ref": "nixos-23.11",
|
"ref": "nixos-24.05",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
|
@ -163,11 +163,11 @@
|
||||||
"src-migen": {
|
"src-migen": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1702942348,
|
"lastModified": 1715484909,
|
||||||
"narHash": "sha256-gKIfHZxsv+jcgDFRW9mPqmwqbZXuRvXefkZcSFjOGHw=",
|
"narHash": "sha256-4DCHBUBfc/VA+7NW2Hr0+JP4NnKPru2uVJyZjCCk0Ws=",
|
||||||
"owner": "m-labs",
|
"owner": "m-labs",
|
||||||
"repo": "migen",
|
"repo": "migen",
|
||||||
"rev": "50934ad10a87ade47219b796535978b9bdf24023",
|
"rev": "4790bb577681a8c3a8d226bc196a4e5deb39e4df",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -179,11 +179,11 @@
|
||||||
"src-misoc": {
|
"src-misoc": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1699352904,
|
"lastModified": 1715647536,
|
||||||
"narHash": "sha256-SglyTmXOPv8jJOjwAjJrj/WhAkItQfUbvKfUqrynwRg=",
|
"narHash": "sha256-q+USDcaKHABwW56Jzq8u94iGPWlyLXMyVt0j/Gyg+IE=",
|
||||||
"ref": "refs/heads/master",
|
"ref": "refs/heads/master",
|
||||||
"rev": "a53859f2167c31ab5225b6c09f30cf05527b94f4",
|
"rev": "fea9de558c730bc394a5936094ae95bb9d6fa726",
|
||||||
"revCount": 2452,
|
"revCount": 2455,
|
||||||
"submodules": true,
|
"submodules": true,
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/m-labs/misoc.git"
|
"url": "https://github.com/m-labs/misoc.git"
|
||||||
|
@ -234,11 +234,11 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1711358419,
|
"lastModified": 1716519432,
|
||||||
"narHash": "sha256-LzetYaLsnov9pHVWSCTSowXUAXkxemAa61CIMY98xsc=",
|
"narHash": "sha256-vgKBJCQRPCutJ4n+FtJNczMZULWW7J3B8icf/PUothw=",
|
||||||
"ref": "master",
|
"ref": "refs/heads/master",
|
||||||
"rev": "195a21fe78e4dde1fd705cb2899ab5d2763ae037",
|
"rev": "46dc25b89e46b9043129d77e3c9348916748e325",
|
||||||
"revCount": 643,
|
"revCount": 645,
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://git.m-labs.hk/m-labs/zynq-rs"
|
"url": "https://git.m-labs.hk/m-labs/zynq-rs"
|
||||||
},
|
},
|
||||||
|
|
13
flake.nix
13
flake.nix
|
@ -11,6 +11,7 @@
|
||||||
pkgs = import artiq.inputs.nixpkgs { system = "x86_64-linux"; overlays = [ (import mozilla-overlay) ]; };
|
pkgs = import artiq.inputs.nixpkgs { system = "x86_64-linux"; overlays = [ (import mozilla-overlay) ]; };
|
||||||
zynqpkgs = zynq-rs.packages.x86_64-linux;
|
zynqpkgs = zynq-rs.packages.x86_64-linux;
|
||||||
artiqpkgs = artiq.packages.x86_64-linux;
|
artiqpkgs = artiq.packages.x86_64-linux;
|
||||||
|
llvmPackages_11 = zynq-rs.llvmPackages_11;
|
||||||
|
|
||||||
rust = zynq-rs.rust;
|
rust = zynq-rs.rust;
|
||||||
rustPlatform = zynq-rs.rustPlatform;
|
rustPlatform = zynq-rs.rustPlatform;
|
||||||
|
@ -132,12 +133,12 @@
|
||||||
pkgs.gnumake
|
pkgs.gnumake
|
||||||
(pkgs.python3.withPackages(ps: [ ps.jsonschema artiqpkgs.migen migen-axi artiqpkgs.misoc artiqpkgs.artiq ]))
|
(pkgs.python3.withPackages(ps: [ ps.jsonschema artiqpkgs.migen migen-axi artiqpkgs.misoc artiqpkgs.artiq ]))
|
||||||
zynqpkgs.cargo-xbuild
|
zynqpkgs.cargo-xbuild
|
||||||
pkgs.llvmPackages_9.llvm
|
llvmPackages_11.llvm
|
||||||
pkgs.llvmPackages_9.clang-unwrapped
|
llvmPackages_11.clang-unwrapped
|
||||||
];
|
];
|
||||||
buildPhase = ''
|
buildPhase = ''
|
||||||
export XARGO_RUST_SRC="${rust}/lib/rustlib/src/rust/library"
|
export XARGO_RUST_SRC="${rust}/lib/rustlib/src/rust/library"
|
||||||
export CLANG_EXTRA_INCLUDE_DIR="${pkgs.llvmPackages_9.clang-unwrapped.lib}/lib/clang/9.0.1/include"
|
export CLANG_EXTRA_INCLUDE_DIR="${llvmPackages_11.clang-unwrapped.lib}/lib/clang/11.1.0/include"
|
||||||
export CARGO_HOME=$(mktemp -d cargo-home.XXX)
|
export CARGO_HOME=$(mktemp -d cargo-home.XXX)
|
||||||
export ZYNQ_RS=${zynq-rs}
|
export ZYNQ_RS=${zynq-rs}
|
||||||
make TARGET=${target} GWARGS="${if json == null then "-V ${variant}" else json}" ${fwtype}
|
make TARGET=${target} GWARGS="${if json == null then "-V ${variant}" else json}" ${fwtype}
|
||||||
|
@ -370,8 +371,8 @@
|
||||||
name = "artiq-zynq-dev-shell";
|
name = "artiq-zynq-dev-shell";
|
||||||
buildInputs = with pkgs; [
|
buildInputs = with pkgs; [
|
||||||
rust
|
rust
|
||||||
llvmPackages_9.llvm
|
llvmPackages_11.llvm
|
||||||
llvmPackages_9.clang-unwrapped
|
llvmPackages_11.clang-unwrapped
|
||||||
gnumake
|
gnumake
|
||||||
cacert
|
cacert
|
||||||
zynqpkgs.cargo-xbuild
|
zynqpkgs.cargo-xbuild
|
||||||
|
@ -384,7 +385,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 = "${pkgs.llvmPackages_9.clang-unwrapped.lib}/lib/clang/9.0.1/include";
|
CLANG_EXTRA_INCLUDE_DIR = "${llvmPackages_11.clang-unwrapped.lib}/lib/clang/11.1.0/include";
|
||||||
ZYNQ_RS = "${zynq-rs}";
|
ZYNQ_RS = "${zynq-rs}";
|
||||||
OPENOCD_ZYNQ = "${zynq-rs}/openocd";
|
OPENOCD_ZYNQ = "${zynq-rs}/openocd";
|
||||||
SZL = "${zynqpkgs.szl}";
|
SZL = "${zynqpkgs.szl}";
|
||||||
|
|
|
@ -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,6 +135,7 @@ class GenericStandalone(SoCCore):
|
||||||
]
|
]
|
||||||
fix_serdes_timing_path(platform)
|
fix_serdes_timing_path(platform)
|
||||||
self.submodules.bootstrap = GTPBootstrapClock(self.platform, clk_freq)
|
self.submodules.bootstrap = GTPBootstrapClock(self.platform, clk_freq)
|
||||||
|
self.config["RTIO_FREQUENCY"] = str(clk_freq/1e6)
|
||||||
self.config["CLOCK_FREQUENCY"] = int(clk_freq)
|
self.config["CLOCK_FREQUENCY"] = int(clk_freq)
|
||||||
|
|
||||||
self.submodules.sys_crg = zynq_clocking.SYSCRG(self.platform, self.ps7, clk_synth_se_buf)
|
self.submodules.sys_crg = zynq_clocking.SYSCRG(self.platform, self.ps7, clk_synth_se_buf)
|
||||||
|
@ -145,7 +146,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.SMAFrequencyMultiplier(platform.request("sma_clkin"))
|
self.submodules.wrpll_refclk = wrpll.FrequencyMultiplier(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,
|
||||||
|
@ -242,6 +243,7 @@ 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()
|
||||||
|
@ -273,7 +275,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.SMAFrequencyMultiplier(platform.request("sma_clkin"))
|
self.submodules.wrpll_refclk = wrpll.FrequencyMultiplier(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,
|
||||||
|
|
|
@ -1,277 +0,0 @@
|
||||||
from migen import *
|
|
||||||
from migen.genlib.fsm import *
|
|
||||||
|
|
||||||
from misoc.interconnect.csr import *
|
|
||||||
|
|
||||||
|
|
||||||
class I2CClockGen(Module):
|
|
||||||
def __init__(self, width):
|
|
||||||
self.load = Signal(width)
|
|
||||||
self.clk2x = Signal()
|
|
||||||
|
|
||||||
cnt = Signal.like(self.load)
|
|
||||||
self.comb += [
|
|
||||||
self.clk2x.eq(cnt == 0),
|
|
||||||
]
|
|
||||||
self.sync += [
|
|
||||||
If(self.clk2x,
|
|
||||||
cnt.eq(self.load),
|
|
||||||
).Else(
|
|
||||||
cnt.eq(cnt - 1),
|
|
||||||
)
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
class I2CMasterMachine(Module):
|
|
||||||
def __init__(self, clock_width):
|
|
||||||
self.scl = Signal(reset=1)
|
|
||||||
self.sda_o = Signal(reset=1)
|
|
||||||
self.sda_i = Signal()
|
|
||||||
|
|
||||||
self.submodules.cg = CEInserter()(I2CClockGen(clock_width))
|
|
||||||
self.start = Signal()
|
|
||||||
self.stop = Signal()
|
|
||||||
self.write = Signal()
|
|
||||||
self.ack = Signal()
|
|
||||||
self.data = Signal(8)
|
|
||||||
self.ready = Signal()
|
|
||||||
|
|
||||||
# # #
|
|
||||||
|
|
||||||
bits = Signal(4)
|
|
||||||
data = Signal(8)
|
|
||||||
|
|
||||||
fsm = CEInserter()(FSM("IDLE"))
|
|
||||||
self.submodules += fsm
|
|
||||||
|
|
||||||
fsm.act("IDLE",
|
|
||||||
self.ready.eq(1),
|
|
||||||
If(self.start,
|
|
||||||
NextState("START0"),
|
|
||||||
).Elif(self.stop,
|
|
||||||
NextState("STOP0"),
|
|
||||||
).Elif(self.write,
|
|
||||||
NextValue(bits, 8),
|
|
||||||
NextValue(data, self.data),
|
|
||||||
NextState("WRITE0")
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
fsm.act("START0",
|
|
||||||
NextValue(self.scl, 1),
|
|
||||||
NextState("START1")
|
|
||||||
)
|
|
||||||
fsm.act("START1",
|
|
||||||
NextValue(self.sda_o, 0),
|
|
||||||
NextState("IDLE")
|
|
||||||
)
|
|
||||||
|
|
||||||
fsm.act("STOP0",
|
|
||||||
NextValue(self.scl, 0),
|
|
||||||
NextState("STOP1")
|
|
||||||
)
|
|
||||||
fsm.act("STOP1",
|
|
||||||
NextValue(self.sda_o, 0),
|
|
||||||
NextState("STOP2")
|
|
||||||
)
|
|
||||||
fsm.act("STOP2",
|
|
||||||
NextValue(self.scl, 1),
|
|
||||||
NextState("STOP3")
|
|
||||||
)
|
|
||||||
fsm.act("STOP3",
|
|
||||||
NextValue(self.sda_o, 1),
|
|
||||||
NextState("IDLE")
|
|
||||||
)
|
|
||||||
|
|
||||||
fsm.act("WRITE0",
|
|
||||||
NextValue(self.scl, 0),
|
|
||||||
NextState("WRITE1")
|
|
||||||
)
|
|
||||||
fsm.act("WRITE1",
|
|
||||||
If(bits == 0,
|
|
||||||
NextValue(self.sda_o, 1),
|
|
||||||
NextState("READACK0"),
|
|
||||||
).Else(
|
|
||||||
NextValue(self.sda_o, data[7]),
|
|
||||||
NextState("WRITE2"),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
fsm.act("WRITE2",
|
|
||||||
NextValue(self.scl, 1),
|
|
||||||
NextValue(data[1:], data[:-1]),
|
|
||||||
NextValue(bits, bits - 1),
|
|
||||||
NextState("WRITE0"),
|
|
||||||
)
|
|
||||||
fsm.act("READACK0",
|
|
||||||
NextValue(self.scl, 1),
|
|
||||||
NextState("READACK1"),
|
|
||||||
)
|
|
||||||
fsm.act("READACK1",
|
|
||||||
NextValue(self.ack, ~self.sda_i),
|
|
||||||
NextState("IDLE")
|
|
||||||
)
|
|
||||||
|
|
||||||
run = Signal()
|
|
||||||
idle = Signal()
|
|
||||||
self.comb += [
|
|
||||||
run.eq((self.start | self.stop | self.write) & self.ready),
|
|
||||||
idle.eq(~run & fsm.ongoing("IDLE")),
|
|
||||||
self.cg.ce.eq(~idle),
|
|
||||||
fsm.ce.eq(run | self.cg.clk2x),
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
class ADPLLProgrammer(Module):
|
|
||||||
def __init__(self):
|
|
||||||
self.i2c_divider = Signal(16)
|
|
||||||
self.i2c_address = Signal(7)
|
|
||||||
|
|
||||||
self.adpll = Signal(24)
|
|
||||||
self.stb = Signal()
|
|
||||||
self.busy = Signal()
|
|
||||||
self.nack = Signal()
|
|
||||||
|
|
||||||
self.scl = Signal()
|
|
||||||
self.sda_i = Signal()
|
|
||||||
self.sda_o = Signal()
|
|
||||||
|
|
||||||
# # #
|
|
||||||
|
|
||||||
master = I2CMasterMachine(16)
|
|
||||||
self.submodules += master
|
|
||||||
|
|
||||||
self.comb += [
|
|
||||||
master.cg.load.eq(self.i2c_divider),
|
|
||||||
self.scl.eq(master.scl),
|
|
||||||
master.sda_i.eq(self.sda_i),
|
|
||||||
self.sda_o.eq(master.sda_o)
|
|
||||||
]
|
|
||||||
|
|
||||||
fsm = FSM()
|
|
||||||
self.submodules += fsm
|
|
||||||
|
|
||||||
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),
|
|
||||||
)
|
|
||||||
]
|
|
|
@ -1,237 +0,0 @@
|
||||||
from migen import *
|
|
||||||
from migen.genlib.cdc import MultiReg, AsyncResetSynchronizer, PulseSynchronizer
|
|
||||||
from misoc.interconnect.csr import *
|
|
||||||
from misoc.interconnect.csr_eventmanager import *
|
|
||||||
|
|
||||||
from ddmtd import DDMTDSampler, DDMTD
|
|
||||||
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,9 +1,10 @@
|
||||||
|
use core::slice;
|
||||||
|
|
||||||
use core_io::{Error as IoError, ErrorKind as IoErrorKind};
|
use core_io::{Error as IoError, ErrorKind as IoErrorKind};
|
||||||
use crc;
|
use crc;
|
||||||
use io::{proto::{ProtoRead, ProtoWrite},
|
use io::{proto::{ProtoRead, ProtoWrite},
|
||||||
Cursor};
|
Cursor};
|
||||||
use libboard_zynq::{time::Milliseconds, timer::GlobalTimer};
|
use libboard_zynq::{time::Milliseconds, timer::GlobalTimer};
|
||||||
use libcortex_a9::asm::dmb;
|
|
||||||
|
|
||||||
pub use crate::drtioaux_proto::Packet;
|
pub use crate::drtioaux_proto::Packet;
|
||||||
use crate::{drtioaux_proto::Error as ProtocolError, mem::mem::DRTIOAUX_MEM, pl::csr::DRTIOAUX};
|
use crate::{drtioaux_proto::Error as ProtocolError, mem::mem::DRTIOAUX_MEM, pl::csr::DRTIOAUX};
|
||||||
|
@ -56,19 +57,6 @@ 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;
|
||||||
|
@ -76,13 +64,7 @@ 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;
|
||||||
// work buffer to accomodate axi burst reads
|
let result = f(slice::from_raw_parts(ptr as *mut u8, 0x400 as usize));
|
||||||
// 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 {
|
||||||
|
@ -133,10 +115,7 @@ where F: FnOnce(&mut [u8]) -> Result<usize, Error> {
|
||||||
unsafe {
|
unsafe {
|
||||||
while (DRTIOAUX[linkno].aux_tx_read)() != 0 {}
|
while (DRTIOAUX[linkno].aux_tx_read)() != 0 {}
|
||||||
let ptr = DRTIOAUX_MEM[linkno].base as *mut u32;
|
let ptr = DRTIOAUX_MEM[linkno].base as *mut u32;
|
||||||
// work buffer, works with unaligned mem access
|
let len = f(slice::from_raw_parts_mut(ptr as *mut u8, 0x400 as usize))?;
|
||||||
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,3 +1,5 @@
|
||||||
|
use core::slice;
|
||||||
|
|
||||||
use core_io::{Error as IoError, ErrorKind as IoErrorKind};
|
use core_io::{Error as IoError, ErrorKind as IoErrorKind};
|
||||||
use crc;
|
use crc;
|
||||||
use io::{proto::{ProtoRead, ProtoWrite},
|
use io::{proto::{ProtoRead, ProtoWrite},
|
||||||
|
@ -8,7 +10,7 @@ use nb;
|
||||||
use void::Void;
|
use void::Void;
|
||||||
|
|
||||||
pub use crate::drtioaux_proto::Packet;
|
pub use crate::drtioaux_proto::Packet;
|
||||||
use crate::{drtioaux::{copy_work_buffer, has_rx_error, Error},
|
use crate::{drtioaux::{has_rx_error, Error},
|
||||||
mem::mem::DRTIOAUX_MEM,
|
mem::mem::DRTIOAUX_MEM,
|
||||||
pl::csr::DRTIOAUX};
|
pl::csr::DRTIOAUX};
|
||||||
|
|
||||||
|
@ -40,13 +42,7 @@ 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;
|
||||||
// work buffer to accomodate axi burst reads
|
let result = f(slice::from_raw_parts(ptr as *mut u8, 0x400 as usize));
|
||||||
// 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 {
|
||||||
|
@ -106,10 +102,7 @@ where F: FnOnce(&mut [u8]) -> Result<usize, Error> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let _ = block_async!(tx_ready(linkno)).await;
|
let _ = block_async!(tx_ready(linkno)).await;
|
||||||
let ptr = DRTIOAUX_MEM[linkno].base as *mut u32;
|
let ptr = DRTIOAUX_MEM[linkno].base as *mut u32;
|
||||||
// work buffer, works with unaligned mem access
|
let len = f(slice::from_raw_parts_mut(ptr as *mut u8, 0x400 as usize))?;
|
||||||
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,9 +1,11 @@
|
||||||
use core_io::{Error as IoError, Read, Write};
|
use core_io::{Error as IoError, Read, Write};
|
||||||
use io::proto::{ProtoRead, ProtoWrite};
|
use io::proto::{ProtoRead, ProtoWrite};
|
||||||
|
|
||||||
|
const MAX_PACKET: usize = 1024;
|
||||||
|
|
||||||
// maximum size of arbitrary payloads
|
// maximum size of arbitrary payloads
|
||||||
// used by satellite -> master analyzer, subkernel exceptions
|
// used by satellite -> master analyzer, subkernel exceptions
|
||||||
pub const SAT_PAYLOAD_MAX_SIZE: usize = /*max size*/512 - /*CRC*/4 - /*packet ID*/1 - /*last*/1 - /*length*/2;
|
pub const SAT_PAYLOAD_MAX_SIZE: usize = /*max size*/MAX_PACKET - /*CRC*/4 - /*packet ID*/1 - /*last*/1 - /*length*/2;
|
||||||
// used by DDMA, subkernel program data (need to provide extra ID and destination)
|
// used by DDMA, subkernel program data (need to provide extra ID and destination)
|
||||||
pub const MASTER_PAYLOAD_MAX_SIZE: usize = SAT_PAYLOAD_MAX_SIZE - /*source*/1 - /*destination*/1 - /*ID*/4;
|
pub const MASTER_PAYLOAD_MAX_SIZE: usize = SAT_PAYLOAD_MAX_SIZE - /*source*/1 - /*destination*/1 - /*ID*/4;
|
||||||
|
|
||||||
|
|
|
@ -335,16 +335,44 @@ pub mod wrpll {
|
||||||
const COUNTER_WIDTH: u32 = 24;
|
const COUNTER_WIDTH: u32 = 24;
|
||||||
const DIV_WIDTH: u32 = 2;
|
const DIV_WIDTH: u32 = 2;
|
||||||
|
|
||||||
const KP: i32 = 6;
|
// y[n] = b0*x[n] + b1*x[n-1] + b2*x[n-2] - a1*y[n-1] - a2*y[n-2]
|
||||||
const KI: i32 = 2;
|
struct FilterParameters {
|
||||||
// 4 ppm capture range
|
pub b0: f64,
|
||||||
const ADPLL_LIM: i32 = (4.0 / 0.0001164) as i32;
|
pub b1: f64,
|
||||||
|
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 {
|
||||||
|
@ -472,10 +500,14 @@ pub mod wrpll {
|
||||||
|
|
||||||
fn reset_plls(timer: &mut GlobalTimer) -> Result<(), &'static str> {
|
fn reset_plls(timer: &mut GlobalTimer) -> Result<(), &'static str> {
|
||||||
unsafe {
|
unsafe {
|
||||||
H_LAST_ADPLL = 0;
|
H_ADPLL1 = 0;
|
||||||
LAST_PERIOD_ERR = 0;
|
H_ADPLL2 = 0;
|
||||||
M_LAST_ADPLL = 0;
|
PERIOD_ERR1 = 0;
|
||||||
LAST_PHASE_ERR = 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)?;
|
||||||
|
@ -519,11 +551,14 @@ 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 {
|
||||||
// Based on https://hackmd.io/IACbwcOTSt6Adj3_F9bKuw?view#Integral-wind-up-and-output-limiting
|
let adpll = ((LPF.b0 * period_err as f64) + (LPF.b1 * PERIOD_ERR1 as f64) + (LPF.b2 * PERIOD_ERR2 as f64)
|
||||||
let adpll = (H_LAST_ADPLL + (KP + KI) * period_err - KP * LAST_PERIOD_ERR).clamp(-ADPLL_LIM, ADPLL_LIM);
|
- (LPF.a1 * H_ADPLL1 as f64)
|
||||||
|
- (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_LAST_ADPLL = adpll;
|
H_ADPLL2 = H_ADPLL1;
|
||||||
LAST_PERIOD_ERR = period_err;
|
PERIOD_ERR2 = PERIOD_ERR1;
|
||||||
|
H_ADPLL1 = adpll;
|
||||||
|
PERIOD_ERR1 = period_err;
|
||||||
};
|
};
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -531,11 +566,14 @@ 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 {
|
||||||
// Based on https://hackmd.io/IACbwcOTSt6Adj3_F9bKuw?view#Integral-wind-up-and-output-limiting
|
let adpll = ((LPF.b0 * phase_err as f64) + (LPF.b1 * PHASE_ERR1 as f64) + (LPF.b2 * PHASE_ERR2 as f64)
|
||||||
let adpll = (M_LAST_ADPLL + (KP + KI) * phase_err - KP * LAST_PHASE_ERR).clamp(-ADPLL_LIM, ADPLL_LIM);
|
- (LPF.a1 * M_ADPLL1 as f64)
|
||||||
|
- (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_LAST_ADPLL = adpll;
|
M_ADPLL2 = M_ADPLL1;
|
||||||
LAST_PHASE_ERR = phase_err;
|
PHASE_ERR2 = PHASE_ERR1;
|
||||||
|
M_ADPLL1 = adpll;
|
||||||
|
PHASE_ERR1 = phase_err;
|
||||||
};
|
};
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,7 +45,10 @@ impl<T: AsRef<[u8]>> Read for Cursor<T> {
|
||||||
fn read(&mut self, buf: &mut [u8]) -> Result<usize, IoError> {
|
fn read(&mut self, buf: &mut [u8]) -> Result<usize, IoError> {
|
||||||
let data = &self.inner.as_ref()[self.pos..];
|
let data = &self.inner.as_ref()[self.pos..];
|
||||||
let len = buf.len().min(data.len());
|
let len = buf.len().min(data.len());
|
||||||
buf[..len].copy_from_slice(&data[..len]);
|
// ``copy_from_slice`` generates AXI bursts, use a regular loop instead
|
||||||
|
for i in 0..len {
|
||||||
|
buf[i] = data[i];
|
||||||
|
}
|
||||||
self.pos += len;
|
self.pos += len;
|
||||||
Ok(len)
|
Ok(len)
|
||||||
}
|
}
|
||||||
|
@ -55,7 +58,9 @@ impl Write for Cursor<&mut [u8]> {
|
||||||
fn write(&mut self, buf: &[u8]) -> Result<usize, IoError> {
|
fn write(&mut self, buf: &[u8]) -> Result<usize, IoError> {
|
||||||
let data = &mut self.inner[self.pos..];
|
let data = &mut self.inner[self.pos..];
|
||||||
let len = buf.len().min(data.len());
|
let len = buf.len().min(data.len());
|
||||||
data[..len].copy_from_slice(&buf[..len]);
|
for i in 0..len {
|
||||||
|
data[i] = buf[i];
|
||||||
|
}
|
||||||
self.pos += len;
|
self.pos += len;
|
||||||
Ok(len)
|
Ok(len)
|
||||||
}
|
}
|
||||||
|
@ -68,7 +73,6 @@ impl Write for Cursor<&mut [u8]> {
|
||||||
|
|
||||||
#[cfg(feature = "alloc")]
|
#[cfg(feature = "alloc")]
|
||||||
impl Write for Cursor<Vec<u8>> {
|
impl Write for Cursor<Vec<u8>> {
|
||||||
#[inline]
|
|
||||||
fn write(&mut self, buf: &[u8]) -> Result<usize, IoError> {
|
fn write(&mut self, buf: &[u8]) -> Result<usize, IoError> {
|
||||||
self.inner.extend_from_slice(buf);
|
self.inner.extend_from_slice(buf);
|
||||||
Ok(buf.len())
|
Ok(buf.len())
|
||||||
|
|
Loading…
Reference in New Issue