Compare commits

..

No commits in common. "master" and "master" have entirely different histories.

40 changed files with 786 additions and 4047 deletions

View File

@ -62,7 +62,7 @@ Notes:
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
it under the terms of the GNU Lesser General Public License as published by

View File

@ -11,11 +11,11 @@
"src-pythonparser": "src-pythonparser"
},
"locked": {
"lastModified": 1714013217,
"narHash": "sha256-P0pVHTSgAkTYWFPjddcPhufe5oH8mjJAsxG8x8mo4NA=",
"ref": "master",
"rev": "7204feae1f504e4a1dcd54b95c59e8f36c62b701",
"revCount": 8776,
"lastModified": 1697013694,
"narHash": "sha256-jmr+pFeyV0+nUbFY8/g2Aw4kU06i5CG0XhLobI8vUR8=",
"ref": "refs/heads/master",
"rev": "f7abc156cbc0a371452148d11436e5f241798092",
"revCount": 8569,
"type": "git",
"url": "https://github.com/m-labs/artiq.git"
},
@ -37,11 +37,11 @@
]
},
"locked": {
"lastModified": 1707216368,
"narHash": "sha256-ZXoqzG2QsVsybALLYXs473avXcyKSZNh2kIgcPo60XQ=",
"lastModified": 1693473687,
"narHash": "sha256-BdLddCWbvoEyakcGwhph9b5dIU1iA0hCQV7KYgU8nos=",
"owner": "m-labs",
"repo": "artiq-comtools",
"rev": "e5d0204490bccc07ef9141b0d7c405ab01cb8273",
"rev": "f522ef3dbc65961f17b2d3d41e927409d970fd79",
"type": "github"
},
"original": {
@ -55,11 +55,11 @@
"systems": "systems"
},
"locked": {
"lastModified": 1694529238,
"narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=",
"lastModified": 1692799911,
"narHash": "sha256-3eihraek4qL744EvQXsK1Ha6C3CR7nnT8X2qWap4RNk=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "ff7b65b44d01cf9ba6a71320833626af21126384",
"rev": "f9e7cf818399d17d347f847525c5a5a8032e4e44",
"type": "github"
},
"original": {
@ -69,38 +69,6 @@
}
},
"mozilla-overlay": {
"flake": false,
"locked": {
"lastModified": 1704373101,
"narHash": "sha256-+gi59LRWRQmwROrmE1E2b3mtocwueCQqZ60CwLG+gbg=",
"owner": "mozilla",
"repo": "nixpkgs-mozilla",
"rev": "9b11a87c0cc54e308fa83aac5b4ee1816d5418a2",
"type": "github"
},
"original": {
"owner": "mozilla",
"repo": "nixpkgs-mozilla",
"type": "github"
}
},
"mozilla-overlay_2": {
"flake": false,
"locked": {
"lastModified": 1704373101,
"narHash": "sha256-+gi59LRWRQmwROrmE1E2b3mtocwueCQqZ60CwLG+gbg=",
"owner": "mozilla",
"repo": "nixpkgs-mozilla",
"rev": "9b11a87c0cc54e308fa83aac5b4ee1816d5418a2",
"type": "github"
},
"original": {
"owner": "mozilla",
"repo": "nixpkgs-mozilla",
"type": "github"
}
},
"mozilla-overlay_3": {
"flake": false,
"locked": {
"lastModified": 1695805681,
@ -116,18 +84,50 @@
"type": "github"
}
},
"mozilla-overlay_2": {
"flake": false,
"locked": {
"lastModified": 1695805681,
"narHash": "sha256-1ElPLD8eFfnuIk0G52HGGpRtQZ4QPCjChRlEOfkZ5ro=",
"owner": "mozilla",
"repo": "nixpkgs-mozilla",
"rev": "6eabade97bc28d707a8b9d82ad13ef143836736e",
"type": "github"
},
"original": {
"owner": "mozilla",
"repo": "nixpkgs-mozilla",
"type": "github"
}
},
"mozilla-overlay_3": {
"flake": false,
"locked": {
"lastModified": 1690536331,
"narHash": "sha256-aRIf2FB2GTdfF7gl13WyETmiV/J7EhBGkSWXfZvlxcA=",
"owner": "mozilla",
"repo": "nixpkgs-mozilla",
"rev": "db89c8707edcffefcd8e738459d511543a339ff5",
"type": "github"
},
"original": {
"owner": "mozilla",
"repo": "nixpkgs-mozilla",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1711668574,
"narHash": "sha256-u1dfs0ASQIEr1icTVrsKwg2xToIpn7ZXxW3RHfHxshg=",
"lastModified": 1696697597,
"narHash": "sha256-q26Qv4DQ+h6IeozF2o1secyQG0jt2VUT3V0K58jr3pg=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "219951b495fc2eac67b1456824cc1ec1fd2ee659",
"rev": "5a237aecb57296f67276ac9ab296a41c23981f56",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-23.11",
"ref": "nixos-23.05",
"repo": "nixpkgs",
"type": "github"
}
@ -147,11 +147,11 @@
]
},
"locked": {
"lastModified": 1708937641,
"narHash": "sha256-Hkb9VYFzFgkYxfbh4kYcDSn7DbMUYehoQDeTALrxo2Q=",
"lastModified": 1693473454,
"narHash": "sha256-kr8Ur6JNW/xVRHdPn3ou980IAxg/n+f3ZQBHuJ1uaC4=",
"owner": "m-labs",
"repo": "sipyco",
"rev": "4a28b311ce0069454b4e8fe1e6049db11b9f1296",
"rev": "5467dcf9738673ab9a49e6f2377bda7c551b5f90",
"type": "github"
},
"original": {
@ -163,11 +163,11 @@
"src-migen": {
"flake": false,
"locked": {
"lastModified": 1702942348,
"narHash": "sha256-gKIfHZxsv+jcgDFRW9mPqmwqbZXuRvXefkZcSFjOGHw=",
"lastModified": 1697013661,
"narHash": "sha256-qNCqgWyE4vTDmyjE2XMJqW1djuBxT25A36AzQfZqluU=",
"owner": "m-labs",
"repo": "migen",
"rev": "50934ad10a87ade47219b796535978b9bdf24023",
"rev": "aadc19df93b7aa9ca761aaebbb98a11e0cf2d7c7",
"type": "github"
},
"original": {
@ -179,11 +179,11 @@
"src-misoc": {
"flake": false,
"locked": {
"lastModified": 1699352904,
"narHash": "sha256-SglyTmXOPv8jJOjwAjJrj/WhAkItQfUbvKfUqrynwRg=",
"lastModified": 1693709836,
"narHash": "sha256-YiCk05RYLzZu1CYkQ2r7XtjwVEqkUGTQn388uOls9tI=",
"ref": "refs/heads/master",
"rev": "a53859f2167c31ab5225b6c09f30cf05527b94f4",
"revCount": 2452,
"rev": "58dc4ee60d165ce9145cf3d904241fc154b6407f",
"revCount": 2448,
"submodules": true,
"type": "git",
"url": "https://github.com/m-labs/misoc.git"
@ -234,11 +234,11 @@
]
},
"locked": {
"lastModified": 1711358419,
"narHash": "sha256-LzetYaLsnov9pHVWSCTSowXUAXkxemAa61CIMY98xsc=",
"ref": "master",
"rev": "195a21fe78e4dde1fd705cb2899ab5d2763ae037",
"revCount": 643,
"lastModified": 1693479539,
"narHash": "sha256-MppR7yxs3cjG7tQc82vX0MhyN71CJL2QWkM65F5hrFU=",
"ref": "refs/heads/master",
"rev": "c15b54f92b3d4e125ae47a0dce7abe4b2bc9e054",
"revCount": 628,
"type": "git",
"url": "https://git.m-labs.hk/m-labs/zynq-rs"
},

View File

@ -78,7 +78,6 @@
# migen/misoc version checks are broken with pyproject for some reason
postPatch = ''
sed -i "1,4d" pyproject.toml
substituteInPlace pyproject.toml \
--replace '"migen@git+https://github.com/m-labs/migen",' ""
substituteInPlace pyproject.toml \
@ -113,7 +112,7 @@
"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"
];
board-package-set = { target, variant, json ? null }: let
build = { target, variant, json ? null }: let
szl = zynqpkgs."${target}-szl";
fsbl = zynqpkgs."${target}-fsbl";
fwtype = if builtins.elem variant sat_variants then "satman" else "runtime";
@ -123,9 +122,6 @@
src = ./src;
cargoLock = {
lockFile = src/Cargo.lock;
outputHashes = {
"tar-no-std-0.1.8" = "sha256-xm17108v4smXOqxdLvHl9CxTCJslmeogjm4Y87IXFuM=";
};
};
nativeBuildInputs = [
@ -153,7 +149,6 @@
doCheck = false;
dontFixup = true;
auditable = false;
};
gateware = pkgs.runCommand "${target}-${variant}-gateware"
{
@ -273,7 +268,7 @@
};
# 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 {
name = "zc706-hitl-tests";
@ -340,29 +335,29 @@
{
inherit fastnumbers artiq-netboot ramda migen-axi binutils-arm;
} //
(board-package-set { target = "zc706"; variant = "nist_clock"; }) //
(board-package-set { target = "zc706"; variant = "nist_clock_master"; }) //
(board-package-set { target = "zc706"; variant = "nist_clock_master_100mhz"; }) //
(board-package-set { target = "zc706"; variant = "nist_clock_satellite"; }) //
(board-package-set { target = "zc706"; variant = "nist_clock_satellite_100mhz"; }) //
(board-package-set { target = "zc706"; variant = "nist_qc2"; }) //
(board-package-set { target = "zc706"; variant = "nist_qc2_master"; }) //
(board-package-set { target = "zc706"; variant = "nist_qc2_master_100mhz"; }) //
(board-package-set { target = "zc706"; variant = "nist_qc2_satellite"; }) //
(board-package-set { target = "zc706"; variant = "nist_qc2_satellite_100mhz"; }) //
(board-package-set { target = "zc706"; variant = "acpki_nist_clock"; }) //
(board-package-set { target = "zc706"; variant = "acpki_nist_clock_master"; }) //
(board-package-set { target = "zc706"; variant = "acpki_nist_clock_master_100mhz"; }) //
(board-package-set { target = "zc706"; variant = "acpki_nist_clock_satellite"; }) //
(board-package-set { target = "zc706"; variant = "acpki_nist_clock_satellite_100mhz"; }) //
(board-package-set { target = "zc706"; variant = "acpki_nist_qc2"; }) //
(board-package-set { target = "zc706"; variant = "acpki_nist_qc2_master"; }) //
(board-package-set { target = "zc706"; variant = "acpki_nist_qc2_master_100mhz"; }) //
(board-package-set { target = "zc706"; variant = "acpki_nist_qc2_satellite"; }) //
(board-package-set { target = "zc706"; variant = "acpki_nist_qc2_satellite_100mhz"; }) //
(board-package-set { target = "kasli_soc"; variant = "demo"; json = ./demo.json; }) //
(board-package-set { 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 = "zc706"; variant = "nist_clock"; }) //
(build { target = "zc706"; variant = "nist_clock_master"; }) //
(build { target = "zc706"; variant = "nist_clock_master_100mhz"; }) //
(build { target = "zc706"; variant = "nist_clock_satellite"; }) //
(build { target = "zc706"; variant = "nist_clock_satellite_100mhz"; }) //
(build { target = "zc706"; variant = "nist_qc2"; }) //
(build { target = "zc706"; variant = "nist_qc2_master"; }) //
(build { target = "zc706"; variant = "nist_qc2_master_100mhz"; }) //
(build { target = "zc706"; variant = "nist_qc2_satellite"; }) //
(build { target = "zc706"; variant = "nist_qc2_satellite_100mhz"; }) //
(build { target = "zc706"; variant = "acpki_nist_clock"; }) //
(build { target = "zc706"; variant = "acpki_nist_clock_master"; }) //
(build { target = "zc706"; variant = "acpki_nist_clock_master_100mhz"; }) //
(build { target = "zc706"; variant = "acpki_nist_clock_satellite"; }) //
(build { target = "zc706"; variant = "acpki_nist_clock_satellite_100mhz"; }) //
(build { target = "zc706"; variant = "acpki_nist_qc2"; }) //
(build { target = "zc706"; variant = "acpki_nist_qc2_master"; }) //
(build { target = "zc706"; variant = "acpki_nist_qc2_master_100mhz"; }) //
(build { target = "zc706"; variant = "acpki_nist_qc2_satellite"; }) //
(build { target = "zc706"; variant = "acpki_nist_qc2_satellite_100mhz"; }) //
(build { target = "kasli_soc"; variant = "demo"; json = ./demo.json; }) //
(build { target = "kasli_soc"; variant = "master"; json = ./kasli-soc-master.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; };
@ -390,7 +385,7 @@
SZL = "${zynqpkgs.szl}";
};
makeArtiqZynqPackage = board-package-set;
makeArtiqZynqPackage = build;
};
}

17
src/Cargo.lock generated
View File

@ -2,12 +2,6 @@
# It is not intended for manual editing.
version = 3
[[package]]
name = "arrayvec"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711"
[[package]]
name = "async-recursion"
version = "0.3.2"
@ -480,7 +474,6 @@ dependencies = [
"log_buffer",
"num-derive",
"num-traits",
"tar-no-std",
"unwind",
"vcell",
"void",
@ -545,16 +538,6 @@ dependencies = [
"unicode-ident",
]
[[package]]
name = "tar-no-std"
version = "0.1.8"
source = "git+https://git.m-labs.hk/M-Labs/tar-no-std?rev=2ab6dc5#2ab6dc58e5249c59c4eb03eaf3a119bcdd678d32"
dependencies = [
"arrayvec",
"bitflags",
"log",
]
[[package]]
name = "unicode-ident"
version = "1.0.5"

View File

@ -1,119 +0,0 @@
from migen import *
from migen.genlib.cdc import PulseSynchronizer, MultiReg
from misoc.interconnect.csr import *
class DDMTDSampler(Module):
def __init__(self, cd_ref, main_clk_se):
self.ref_beating = Signal()
self.main_beating = Signal()
# # #
ref_clk = Signal()
self.specials +=[
# ISERDESE2 can only be driven from fabric via IDELAYE2 (see UG471)
Instance("IDELAYE2",
p_DELAY_SRC="DATAIN",
p_HIGH_PERFORMANCE_MODE="TRUE",
p_REFCLK_FREQUENCY=208.3, # REFCLK frequency from IDELAYCTRL
p_IDELAY_VALUE=0,
i_DATAIN=cd_ref.clk,
o_DATAOUT=ref_clk
),
Instance("ISERDESE2",
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):
def __init__(self, counter, input_signal, stable_0_period=100, stable_1_period=100):
self.tag = Signal(len(counter))
self.detect = Signal()
stable_0_counter = Signal(reset=stable_0_period - 1, max=stable_0_period)
stable_1_counter = Signal(reset=stable_1_period - 1, max=stable_1_period)
# # #
# Based on CERN's median edge deglitcher FSM
# https://white-rabbit.web.cern.ch/documents/Precise_time_and_frequency_transfer_in_a_White_Rabbit_network.pdf (p.72)
fsm = ClockDomainsRenamer("helper")(FSM(reset_state="WAIT_STABLE_0"))
self.submodules += fsm
fsm.act("WAIT_STABLE_0",
If(stable_0_counter != 0,
NextValue(stable_0_counter, stable_0_counter - 1)
).Else(
NextValue(stable_0_counter, stable_0_period - 1),
NextState("WAIT_EDGE")
),
If(input_signal,
NextValue(stable_0_counter, stable_0_period - 1)
),
)
fsm.act("WAIT_EDGE",
If(input_signal,
NextValue(self.tag, counter),
NextState("GOT_EDGE")
)
)
fsm.act("GOT_EDGE",
If(stable_1_counter != 0,
NextValue(stable_1_counter, stable_1_counter - 1)
).Else(
NextValue(stable_1_counter, stable_1_period - 1),
self.detect.eq(1),
NextState("WAIT_STABLE_0")
),
If(~input_signal,
NextValue(self.tag, self.tag + 1),
NextValue(stable_1_counter, stable_1_period - 1)
),
)
class DDMTD(Module):
def __init__(self, counter, input_signal):
# in helper clock domain
self.h_tag = Signal(len(counter))
self.h_tag_update = Signal()
# # #
deglitcher = DDMTDDeglitcherMedianEdge(counter, input_signal)
self.submodules += deglitcher
self.sync.helper += [
self.h_tag_update.eq(0),
If(deglitcher.detect,
self.h_tag_update.eq(1),
self.h_tag.eq(deglitcher.tag)
)
]

View File

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

View File

@ -26,7 +26,6 @@ import analyzer
import acpki
import drtio_aux_controller
import zynq_clocking
import wrpll
from config import write_csr_file, write_mem_file, write_rustc_cfg_file
eem_iostandard_dict = {
@ -109,7 +108,6 @@ class GenericStandalone(SoCCore):
def __init__(self, description, acpki=False):
self.acpki = acpki
clk_freq = description["rtio_frequency"]
with_wrpll = description["enable_wrpll"]
platform = kasli_soc.Platform()
platform.toolchain.bitstream_commands.extend([
@ -121,6 +119,13 @@ class GenericStandalone(SoCCore):
SoCCore.__init__(self, platform=platform, csr_data_width=32, ident=ident, ps_cd_sys=False)
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_se = Signal()
clk_synth_se_buf = Signal()
@ -144,23 +149,6 @@ class GenericStandalone(SoCCore):
self.crg = self.ps7 # HACK for eem_7series to find the clock
self.crg.cd_sys = self.sys_crg.cd_sys
if with_wrpll:
self.submodules.wrpll_refclk = wrpll.SMAFrequencyMultiplier(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 = []
has_grabber = any(peripheral["type"] == "grabber" for peripheral in description["peripherals"])
if has_grabber:
@ -219,7 +207,6 @@ class GenericStandalone(SoCCore):
class GenericMaster(SoCCore):
def __init__(self, description, acpki=False):
clk_freq = description["rtio_frequency"]
with_wrpll = description["enable_wrpll"]
has_drtio_over_eem = any(peripheral["type"] == "shuttler" for peripheral in description["peripherals"])
self.acpki = acpki
@ -235,6 +222,8 @@ class GenericMaster(SoCCore):
self.config["HW_REV"] = description["hw_rev"]
self.submodules += SMAClkinForward(self.platform)
data_pads = [platform.request("sfp", i) for i in range(4)]
self.submodules.gt_drtio = gtx_7series.GTX(
@ -248,16 +237,12 @@ class GenericMaster(SoCCore):
gtx0 = self.gt_drtio.gtxs[0]
self.specials += Instance("BUFG", i_I=gtx0.txoutclk, o_O=txout_buf)
ext_async_rst = Signal()
self.submodules.bootstrap = GTPBootstrapClock(self.platform, clk_freq)
self.submodules.sys_crg = zynq_clocking.SYSCRG(
self.platform,
self.ps7,
txout_buf,
clk_sw=self.gt_drtio.stable_clkin.storage,
clk_sw_status=gtx0.tx_init.done,
ext_async_rst=ext_async_rst)
clk_sw=gtx0.tx_init.done)
self.csr_devices.append("sys_crg")
self.crg = self.ps7 # HACK for eem_7series to find the clock
self.crg.cd_sys = self.sys_crg.cd_sys
@ -265,28 +250,8 @@ class GenericMaster(SoCCore):
self.bootstrap.cd_bootstrap.clk, self.sys_crg.cd_sys.clk)
fix_serdes_timing_path(platform)
self.comb += ext_async_rst.eq(self.sys_crg.clk_sw_fsm.o_clk_sw & ~gtx0.tx_init.done)
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:
clk_synth = platform.request("cdr_clk_clean_fabric")
clk_synth_se = Signal()
platform.add_period_constraint(clk_synth.p, 8.0)
self.specials += Instance("IBUFGDS", p_DIFF_TERM="TRUE", p_IBUF_LOW_PWR="FALSE", i_I=clk_synth.p, i_IB=clk_synth.n, o_O=clk_synth_se)
self.submodules.wrpll_refclk = wrpll.SMAFrequencyMultiplier(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.config["HAS_SI5324"] = None
self.config["SI5324_SOFT_RESET"] = None
self.rtio_channels = []
has_grabber = any(peripheral["type"] == "grabber" for peripheral in description["peripherals"])
@ -428,7 +393,6 @@ class GenericMaster(SoCCore):
class GenericSatellite(SoCCore):
def __init__(self, description, acpki=False):
clk_freq = description["rtio_frequency"]
with_wrpll = description["enable_wrpll"]
self.acpki = acpki
@ -455,16 +419,12 @@ class GenericSatellite(SoCCore):
gtx0 = self.gt_drtio.gtxs[0]
self.specials += Instance("BUFG", i_I=gtx0.txoutclk, o_O=txout_buf)
ext_async_rst = Signal()
self.submodules.bootstrap = GTPBootstrapClock(self.platform, clk_freq)
self.submodules.sys_crg = zynq_clocking.SYSCRG(
self.platform,
self.ps7,
txout_buf,
clk_sw=self.gt_drtio.stable_clkin.storage,
clk_sw_status=gtx0.tx_init.done,
ext_async_rst=ext_async_rst)
clk_sw=gtx0.tx_init.done)
platform.add_false_path_constraints(
self.bootstrap.cd_bootstrap.clk, self.sys_crg.cd_sys.clk)
self.csr_devices.append("sys_crg")
@ -473,9 +433,6 @@ class GenericSatellite(SoCCore):
fix_serdes_timing_path(platform)
self.comb += ext_async_rst.eq(self.sys_crg.clk_sw_fsm.o_clk_sw & ~gtx0.tx_init.done)
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.rtio_channels = []
has_grabber = any(peripheral["type"] == "grabber" for peripheral in description["peripherals"])
if has_grabber:
@ -580,30 +537,14 @@ class GenericSatellite(SoCCore):
self.config["RTIO_FREQUENCY"] = str(clk_freq/1e6)
self.config["CLOCK_FREQUENCY"] = int(clk_freq)
if with_wrpll:
clk_synth = platform.request("cdr_clk_clean_fabric")
clk_synth_se = Signal()
platform.add_period_constraint(clk_synth.p, 8.0)
self.specials += Instance("IBUFGDS", p_DIFF_TERM="TRUE", p_IBUF_LOW_PWR="FALSE", i_I=clk_synth.p, i_IB=clk_synth.n, o_O=clk_synth_se)
self.submodules.wrpll = wrpll.WRPLL(
platform=self.platform,
cd_ref=self.gt_drtio.cd_rtio_rx0,
main_clk_se=clk_synth_se)
self.submodules.wrpll_skewtester = wrpll.SkewTester(self.rx_synchronizer)
self.csr_devices.append("wrpll_skewtester")
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"] = "GT_CDR"
else:
self.submodules.siphaser = SiPhaser7Series(
si5324_clkin=platform.request("cdr_clk"),
rx_synchronizer=self.rx_synchronizer,
ultrascale=False,
rtio_clk_freq=self.gt_drtio.rtio_clk_freq)
self.csr_devices.append("siphaser")
self.config["HAS_SI5324"] = None
self.config["SI5324_SOFT_RESET"] = None
self.submodules.siphaser = SiPhaser7Series(
si5324_clkin=platform.request("cdr_clk"),
rx_synchronizer=self.rx_synchronizer,
ultrascale=False,
rtio_clk_freq=self.gt_drtio.rtio_clk_freq)
self.csr_devices.append("siphaser")
self.config["HAS_SI5324"] = None
self.config["SI5324_SOFT_RESET"] = None
gtx0 = self.gt_drtio.gtxs[0]
platform.add_false_path_constraints(

View File

@ -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),
)
]

View File

@ -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),
]

View File

@ -226,7 +226,6 @@ class _MasterBase(SoCCore):
self.csr_devices.append("gt_drtio")
self.submodules.rtio_tsc = rtio.TSC(glbl_fine_ts_width=3)
ext_async_rst = Signal()
txout_buf = Signal()
gtx0 = self.gt_drtio.gtxs[0]
self.specials += Instance("BUFG", i_I=gtx0.txoutclk, o_O=txout_buf)
@ -235,17 +234,12 @@ class _MasterBase(SoCCore):
self.platform,
self.ps7,
txout_buf,
clk_sw=self.gt_drtio.stable_clkin.storage,
clk_sw_status=gtx0.tx_init.done,
ext_async_rst=ext_async_rst,
clk_sw=gtx0.tx_init.done,
freq=clk_freq)
platform.add_false_path_constraints(
self.bootstrap.cd_bootstrap.clk, self.sys_crg.cd_sys.clk)
self.csr_devices.append("sys_crg")
self.comb += ext_async_rst.eq(self.sys_crg.clk_sw_fsm.o_clk_sw & ~gtx0.tx_init.done)
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")
drtio_csr_group = []
drtioaux_csr_group = []
drtioaux_memory_group = []
@ -367,7 +361,6 @@ class _SatelliteBase(SoCCore):
clk_freq=clk_freq)
self.csr_devices.append("gt_drtio")
ext_async_rst = Signal()
txout_buf = Signal()
txout_buf.attr.add("keep")
gtx0 = self.gt_drtio.gtxs[0]
@ -380,17 +373,12 @@ class _SatelliteBase(SoCCore):
self.platform,
self.ps7,
txout_buf,
clk_sw=self.gt_drtio.stable_clkin.storage,
clk_sw_status=gtx0.tx_init.done,
ext_async_rst=ext_async_rst,
clk_sw=gtx0.tx_init.done,
freq=clk_freq)
platform.add_false_path_constraints(
self.bootstrap.cd_bootstrap.clk, self.sys_crg.cd_sys.clk)
self.csr_devices.append("sys_crg")
self.comb += ext_async_rst.eq(self.sys_crg.clk_sw_fsm.o_clk_sw & ~gtx0.tx_init.done)
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")
drtioaux_csr_group = []
drtioaux_memory_group = []
drtiorep_csr_group = []

View File

@ -65,7 +65,7 @@ class ClockSwitchFSM(Module):
class SYSCRG(Module, AutoCSR):
def __init__(self, platform, ps7, main_clk, clk_sw=None, clk_sw_status=None, freq=125e6, ext_async_rst=None, ):
def __init__(self, platform, ps7, main_clk, clk_sw=None, freq=125e6):
# assumes bootstrap clock is same freq as main and sys output
self.clock_domains.cd_sys = ClockDomain()
self.clock_domains.cd_sys4x = ClockDomain(reset_less=True)
@ -88,7 +88,7 @@ class SYSCRG(Module, AutoCSR):
else:
self.comb += self.clk_sw_fsm.i_clk_sw.eq(clk_sw)
self.mmcm_locked = Signal()
mmcm_locked = Signal()
mmcm_sys = Signal()
mmcm_sys4x = Signal()
mmcm_sys5x = Signal()
@ -96,7 +96,7 @@ class SYSCRG(Module, AutoCSR):
mmcm_fb_clk = Signal()
self.specials += [
Instance("MMCME2_ADV",
p_STARTUP_WAIT="FALSE", o_LOCKED=self.mmcm_locked,
p_STARTUP_WAIT="FALSE", o_LOCKED=mmcm_locked,
p_BANDWIDTH="HIGH",
p_REF_JITTER1=0.001,
p_CLKIN1_PERIOD=period, i_CLKIN1=main_clk,
@ -125,19 +125,10 @@ class SYSCRG(Module, AutoCSR):
Instance("BUFG", i_I=mmcm_sys, o_O=self.cd_sys.clk),
Instance("BUFG", i_I=mmcm_sys4x, o_O=self.cd_sys4x.clk),
Instance("BUFG", i_I=mmcm_clk208, o_O=self.cd_clk200.clk),
AsyncResetSynchronizer(self.cd_sys, ~mmcm_locked),
AsyncResetSynchronizer(self.cd_clk200, ~mmcm_locked),
]
if ext_async_rst is not None:
self.specials += [
AsyncResetSynchronizer(self.cd_sys, ~self.mmcm_locked | ext_async_rst),
AsyncResetSynchronizer(self.cd_clk200, ~self.mmcm_locked | ext_async_rst),
]
else:
self.specials += [
AsyncResetSynchronizer(self.cd_sys, ~self.mmcm_locked),
AsyncResetSynchronizer(self.cd_clk200, ~self.mmcm_locked),
]
reset_counter = Signal(4, reset=15)
ic_reset = Signal(reset=1)
self.sync.clk200 += \
@ -148,7 +139,4 @@ class SYSCRG(Module, AutoCSR):
)
self.specials += Instance("IDELAYCTRL", i_REFCLK=ClockSignal("clk200"), i_RST=ic_reset)
if clk_sw_status is None:
self.comb += self.current_clock.status.eq(self.clk_sw_fsm.o_clk_sw)
else:
self.comb += self.current_clock.status.eq(clk_sw_status)
self.comb += self.current_clock.status.eq(self.clk_sw_fsm.o_clk_sw)

View File

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

View File

@ -74,15 +74,12 @@ where F: FnOnce(&[u8]) -> Result<T, Error> {
let linkidx = linkno as usize;
unsafe {
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 + read_ptr * 0x400) as *mut u32;
let ptr = (DRTIOAUX_MEM[linkidx].base + DRTIOAUX_MEM[linkidx].size / 2) as *mut u32;
let len = (DRTIOAUX[linkidx].aux_rx_length_read)() 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);
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);
Ok(Some(result?))
} else {
@ -103,15 +100,15 @@ pub fn recv(linkno: u8) -> Result<Option<Packet>, Error> {
let mut reader = Cursor::new(buffer);
let packet = Packet::read_from(&mut reader)?;
let padding = (12 - (reader.position() % 8)) % 8;
let checksum_at = reader.position() + padding;
let checksum_at = buffer.len() - 4;
let checksum = crc::crc32::checksum_ieee(&reader.get_ref()[0..checksum_at]);
reader.set_position(checksum_at);
if reader.read_u32()? != checksum {
return Err(Error::CorruptedPacket);
}
Ok(packet)
reader.set_position(0);
Ok(Packet::read_from(&mut reader)?)
})
}
@ -133,9 +130,10 @@ where F: FnOnce(&mut [u8]) -> Result<usize, Error> {
unsafe {
while (DRTIOAUX[linkno].aux_tx_read)() != 0 {}
let ptr = DRTIOAUX_MEM[linkno].base as *mut u32;
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)?;
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_write)(1);

View File

@ -38,15 +38,12 @@ where F: FnOnce(&[u8]) -> Result<T, Error> {
let linkidx = linkno as usize;
unsafe {
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 + read_ptr * 0x400) as *mut u32;
let ptr = (DRTIOAUX_MEM[linkidx].base + DRTIOAUX_MEM[linkidx].size / 2) as *mut u32;
let len = (DRTIOAUX[linkidx].aux_rx_length_read)() 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);
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);
Ok(Some(result?))
} else {
@ -67,15 +64,15 @@ pub async fn recv(linkno: u8) -> Result<Option<Packet>, Error> {
let mut reader = Cursor::new(buffer);
let packet = Packet::read_from(&mut reader)?;
let padding = (12 - (reader.position() % 8)) % 8;
let checksum_at = reader.position() + padding;
let checksum_at = buffer.len() - 4;
let checksum = crc::crc32::checksum_ieee(&reader.get_ref()[0..checksum_at]);
reader.set_position(checksum_at);
if reader.read_u32()? != checksum {
return Err(Error::CorruptedPacket);
}
Ok(packet)
reader.set_position(0);
Ok(Packet::read_from(&mut reader)?)
})
.await
}
@ -106,9 +103,10 @@ where F: FnOnce(&mut [u8]) -> Result<usize, Error> {
unsafe {
let _ = block_async!(tx_ready(linkno)).await;
let ptr = DRTIOAUX_MEM[linkno].base as *mut u32;
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)?;
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_write)(1);

View File

@ -5,7 +5,7 @@ use io::proto::{ProtoRead, ProtoWrite};
// 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;
// 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 - /*destination*/1 - /*ID*/4;
#[derive(Debug)]
pub enum Error {
@ -19,46 +19,6 @@ impl From<IoError> for Error {
}
}
#[derive(PartialEq, Clone, Copy, Debug)]
#[repr(u8)]
pub enum PayloadStatus {
Middle = 0,
First = 1,
Last = 2,
FirstAndLast = 3,
}
impl From<u8> for PayloadStatus {
fn from(value: u8) -> PayloadStatus {
match value {
0 => PayloadStatus::Middle,
1 => PayloadStatus::First,
2 => PayloadStatus::Last,
3 => PayloadStatus::FirstAndLast,
_ => unreachable!(),
}
}
}
impl PayloadStatus {
pub fn is_first(self) -> bool {
self == PayloadStatus::First || self == PayloadStatus::FirstAndLast
}
pub fn is_last(self) -> bool {
self == PayloadStatus::Last || self == PayloadStatus::FirstAndLast
}
pub fn from_status(first: bool, last: bool) -> PayloadStatus {
match (first, last) {
(true, true) => PayloadStatus::FirstAndLast,
(true, false) => PayloadStatus::First,
(false, true) => PayloadStatus::Last,
(false, false) => PayloadStatus::Middle,
}
}
}
#[derive(PartialEq, Debug)]
pub enum Packet {
EchoRequest,
@ -197,40 +157,31 @@ pub enum Packet {
},
DmaAddTraceRequest {
source: u8,
destination: u8,
id: u32,
status: PayloadStatus,
last: bool,
length: u16,
trace: [u8; MASTER_PAYLOAD_MAX_SIZE],
},
DmaAddTraceReply {
source: u8,
destination: u8,
id: u32,
succeeded: bool,
},
DmaRemoveTraceRequest {
source: u8,
destination: u8,
id: u32,
},
DmaRemoveTraceReply {
destination: u8,
succeeded: bool,
},
DmaPlaybackRequest {
source: u8,
destination: u8,
id: u32,
timestamp: u64,
},
DmaPlaybackReply {
destination: u8,
succeeded: bool,
},
DmaPlaybackStatus {
source: u8,
destination: u8,
id: u32,
error: u8,
@ -241,7 +192,7 @@ pub enum Packet {
SubkernelAddDataRequest {
destination: u8,
id: u32,
status: PayloadStatus,
last: bool,
length: u16,
data: [u8; MASTER_PAYLOAD_MAX_SIZE],
},
@ -249,20 +200,22 @@ pub enum Packet {
succeeded: bool,
},
SubkernelLoadRunRequest {
source: u8,
destination: u8,
id: u32,
run: bool,
},
SubkernelLoadRunReply {
succeeded: bool,
},
SubkernelStopRequest {
destination: u8,
},
SubkernelStopReply {
succeeded: bool,
},
SubkernelFinished {
destination: u8,
id: u32,
with_exception: bool,
exception_src: u8,
},
SubkernelExceptionRequest {
destination: u8,
@ -273,10 +226,9 @@ pub enum Packet {
data: [u8; SAT_PAYLOAD_MAX_SIZE],
},
SubkernelMessage {
source: u8,
destination: u8,
id: u32,
status: PayloadStatus,
last: bool,
length: u16,
data: [u8; MASTER_PAYLOAD_MAX_SIZE],
},
@ -437,49 +389,39 @@ impl Packet {
}
0xb0 => {
let source = reader.read_u8()?;
let destination = reader.read_u8()?;
let id = reader.read_u32()?;
let status = reader.read_u8()?;
let last = reader.read_bool()?;
let length = reader.read_u16()?;
let mut trace: [u8; MASTER_PAYLOAD_MAX_SIZE] = [0; MASTER_PAYLOAD_MAX_SIZE];
reader.read_exact(&mut trace[0..length as usize])?;
Packet::DmaAddTraceRequest {
source: source,
destination: destination,
id: id,
status: PayloadStatus::from(status),
last: last,
length: length as u16,
trace: trace,
}
}
0xb1 => Packet::DmaAddTraceReply {
source: reader.read_u8()?,
destination: reader.read_u8()?,
id: reader.read_u32()?,
succeeded: reader.read_bool()?,
},
0xb2 => Packet::DmaRemoveTraceRequest {
source: reader.read_u8()?,
destination: reader.read_u8()?,
id: reader.read_u32()?,
},
0xb3 => Packet::DmaRemoveTraceReply {
destination: reader.read_u8()?,
succeeded: reader.read_bool()?,
},
0xb4 => Packet::DmaPlaybackRequest {
source: reader.read_u8()?,
destination: reader.read_u8()?,
id: reader.read_u32()?,
timestamp: reader.read_u64()?,
},
0xb5 => Packet::DmaPlaybackReply {
destination: reader.read_u8()?,
succeeded: reader.read_bool()?,
},
0xb6 => Packet::DmaPlaybackStatus {
source: reader.read_u8()?,
destination: reader.read_u8()?,
id: reader.read_u32()?,
error: reader.read_u8()?,
@ -490,14 +432,14 @@ impl Packet {
0xc0 => {
let destination = reader.read_u8()?;
let id = reader.read_u32()?;
let status = PayloadStatus::from(reader.read_u8()?);
let last = reader.read_bool()?;
let length = reader.read_u16()?;
let mut data: [u8; MASTER_PAYLOAD_MAX_SIZE] = [0; MASTER_PAYLOAD_MAX_SIZE];
reader.read_exact(&mut data[0..length as usize])?;
Packet::SubkernelAddDataRequest {
destination: destination,
id: id,
status: status,
last: last,
length: length as u16,
data: data,
}
@ -506,20 +448,22 @@ impl Packet {
succeeded: reader.read_bool()?,
},
0xc4 => Packet::SubkernelLoadRunRequest {
source: reader.read_u8()?,
destination: reader.read_u8()?,
id: reader.read_u32()?,
run: reader.read_bool()?,
},
0xc5 => Packet::SubkernelLoadRunReply {
succeeded: reader.read_bool()?,
},
0xc6 => Packet::SubkernelStopRequest {
destination: reader.read_u8()?,
},
0xc7 => Packet::SubkernelStopReply {
succeeded: reader.read_bool()?,
},
0xc8 => Packet::SubkernelFinished {
destination: reader.read_u8()?,
id: reader.read_u32()?,
with_exception: reader.read_bool()?,
exception_src: reader.read_u8()?,
},
0xc9 => Packet::SubkernelExceptionRequest {
destination: reader.read_u8()?,
@ -536,18 +480,16 @@ impl Packet {
}
}
0xcb => {
let source = reader.read_u8()?;
let destination = reader.read_u8()?;
let id = reader.read_u32()?;
let status = reader.read_u8()?;
let last = reader.read_bool()?;
let length = reader.read_u16()?;
let mut data: [u8; MASTER_PAYLOAD_MAX_SIZE] = [0; MASTER_PAYLOAD_MAX_SIZE];
reader.read_exact(&mut data[0..length as usize])?;
Packet::SubkernelMessage {
source: source,
destination: destination,
id: id,
status: PayloadStatus::from(status),
last: last,
length: length as u16,
data: data,
}
@ -769,69 +711,49 @@ impl Packet {
}
Packet::DmaAddTraceRequest {
source,
destination,
id,
status,
last,
trace,
length,
} => {
writer.write_u8(0xb0)?;
writer.write_u8(source)?;
writer.write_u8(destination)?;
writer.write_u32(id)?;
writer.write_u8(status as u8)?;
writer.write_bool(last)?;
// trace may be broken down to fit within drtio aux memory limit
// will be reconstructed by satellite
writer.write_u16(length)?;
writer.write_all(&trace[0..length as usize])?;
}
Packet::DmaAddTraceReply {
source,
destination,
id,
succeeded,
} => {
Packet::DmaAddTraceReply { succeeded } => {
writer.write_u8(0xb1)?;
writer.write_u8(source)?;
writer.write_u8(destination)?;
writer.write_u32(id)?;
writer.write_bool(succeeded)?;
}
Packet::DmaRemoveTraceRequest {
source,
destination,
id,
} => {
Packet::DmaRemoveTraceRequest { destination, id } => {
writer.write_u8(0xb2)?;
writer.write_u8(source)?;
writer.write_u8(destination)?;
writer.write_u32(id)?;
}
Packet::DmaRemoveTraceReply { destination, succeeded } => {
Packet::DmaRemoveTraceReply { succeeded } => {
writer.write_u8(0xb3)?;
writer.write_u8(destination)?;
writer.write_bool(succeeded)?;
}
Packet::DmaPlaybackRequest {
source,
destination,
id,
timestamp,
} => {
writer.write_u8(0xb4)?;
writer.write_u8(source)?;
writer.write_u8(destination)?;
writer.write_u32(id)?;
writer.write_u64(timestamp)?;
}
Packet::DmaPlaybackReply { destination, succeeded } => {
Packet::DmaPlaybackReply { succeeded } => {
writer.write_u8(0xb5)?;
writer.write_u8(destination)?;
writer.write_bool(succeeded)?;
}
Packet::DmaPlaybackStatus {
source,
destination,
id,
error,
@ -839,7 +761,6 @@ impl Packet {
timestamp,
} => {
writer.write_u8(0xb6)?;
writer.write_u8(source)?;
writer.write_u8(destination)?;
writer.write_u32(id)?;
writer.write_u8(error)?;
@ -850,14 +771,14 @@ impl Packet {
Packet::SubkernelAddDataRequest {
destination,
id,
status,
last,
data,
length,
} => {
writer.write_u8(0xc0)?;
writer.write_u8(destination)?;
writer.write_u32(id)?;
writer.write_u8(status as u8)?;
writer.write_bool(last)?;
writer.write_u16(length)?;
writer.write_all(&data[0..length as usize])?;
}
@ -865,34 +786,28 @@ impl Packet {
writer.write_u8(0xc1)?;
writer.write_bool(succeeded)?;
}
Packet::SubkernelLoadRunRequest {
source,
destination,
id,
run,
} => {
Packet::SubkernelLoadRunRequest { destination, id, run } => {
writer.write_u8(0xc4)?;
writer.write_u8(source)?;
writer.write_u8(destination)?;
writer.write_u32(id)?;
writer.write_bool(run)?;
}
Packet::SubkernelLoadRunReply { destination, succeeded } => {
Packet::SubkernelLoadRunReply { succeeded } => {
writer.write_u8(0xc5)?;
writer.write_u8(destination)?;
writer.write_bool(succeeded)?;
}
Packet::SubkernelFinished {
destination,
id,
with_exception,
exception_src,
} => {
writer.write_u8(0xc8)?;
Packet::SubkernelStopRequest { destination } => {
writer.write_u8(0xc6)?;
writer.write_u8(destination)?;
}
Packet::SubkernelStopReply { succeeded } => {
writer.write_u8(0xc7)?;
writer.write_bool(succeeded)?;
}
Packet::SubkernelFinished { id, with_exception } => {
writer.write_u8(0xc8)?;
writer.write_u32(id)?;
writer.write_bool(with_exception)?;
writer.write_u8(exception_src)?;
}
Packet::SubkernelExceptionRequest { destination } => {
writer.write_u8(0xc9)?;
@ -905,18 +820,16 @@ impl Packet {
writer.write_all(&data[0..length as usize])?;
}
Packet::SubkernelMessage {
source,
destination,
id,
status,
last,
data,
length,
} => {
writer.write_u8(0xcb)?;
writer.write_u8(source)?;
writer.write_u8(destination)?;
writer.write_u32(id)?;
writer.write_u8(status as u8)?;
writer.write_bool(last)?;
writer.write_u16(length)?;
writer.write_all(&data[0..length as usize])?;
}
@ -927,39 +840,4 @@ impl Packet {
}
Ok(())
}
pub fn routable_destination(&self) -> Option<u8> {
// only for packets that could be re-routed, not only forwarded
match self {
Packet::DmaAddTraceRequest { destination, .. } => Some(*destination),
Packet::DmaAddTraceReply { destination, .. } => Some(*destination),
Packet::DmaRemoveTraceRequest { destination, .. } => Some(*destination),
Packet::DmaRemoveTraceReply { destination, .. } => Some(*destination),
Packet::DmaPlaybackRequest { destination, .. } => Some(*destination),
Packet::DmaPlaybackReply { destination, .. } => Some(*destination),
Packet::SubkernelLoadRunRequest { destination, .. } => Some(*destination),
Packet::SubkernelLoadRunReply { destination, .. } => Some(*destination),
Packet::SubkernelMessage { destination, .. } => Some(*destination),
Packet::SubkernelMessageAck { destination } => Some(*destination),
Packet::DmaPlaybackStatus { destination, .. } => Some(*destination),
Packet::SubkernelFinished { destination, .. } => Some(*destination),
_ => None,
}
}
pub fn expects_response(&self) -> bool {
// returns true if the routable packet should elicit a response
// e.g. reply, ACK packets end a conversation,
// and firmware should not wait for response
match self {
Packet::DmaAddTraceReply { .. }
| Packet::DmaRemoveTraceReply { .. }
| Packet::DmaPlaybackReply { .. }
| Packet::SubkernelLoadRunReply { .. }
| Packet::SubkernelMessageAck { .. }
| Packet::DmaPlaybackStatus { .. }
| Packet::SubkernelFinished { .. } => false,
_ => true,
}
}
}

View File

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

View File

@ -1,7 +1,6 @@
use libboard_zynq::i2c;
use log::info;
#[cfg(has_virtual_leds)]
use crate::pl::csr;
// Only the bare minimum registers. Bits/IO connections equivalent between IC types.
@ -20,15 +19,11 @@ const IODIR_OUT_SFP_LED: u8 = 0x40;
const IODIR_OUT_SFP0_LED: u8 = 0x40;
#[cfg(hw_rev = "v1.1")]
const IODIR_OUT_SFP0_LED: u8 = 0x80;
#[cfg(has_si549)]
const IODIR_CLK_SEL: u8 = 0x80; // out
#[cfg(has_si5324)]
const IODIR_CLK_SEL: u8 = 0x00; // in
//IO expander port direction
const IODIR0: [u8; 2] = [
0xFF & !IODIR_OUT_SFP_TX_DISABLE & !IODIR_OUT_SFP0_LED,
0xFF & !IODIR_OUT_SFP_TX_DISABLE & !IODIR_OUT_SFP_LED & !IODIR_CLK_SEL,
0xFF & !IODIR_OUT_SFP_TX_DISABLE & !IODIR_OUT_SFP_LED,
];
const IODIR1: [u8; 2] = [
@ -38,7 +33,6 @@ const IODIR1: [u8; 2] = [
pub struct IoExpander {
address: u8,
#[cfg(has_virtual_leds)]
virtual_led_mapping: &'static [(u8, u8, u8)],
iodir: [u8; 2],
out_current: [u8; 2],
@ -48,18 +42,17 @@ pub struct IoExpander {
impl IoExpander {
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)];
#[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)];
#[cfg(has_virtual_leds)]
const VIRTUAL_LED_MAPPING1: [(u8, u8, u8); 2] = [(2, 0, 6), (3, 1, 6)];
// Both expanders on SHARED I2C bus
let mut io_expander = match index {
0 => IoExpander {
address: 0x40,
#[cfg(has_virtual_leds)]
virtual_led_mapping: &VIRTUAL_LED_MAPPING0,
iodir: IODIR0,
out_current: [0; 2],
@ -73,7 +66,6 @@ impl IoExpander {
},
1 => IoExpander {
address: 0x42,
#[cfg(has_virtual_leds)]
virtual_led_mapping: &VIRTUAL_LED_MAPPING1,
iodir: IODIR1,
out_current: [0; 2],

View File

@ -1,7 +1,5 @@
#![no_std]
#![feature(never_type)]
#![feature(naked_functions)]
#![feature(asm)]
extern crate core_io;
extern crate crc;
@ -21,7 +19,6 @@ pub mod drtioaux;
#[cfg(has_drtio)]
pub mod drtioaux_async;
pub mod drtioaux_proto;
pub mod fiq;
#[cfg(feature = "target_kasli_soc")]
pub mod io_expander;
pub mod logger;
@ -38,8 +35,7 @@ pub mod drtio_eem;
pub mod grabber;
#[cfg(has_si5324)]
pub mod si5324;
#[cfg(has_si549)]
pub mod si549;
use core::{cmp, str};
pub fn identifier_read(buf: &mut [u8]) -> &str {

View File

@ -1,816 +0,0 @@
use embedded_hal::prelude::_embedded_hal_blocking_delay_DelayUs;
use libboard_zynq::timer::GlobalTimer;
use log::info;
use crate::pl::csr;
#[cfg(feature = "target_kasli_soc")]
const ADDRESS: u8 = 0x67;
const ADPLL_MAX: i32 = (950.0 / 0.0001164) as i32;
pub struct DividerConfig {
pub hsdiv: u16,
pub lsdiv: u8,
pub fbdiv: u64,
}
pub struct FrequencySetting {
pub main: DividerConfig,
pub helper: DividerConfig,
}
mod i2c {
use super::*;
#[derive(Clone, Copy)]
pub enum DCXO {
Main,
Helper,
}
fn half_period(timer: &mut GlobalTimer) {
timer.delay_us(1)
}
fn sda_i(dcxo: DCXO) -> bool {
match dcxo {
DCXO::Main => unsafe { csr::wrpll::main_dcxo_sda_in_read() == 1 },
DCXO::Helper => unsafe { csr::wrpll::helper_dcxo_sda_in_read() == 1 },
}
}
fn sda_oe(dcxo: DCXO, oe: bool) {
let val = if oe { 1 } else { 0 };
match dcxo {
DCXO::Main => unsafe { csr::wrpll::main_dcxo_sda_oe_write(val) },
DCXO::Helper => unsafe { csr::wrpll::helper_dcxo_sda_oe_write(val) },
};
}
fn sda_o(dcxo: DCXO, o: bool) {
let val = if o { 1 } else { 0 };
match dcxo {
DCXO::Main => unsafe { csr::wrpll::main_dcxo_sda_out_write(val) },
DCXO::Helper => unsafe { csr::wrpll::helper_dcxo_sda_out_write(val) },
};
}
fn scl_oe(dcxo: DCXO, oe: bool) {
let val = if oe { 1 } else { 0 };
match dcxo {
DCXO::Main => unsafe { csr::wrpll::main_dcxo_scl_oe_write(val) },
DCXO::Helper => unsafe { csr::wrpll::helper_dcxo_scl_oe_write(val) },
};
}
fn scl_o(dcxo: DCXO, o: bool) {
let val = if o { 1 } else { 0 };
match dcxo {
DCXO::Main => unsafe { csr::wrpll::main_dcxo_scl_out_write(val) },
DCXO::Helper => unsafe { csr::wrpll::helper_dcxo_scl_out_write(val) },
};
}
pub fn init(dcxo: DCXO, timer: &mut GlobalTimer) -> Result<(), &'static str> {
// Set SCL as output, and high level
scl_o(dcxo, true);
scl_oe(dcxo, true);
// Prepare a zero level on SDA so that sda_oe pulls it down
sda_o(dcxo, false);
// Release SDA
sda_oe(dcxo, false);
// Check the I2C bus is ready
half_period(timer);
half_period(timer);
if !sda_i(dcxo) {
// Try toggling SCL a few times
for _bit in 0..8 {
scl_o(dcxo, false);
half_period(timer);
scl_o(dcxo, true);
half_period(timer);
}
}
if !sda_i(dcxo) {
return Err("SDA is stuck low and doesn't get unstuck");
}
Ok(())
}
pub fn start(dcxo: DCXO, timer: &mut GlobalTimer) {
// Set SCL high then SDA low
scl_o(dcxo, true);
half_period(timer);
sda_oe(dcxo, true);
half_period(timer);
}
pub fn stop(dcxo: DCXO, timer: &mut GlobalTimer) {
// First, make sure SCL is low, so that the target releases the SDA line
scl_o(dcxo, false);
half_period(timer);
// Set SCL high then SDA high
sda_oe(dcxo, true);
scl_o(dcxo, true);
half_period(timer);
sda_oe(dcxo, false);
half_period(timer);
}
pub fn write(dcxo: DCXO, data: u8, timer: &mut GlobalTimer) -> bool {
// MSB first
for bit in (0..8).rev() {
// Set SCL low and set our bit on SDA
scl_o(dcxo, false);
sda_oe(dcxo, data & (1 << bit) == 0);
half_period(timer);
// Set SCL high ; data is shifted on the rising edge of SCL
scl_o(dcxo, true);
half_period(timer);
}
// Check ack
// Set SCL low, then release SDA so that the I2C target can respond
scl_o(dcxo, false);
half_period(timer);
sda_oe(dcxo, false);
// Set SCL high and check for ack
scl_o(dcxo, true);
half_period(timer);
// returns true if acked (I2C target pulled SDA low)
!sda_i(dcxo)
}
pub fn read(dcxo: DCXO, ack: bool, timer: &mut GlobalTimer) -> u8 {
// Set SCL low first, otherwise setting SDA as input may cause a transition
// on SDA with SCL high which will be interpreted as START/STOP condition.
scl_o(dcxo, false);
half_period(timer); // make sure SCL has settled low
sda_oe(dcxo, false);
let mut data: u8 = 0;
// MSB first
for bit in (0..8).rev() {
scl_o(dcxo, false);
half_period(timer);
// Set SCL high and shift data
scl_o(dcxo, true);
half_period(timer);
if sda_i(dcxo) {
data |= 1 << bit
}
}
// Send ack
// Set SCL low and pull SDA low when acking
scl_o(dcxo, false);
if ack {
sda_oe(dcxo, true)
}
half_period(timer);
// then set SCL high
scl_o(dcxo, true);
half_period(timer);
data
}
}
fn write(dcxo: i2c::DCXO, reg: u8, val: u8, timer: &mut GlobalTimer) -> Result<(), &'static str> {
i2c::start(dcxo, timer);
if !i2c::write(dcxo, ADDRESS << 1, timer) {
return Err("Si549 failed to ack write address");
}
if !i2c::write(dcxo, reg, timer) {
return Err("Si549 failed to ack register");
}
if !i2c::write(dcxo, val, timer) {
return Err("Si549 failed to ack value");
}
i2c::stop(dcxo, timer);
Ok(())
}
fn read(dcxo: i2c::DCXO, reg: u8, timer: &mut GlobalTimer) -> Result<u8, &'static str> {
i2c::start(dcxo, timer);
if !i2c::write(dcxo, ADDRESS << 1, timer) {
return Err("Si549 failed to ack write address");
}
if !i2c::write(dcxo, reg, timer) {
return Err("Si549 failed to ack register");
}
i2c::stop(dcxo, timer);
i2c::start(dcxo, timer);
if !i2c::write(dcxo, (ADDRESS << 1) | 1, timer) {
return Err("Si549 failed to ack read address");
}
let val = i2c::read(dcxo, false, timer);
i2c::stop(dcxo, timer);
Ok(val)
}
fn setup(dcxo: i2c::DCXO, config: &DividerConfig, timer: &mut GlobalTimer) -> Result<(), &'static str> {
i2c::init(dcxo, timer)?;
write(dcxo, 255, 0x00, timer)?; // PAGE
write(dcxo, 69, 0x00, timer)?; // Disable FCAL override.
write(dcxo, 17, 0x00, timer)?; // Synchronously disable output
// The Si549 has no ID register, so we check that it responds correctly
// by writing values to a RAM-like register and reading them back.
for test_value in 0..255 {
write(dcxo, 23, test_value, timer)?;
let readback = read(dcxo, 23, timer)?;
if readback != test_value {
return Err("Si549 detection failed");
}
}
write(dcxo, 23, config.hsdiv as u8, timer)?;
write(dcxo, 24, (config.hsdiv >> 8) as u8 | (config.lsdiv << 4), timer)?;
write(dcxo, 26, config.fbdiv as u8, timer)?;
write(dcxo, 27, (config.fbdiv >> 8) as u8, timer)?;
write(dcxo, 28, (config.fbdiv >> 16) as u8, timer)?;
write(dcxo, 29, (config.fbdiv >> 24) as u8, timer)?;
write(dcxo, 30, (config.fbdiv >> 32) as u8, timer)?;
write(dcxo, 31, (config.fbdiv >> 40) as u8, timer)?;
write(dcxo, 7, 0x08, timer)?; // Start FCAL
timer.delay_us(30_000); // Internal FCAL VCO calibration
write(dcxo, 17, 0x01, timer)?; // Synchronously enable output
Ok(())
}
pub fn main_setup(timer: &mut GlobalTimer, settings: &FrequencySetting) -> Result<(), &'static str> {
unsafe {
csr::wrpll::main_dcxo_bitbang_enable_write(1);
csr::wrpll::main_dcxo_i2c_address_write(ADDRESS);
}
setup(i2c::DCXO::Main, &settings.main, timer)?;
// Si549 maximum settling time for large frequency change.
timer.delay_us(40_000);
unsafe {
csr::wrpll::main_dcxo_bitbang_enable_write(0);
}
info!("Main Si549 started");
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)]
pub mod wrpll {
use super::*;
const BEATING_PERIOD: i32 = 0x8000;
const BEATING_HALFPERIOD: i32 = 0x4000;
const COUNTER_WIDTH: u32 = 24;
const DIV_WIDTH: u32 = 2;
const KP: i32 = 6;
const KI: i32 = 2;
// 4 ppm capture range
const ADPLL_LIM: i32 = (4.0 / 0.0001164) as i32;
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)]
pub enum ISR {
RefTag,
MainTag,
}
mod tag_collector {
use super::*;
#[cfg(wrpll_ref_clk = "GT_CDR")]
static mut TAG_OFFSET: u32 = 8382;
#[cfg(wrpll_ref_clk = "SMA_CLKIN")]
static mut TAG_OFFSET: u32 = 0;
static mut REF_TAG: u32 = 0;
static mut REF_TAG_READY: bool = false;
static mut MAIN_TAG: u32 = 0;
static mut MAIN_TAG_READY: bool = false;
pub fn reset() {
clear_phase_diff_ready();
unsafe {
REF_TAG = 0;
MAIN_TAG = 0;
}
}
pub fn clear_phase_diff_ready() {
unsafe {
REF_TAG_READY = false;
MAIN_TAG_READY = false;
}
}
pub fn collect_tags(interrupt: ISR) {
match interrupt {
ISR::RefTag => unsafe {
REF_TAG = csr::wrpll::ref_tag_read();
REF_TAG_READY = true;
},
ISR::MainTag => unsafe {
MAIN_TAG = csr::wrpll::main_tag_read();
MAIN_TAG_READY = true;
},
}
}
pub fn phase_diff_ready() -> bool {
unsafe { REF_TAG_READY && MAIN_TAG_READY }
}
#[cfg(feature = "calibrate_wrpll_skew")]
pub fn set_tag_offset(offset: u32) {
unsafe {
TAG_OFFSET = offset;
}
}
#[cfg(feature = "calibrate_wrpll_skew")]
pub fn get_tag_offset() -> u32 {
unsafe { TAG_OFFSET }
}
pub fn get_period_error() -> i32 {
// 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 };
// mapping tags from [0, 2π] -> [-π, π]
if period_error > BEATING_HALFPERIOD {
period_error -= BEATING_PERIOD
}
period_error
}
pub fn get_phase_error() -> i32 {
// MAIN_TAG(n) - REF_TAG(n) - TAG_OFFSET mod BEATING_PERIOD
let mut phase_error = unsafe {
MAIN_TAG
.overflowing_sub(REF_TAG + TAG_OFFSET)
.0
.rem_euclid(BEATING_PERIOD as u32) as i32
};
// mapping tags from [0, 2π] -> [-π, π]
if phase_error > BEATING_HALFPERIOD {
phase_error -= BEATING_PERIOD
}
phase_error
}
}
fn set_isr(en: bool) {
let val = if en { 1 } else { 0 };
unsafe {
csr::wrpll::ref_tag_ev_enable_write(val);
csr::wrpll::main_tag_ev_enable_write(val);
}
}
fn set_base_adpll() -> Result<(), &'static str> {
let count2adpll =
|error: i32| ((error as f64 * 1e6) / (0.0001164 * (1 << (COUNTER_WIDTH - DIV_WIDTH)) as f64)) as i32;
let (ref_count, main_count) = get_freq_counts();
unsafe {
BASE_ADPLL = count2adpll(ref_count as i32 - main_count as i32);
set_adpll(i2c::DCXO::Main, BASE_ADPLL)?;
set_adpll(i2c::DCXO::Helper, BASE_ADPLL)?;
}
Ok(())
}
fn get_freq_counts() -> (u32, u32) {
unsafe {
csr::wrpll::frequency_counter_update_write(1);
while csr::wrpll::frequency_counter_busy_read() == 1 {}
#[cfg(wrpll_ref_clk = "GT_CDR")]
let ref_count = csr::wrpll::frequency_counter_counter_rtio_rx0_read();
#[cfg(wrpll_ref_clk = "SMA_CLKIN")]
let ref_count = csr::wrpll::frequency_counter_counter_ref_read();
let main_count = csr::wrpll::frequency_counter_counter_sys_read();
(ref_count, main_count)
}
}
fn reset_plls(timer: &mut GlobalTimer) -> Result<(), &'static str> {
unsafe {
H_LAST_ADPLL = 0;
LAST_PERIOD_ERR = 0;
M_LAST_ADPLL = 0;
LAST_PHASE_ERR = 0;
}
set_adpll(i2c::DCXO::Main, 0)?;
set_adpll(i2c::DCXO::Helper, 0)?;
// wait for adpll to transfer and DCXO to settle
timer.delay_us(200);
Ok(())
}
fn clear_pending(interrupt: ISR) {
match interrupt {
ISR::RefTag => unsafe { csr::wrpll::ref_tag_ev_pending_write(1) },
ISR::MainTag => unsafe { csr::wrpll::main_tag_ev_pending_write(1) },
};
}
fn is_pending(interrupt: ISR) -> bool {
match interrupt {
ISR::RefTag => unsafe { csr::wrpll::ref_tag_ev_pending_read() == 1 },
ISR::MainTag => unsafe { csr::wrpll::main_tag_ev_pending_read() == 1 },
}
}
pub fn interrupt_handler() {
if is_pending(ISR::RefTag) {
tag_collector::collect_tags(ISR::RefTag);
clear_pending(ISR::RefTag);
helper_pll().expect("failed to run helper DCXO PLL");
}
if is_pending(ISR::MainTag) {
tag_collector::collect_tags(ISR::MainTag);
clear_pending(ISR::MainTag);
}
if tag_collector::phase_diff_ready() {
main_pll().expect("failed to run main DCXO PLL");
tag_collector::clear_phase_diff_ready();
}
}
fn helper_pll() -> Result<(), &'static str> {
let period_err = tag_collector::get_period_error();
unsafe {
// Based on https://hackmd.io/IACbwcOTSt6Adj3_F9bKuw?view#Integral-wind-up-and-output-limiting
let adpll = (H_LAST_ADPLL + (KP + KI) * period_err - KP * LAST_PERIOD_ERR).clamp(-ADPLL_LIM, ADPLL_LIM);
set_adpll(i2c::DCXO::Helper, BASE_ADPLL + adpll)?;
H_LAST_ADPLL = adpll;
LAST_PERIOD_ERR = period_err;
};
Ok(())
}
fn main_pll() -> Result<(), &'static str> {
let phase_err = tag_collector::get_phase_error();
unsafe {
// Based on https://hackmd.io/IACbwcOTSt6Adj3_F9bKuw?view#Integral-wind-up-and-output-limiting
let adpll = (M_LAST_ADPLL + (KP + KI) * phase_err - KP * LAST_PHASE_ERR).clamp(-ADPLL_LIM, ADPLL_LIM);
set_adpll(i2c::DCXO::Main, BASE_ADPLL + adpll)?;
M_LAST_ADPLL = adpll;
LAST_PHASE_ERR = 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(())
}
pub fn select_recovered_clock(rc: bool, timer: &mut GlobalTimer) {
set_isr(false);
if rc {
tag_collector::reset();
reset_plls(timer).expect("failed to reset main and helper PLL");
// get within capture range
set_base_adpll().expect("failed to set base adpll");
// clear gateware pending flag
clear_pending(ISR::RefTag);
clear_pending(ISR::MainTag);
// use nFIQ to avoid IRQ being disabled by mutex lock and mess up PLL
set_isr(true);
info!("WRPLL interrupt enabled");
#[cfg(feature = "calibrate_wrpll_skew")]
calibrate_skew(timer).expect("failed to set the correct skew");
#[cfg(wrpll_ref_clk = "GT_CDR")]
test_skew(timer).expect("skew test failed");
}
}
}
#[cfg(has_wrpll_refclk)]
pub mod wrpll_refclk {
use super::*;
pub struct MmcmSetting {
pub clkout0_reg1: u16, //0x08
pub clkout0_reg2: u16, //0x09
pub clkfbout_reg1: u16, //0x14
pub clkfbout_reg2: u16, //0x15
pub div_reg: u16, //0x16
pub lock_reg1: u16, //0x18
pub lock_reg2: u16, //0x19
pub lock_reg3: u16, //0x1A
pub power_reg: u16, //0x28
pub filt_reg1: u16, //0x4E
pub filt_reg2: u16, //0x4F
}
fn one_clock_cycle() {
unsafe {
csr::wrpll_refclk::mmcm_dclk_write(1);
csr::wrpll_refclk::mmcm_dclk_write(0);
}
}
fn set_addr(address: u8) {
unsafe {
csr::wrpll_refclk::mmcm_daddr_write(address);
}
}
fn set_data(value: u16) {
unsafe {
csr::wrpll_refclk::mmcm_din_write(value);
}
}
fn set_enable(en: bool) {
unsafe {
let val = if en { 1 } else { 0 };
csr::wrpll_refclk::mmcm_den_write(val);
}
}
fn set_write_enable(en: bool) {
unsafe {
let val = if en { 1 } else { 0 };
csr::wrpll_refclk::mmcm_dwen_write(val);
}
}
fn get_data() -> u16 {
unsafe { csr::wrpll_refclk::mmcm_dout_read() }
}
fn drp_ready() -> bool {
unsafe { csr::wrpll_refclk::mmcm_dready_read() == 1 }
}
#[allow(dead_code)]
fn read(address: u8) -> u16 {
set_addr(address);
set_enable(true);
// Set DADDR on the mmcm and assert DEN for one clock cycle
one_clock_cycle();
set_enable(false);
while !drp_ready() {
// keep the clock signal until data is ready
one_clock_cycle();
}
get_data()
}
fn write(address: u8, value: u16) {
set_addr(address);
set_data(value);
set_write_enable(true);
set_enable(true);
// Set DADDR, DI on the mmcm and assert DWE, DEN for one clock cycle
one_clock_cycle();
set_write_enable(false);
set_enable(false);
while !drp_ready() {
// keep the clock signal until write is finished
one_clock_cycle();
}
}
fn reset(rst: bool) {
unsafe {
let val = if rst { 1 } else { 0 };
csr::wrpll_refclk::mmcm_reset_write(val)
}
}
pub fn setup(timer: &mut GlobalTimer, settings: MmcmSetting, mmcm_bypass: bool) -> 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
// hold reset HIGH during mmcm config
reset(true);
write(0x08, settings.clkout0_reg1);
write(0x09, settings.clkout0_reg2);
write(0x14, settings.clkfbout_reg1);
write(0x15, settings.clkfbout_reg2);
write(0x16, settings.div_reg);
write(0x18, settings.lock_reg1);
write(0x19, settings.lock_reg2);
write(0x1A, settings.lock_reg3);
write(0x28, settings.power_reg);
write(0x4E, settings.filt_reg1);
write(0x4F, settings.filt_reg2);
reset(false);
// wait for the mmcm to lock
timer.delay_us(100);
let locked = unsafe { csr::wrpll_refclk::mmcm_locked_read() == 1 };
if !locked {
return Err("mmcm failed to generate 125MHz ref clock from SMA CLKIN");
}
}
unsafe {
csr::wrpll_refclk::refclk_reset_write(0);
}
Ok(())
}
}

View File

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

View File

@ -170,7 +170,6 @@ pub extern "C" fn dma_playback(timestamp: i64, ptr: i32, _uses_ddma: bool) {
csr::rtio_dma::base_address_write(ptr as u32);
csr::rtio_dma::time_offset_write(timestamp as u64);
let old_cri_master = csr::cri_con::selected_read();
csr::cri_con::selected_write(1);
csr::rtio_dma::enable_write(1);
#[cfg(has_drtio)]
@ -184,7 +183,7 @@ pub extern "C" fn dma_playback(timestamp: i64, ptr: i32, _uses_ddma: bool) {
});
}
while csr::rtio_dma::enable_read() != 0 {}
csr::cri_con::selected_write(old_cri_master);
csr::cri_con::selected_write(0);
let error = csr::rtio_dma::error_read();
if error != 0 {

View File

@ -77,7 +77,6 @@ pub enum Message {
#[cfg(has_drtio)]
SubkernelLoadRunRequest {
id: u32,
destination: u8,
run: bool,
},
#[cfg(has_drtio)]
@ -87,7 +86,7 @@ pub enum Message {
#[cfg(has_drtio)]
SubkernelAwaitFinishRequest {
id: u32,
timeout: i64,
timeout: u64,
},
#[cfg(has_drtio)]
SubkernelAwaitFinishReply {
@ -96,16 +95,14 @@ pub enum Message {
#[cfg(has_drtio)]
SubkernelMsgSend {
id: u32,
destination: Option<u8>,
data: Vec<u8>,
},
#[cfg(has_drtio)]
SubkernelMsgSent,
#[cfg(has_drtio)]
SubkernelMsgRecvRequest {
id: i32,
timeout: i64,
tags: Vec<u8>,
id: u32,
timeout: u64,
},
#[cfg(has_drtio)]
SubkernelMsgRecvReply {

View File

@ -10,7 +10,7 @@ use crate::{eh_artiq, rpc::send_args};
fn rpc_send_common(is_async: bool, service: u32, tag: &CSlice<u8>, data: *const *const ()) {
let core1_tx = unsafe { KERNEL_CHANNEL_1TO0.as_mut().unwrap() };
let mut buffer = Vec::<u8>::new();
send_args(&mut buffer, service, tag.as_ref(), data, true).expect("RPC encoding failed");
send_args(&mut buffer, service, tag.as_ref(), data).expect("RPC encoding failed");
core1_tx.send(Message::RpcSend { is_async, data: buffer });
}

View File

@ -5,16 +5,12 @@ use cslice::CSlice;
use super::{Message, SubkernelStatus, KERNEL_CHANNEL_0TO1, KERNEL_CHANNEL_1TO0};
use crate::{artiq_raise, rpc::send_args};
pub extern "C" fn load_run(id: u32, destination: u8, run: bool) {
pub extern "C" fn load_run(id: u32, run: bool) {
unsafe {
KERNEL_CHANNEL_1TO0
.as_mut()
.unwrap()
.send(Message::SubkernelLoadRunRequest {
id: id,
destination: destination,
run: run,
});
.send(Message::SubkernelLoadRunRequest { id: id, run: run });
}
match unsafe { KERNEL_CHANNEL_0TO1.as_mut().unwrap() }.recv() {
Message::SubkernelLoadRunReply { succeeded: true } => (),
@ -25,7 +21,7 @@ pub extern "C" fn load_run(id: u32, destination: u8, run: bool) {
}
}
pub extern "C" fn await_finish(id: u32, timeout: i64) {
pub extern "C" fn await_finish(id: u32, timeout: u64) {
unsafe {
KERNEL_CHANNEL_1TO0
.as_mut()
@ -55,22 +51,14 @@ pub extern "C" fn await_finish(id: u32, timeout: i64) {
}
}
pub extern "C" fn send_message(
id: u32,
is_return: bool,
destination: u8,
count: u8,
tag: &CSlice<u8>,
data: *const *const (),
) {
pub extern "C" fn send_message(id: u32, count: u8, tag: &CSlice<u8>, data: *const *const ()) {
let mut buffer = Vec::<u8>::new();
send_args(&mut buffer, 0, tag.as_ref(), data, false).expect("RPC encoding failed");
send_args(&mut buffer, 0, tag.as_ref(), data).expect("RPC encoding failed");
// overwrite service tag, include how many tags are in the message
buffer[3] = count;
unsafe {
KERNEL_CHANNEL_1TO0.as_mut().unwrap().send(Message::SubkernelMsgSend {
id: id,
destination: if is_return { None } else { Some(destination) },
data: buffer[3..].to_vec(),
});
}
@ -80,7 +68,7 @@ pub extern "C" fn send_message(
}
}
pub extern "C" fn await_message(id: i32, timeout: i64, tags: &CSlice<u8>, min: u8, max: u8) {
pub extern "C" fn await_message(id: u32, timeout: u64, min: u8, max: u8) {
unsafe {
KERNEL_CHANNEL_1TO0
.as_mut()
@ -88,7 +76,6 @@ pub extern "C" fn await_message(id: i32, timeout: i64, tags: &CSlice<u8>, min: u
.send(Message::SubkernelMsgRecvRequest {
id: id,
timeout: timeout,
tags: tags.as_ref().to_vec(),
});
}
match unsafe { KERNEL_CHANNEL_0TO1.as_mut().unwrap() }.recv() {

View File

@ -175,12 +175,7 @@ where
}
}
pub fn recv_return<'a, F, R>(
reader: &mut R,
tag_bytes: &'a [u8],
data: *mut (),
alloc: &mut F,
) -> Result<&'a [u8], Error>
pub fn recv_return<F, R>(reader: &mut R, tag_bytes: &[u8], data: *mut (), alloc: &mut F) -> Result<(), Error>
where
F: FnMut(usize) -> *mut (),
R: Read + ?Sized,
@ -192,22 +187,12 @@ where
let mut data = data;
unsafe { recv_value(reader, tag, &mut data, alloc)? };
Ok(it.data)
Ok(())
}
unsafe fn send_elements<W>(
writer: &mut W,
elt_tag: Tag,
length: usize,
data: *const (),
write_tags: bool,
) -> Result<(), Error>
where
W: Write + ?Sized,
{
if write_tags {
writer.write_u8(elt_tag.as_u8())?;
}
unsafe fn send_elements<W>(writer: &mut W, elt_tag: Tag, length: usize, data: *const ()) -> Result<(), Error>
where W: Write + ?Sized {
writer.write_u8(elt_tag.as_u8())?;
match elt_tag {
// we cannot use NativeEndian::from_slice_i32 as the data is not mutable,
// and that is not needed as the data is already in native endian
@ -226,14 +211,14 @@ where
_ => {
let mut data = data;
for _ in 0..length {
send_value(writer, elt_tag, &mut data, write_tags)?;
send_value(writer, elt_tag, &mut data)?;
}
}
}
Ok(())
}
unsafe fn send_value<W>(writer: &mut W, tag: Tag, data: &mut *const (), write_tags: bool) -> Result<(), Error>
unsafe fn send_value<W>(writer: &mut W, tag: Tag, data: &mut *const ()) -> Result<(), Error>
where W: Write + ?Sized {
macro_rules! consume_value {
($ty:ty, | $ptr:ident | $map:expr) => {{
@ -243,9 +228,7 @@ where W: Write + ?Sized {
}};
}
if write_tags {
writer.write_u8(tag.as_u8())?;
}
writer.write_u8(tag.as_u8())?;
match tag {
Tag::None => Ok(()),
Tag::Bool => consume_value!(u8, |ptr| writer.write_u8(*ptr)),
@ -257,14 +240,12 @@ where W: Write + ?Sized {
Tag::Bytes | Tag::ByteArray => consume_value!(CSlice<u8>, |ptr| writer.write_bytes((*ptr).as_ref())),
Tag::Tuple(it, arity) => {
let mut it = it.clone();
if write_tags {
writer.write_u8(arity)?;
}
writer.write_u8(arity)?;
let mut max_alignment = 0;
for _ in 0..arity {
let tag = it.next().expect("truncated tag");
max_alignment = core::cmp::max(max_alignment, tag.alignment());
send_value(writer, tag, data, write_tags)?
send_value(writer, tag, data)?
}
*data = round_up_const(*data, max_alignment);
Ok(())
@ -279,13 +260,11 @@ where W: Write + ?Sized {
let length = (**ptr).length as usize;
writer.write_u32((*ptr).length)?;
let tag = it.clone().next().expect("truncated tag");
send_elements(writer, tag, length, (**ptr).elements, write_tags)
send_elements(writer, tag, length, (**ptr).elements)
})
}
Tag::Array(it, num_dims) => {
if write_tags {
writer.write_u8(num_dims)?;
}
writer.write_u8(num_dims)?;
consume_value!(*const (), |buffer| {
let elt_tag = it.clone().next().expect("truncated tag");
@ -297,14 +276,14 @@ where W: Write + ?Sized {
})
}
let length = total_len as usize;
send_elements(writer, elt_tag, length, *buffer, write_tags)
send_elements(writer, elt_tag, length, *buffer)
})
}
Tag::Range(it) => {
let tag = it.clone().next().expect("truncated tag");
send_value(writer, tag, data, write_tags)?;
send_value(writer, tag, data, write_tags)?;
send_value(writer, tag, data, write_tags)?;
send_value(writer, tag, data)?;
send_value(writer, tag, data)?;
send_value(writer, tag, data)?;
Ok(())
}
Tag::Keyword(it) => {
@ -316,7 +295,7 @@ where W: Write + ?Sized {
writer.write_string(str::from_utf8((*ptr).name.as_ref()).unwrap())?;
let tag = it.clone().next().expect("truncated tag");
let mut data = ptr.offset(1) as *const ();
send_value(writer, tag, &mut data, write_tags)
send_value(writer, tag, &mut data)
})
// Tag::Keyword never appears in composite types, so we don't have
// to accurately advance data.
@ -331,16 +310,8 @@ where W: Write + ?Sized {
}
}
pub fn send_args<W>(
writer: &mut W,
service: u32,
tag_bytes: &[u8],
data: *const *const (),
write_tags: bool,
) -> Result<(), Error>
where
W: Write + ?Sized,
{
pub fn send_args<W>(writer: &mut W, service: u32, tag_bytes: &[u8], data: *const *const ()) -> Result<(), Error>
where W: Write + ?Sized {
let (arg_tags_bytes, return_tag_bytes) = split_tag(tag_bytes);
let mut args_it = TagIterator::new(arg_tags_bytes);
@ -351,7 +322,7 @@ where
for index in 0.. {
if let Some(arg_tag) = args_it.next() {
let mut data = unsafe { *data.offset(index) };
unsafe { send_value(writer, arg_tag, &mut data, write_tags)? };
unsafe { send_value(writer, arg_tag, &mut data)? };
} else {
break;
}
@ -479,7 +450,7 @@ pub mod tag {
#[derive(Debug, Clone, Copy)]
pub struct TagIterator<'a> {
pub data: &'a [u8],
data: &'a [u8],
}
impl<'a> TagIterator<'a> {

View File

@ -40,8 +40,4 @@ unwind = { path = "../libunwind" }
libc = { path = "../libc" }
io = { path = "../libio", features = ["alloc"] }
ksupport = { path = "../libksupport" }
libboard_artiq = { path = "../libboard_artiq" }
[dependencies.tar-no-std]
git = "https://git.m-labs.hk/M-Labs/tar-no-std"
rev = "2ab6dc5"
libboard_artiq = { path = "../libboard_artiq" }

View File

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

View File

@ -3,22 +3,17 @@ use core::{cell::RefCell, fmt, slice, str};
use core_io::Error as IoError;
use cslice::CSlice;
use dyld::elf;
use futures::{future::FutureExt, select_biased};
#[cfg(has_drtio)]
use io::Cursor;
use io::{Cursor, ProtoRead};
#[cfg(has_drtio)]
use ksupport::rpc;
use ksupport::{kernel, resolve_channel_name};
#[cfg(has_drtio)]
use libasync::delay;
use libasync::{smoltcp::{Sockets, TcpStream},
task};
use libboard_artiq::drtio_routing;
#[cfg(feature = "target_kasli_soc")]
use libboard_zynq::error_led::ErrorLED;
#[cfg(has_drtio)]
use libboard_zynq::time::Milliseconds;
use libboard_zynq::{self as zynq,
smoltcp::{self,
iface::{EthernetInterfaceBuilder, NeighborCache},
@ -32,8 +27,6 @@ use libcortex_a9::{mutex::Mutex,
use log::{error, info, warn};
use num_derive::{FromPrimitive, ToPrimitive};
use num_traits::{FromPrimitive, ToPrimitive};
#[cfg(has_drtio)]
use tar_no_std::TarArchiveRef;
#[cfg(has_drtio)]
use crate::pl;
@ -50,8 +43,6 @@ pub enum Error {
BufferExhausted,
#[cfg(has_drtio)]
SubkernelError(subkernel::Error),
#[cfg(has_drtio)]
DestinationDown,
}
pub type Result<T> = core::result::Result<T, Error>;
@ -66,8 +57,6 @@ impl fmt::Display for Error {
Error::BufferExhausted => write!(f, "buffer exhausted"),
#[cfg(has_drtio)]
Error::SubkernelError(error) => write!(f, "subkernel error: {:?}", error),
#[cfg(has_drtio)]
Error::DestinationDown => write!(f, "subkernel destination down"),
}
}
}
@ -401,11 +390,7 @@ async fn handle_run_kernel(
control.borrow_mut().tx.async_send(reply).await;
}
#[cfg(has_drtio)]
kernel::Message::SubkernelLoadRunRequest {
id,
destination: _,
run,
} => {
kernel::Message::SubkernelLoadRunRequest { id, run } => {
let succeeded = match subkernel::load(aux_mutex, routing_table, timer, id, run).await {
Ok(()) => true,
Err(e) => {
@ -451,9 +436,8 @@ async fn handle_run_kernel(
.await;
}
#[cfg(has_drtio)]
kernel::Message::SubkernelMsgSend { id, destination, data } => {
let res =
subkernel::message_send(aux_mutex, routing_table, timer, id, destination.unwrap(), data).await;
kernel::Message::SubkernelMsgSend { id, data } => {
let res = subkernel::message_send(aux_mutex, routing_table, timer, id, data).await;
match res {
Ok(_) => (),
Err(e) => {
@ -467,27 +451,13 @@ async fn handle_run_kernel(
.await;
}
#[cfg(has_drtio)]
kernel::Message::SubkernelMsgRecvRequest { id, timeout, tags } => {
let message_received = subkernel::message_await(id as u32, timeout, timer).await;
kernel::Message::SubkernelMsgRecvRequest { id, timeout } => {
let message_received = subkernel::message_await(id, timeout, timer).await;
let (status, count) = match message_received {
Ok(ref message) => (kernel::SubkernelStatus::NoError, message.count),
Err(SubkernelError::Timeout) => (kernel::SubkernelStatus::Timeout, 0),
Err(SubkernelError::IncorrectState) => (kernel::SubkernelStatus::IncorrectState, 0),
Err(SubkernelError::CommLost) => (kernel::SubkernelStatus::CommLost, 0),
Err(SubkernelError::SubkernelException) => {
error!("Exception in subkernel");
// just retrieve the exception
let status = subkernel::await_finish(aux_mutex, routing_table, timer, id as u32, timeout)
.await
.unwrap();
match stream {
None => (),
Some(stream) => {
write_chunk(stream, &status.exception.unwrap()).await?;
}
}
(kernel::SubkernelStatus::OtherError, 0)
}
Err(_) => (kernel::SubkernelStatus::OtherError, 0),
};
control
@ -501,7 +471,7 @@ async fn handle_run_kernel(
if let Ok(message) = message_received {
// receive code almost identical to RPC recv, except we are not reading from a stream
let mut reader = Cursor::new(message.data);
let mut current_tags: &[u8] = &tags;
let mut tag: [u8; 1] = [message.tag];
let mut i = 0;
loop {
// kernel has to consume all arguments in the whole message
@ -509,7 +479,7 @@ async fn handle_run_kernel(
kernel::Message::RpcRecvRequest(slot) => slot,
other => panic!("expected root value slot from core1, not {:?}", other),
};
let remaining_tags = rpc::recv_return(&mut reader, &current_tags, slot, &mut |size| {
rpc::recv_return(&mut reader, &tag, slot, &mut |size| {
if size == 0 {
0 as *mut ()
} else {
@ -530,7 +500,7 @@ async fn handle_run_kernel(
.await;
i += 1;
if i < count {
current_tags = remaining_tags;
tag[0] = reader.read_u8()?;
} else {
break;
}
@ -554,56 +524,6 @@ async fn handle_run_kernel(
Ok(())
}
async fn handle_flash_kernel(
buffer: &Vec<u8>,
control: &Rc<RefCell<kernel::Control>>,
_up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>,
_aux_mutex: &Rc<Mutex<bool>>,
_routing_table: &drtio_routing::RoutingTable,
_timer: GlobalTimer,
) -> Result<()> {
if buffer[0] == elf::ELFMAG0 && buffer[1] == elf::ELFMAG1 && buffer[2] == elf::ELFMAG2 && buffer[3] == elf::ELFMAG3
{
// assume ELF file, proceed as before
load_kernel(buffer, control, None).await
} else {
#[cfg(has_drtio)]
{
let archive = TarArchiveRef::new(buffer.as_ref());
let entries = archive.entries();
let mut main_lib: Vec<u8> = Vec::new();
for entry in entries {
if entry.filename().as_str() == "main.elf" {
main_lib = entry.data().to_vec();
} else {
// subkernel filename must be in format:
// "<subkernel id> <destination>.elf"
let filename = entry.filename();
let mut iter = filename.as_str().split_whitespace();
let sid: u32 = iter.next().unwrap().parse().unwrap();
let dest: u8 = iter.next().unwrap().strip_suffix(".elf").unwrap().parse().unwrap();
let up = _up_destinations.borrow()[dest as usize];
if up {
let subkernel_lib = entry.data().to_vec();
subkernel::add_subkernel(sid, dest, subkernel_lib).await;
match subkernel::upload(_aux_mutex, _routing_table, _timer, sid).await {
Ok(_) => (),
Err(_) => return Err(Error::UnexpectedPattern),
}
} else {
return Err(Error::DestinationDown);
}
}
}
load_kernel(&main_lib, control, None).await
}
#[cfg(not(has_drtio))]
{
panic!("multi-kernel libraries are not supported in standalone systems");
}
}
}
async fn load_kernel(
buffer: &Vec<u8>,
control: &Rc<RefCell<kernel::Control>>,
@ -759,6 +679,7 @@ pub fn main(timer: GlobalTimer, cfg: Config) {
Sockets::init(32);
// before, mutex was on io, but now that io isn't used...?
let aux_mutex: Rc<Mutex<bool>> = Rc::new(Mutex::new(false));
#[cfg(has_drtio)]
let drtio_routing_table = Rc::new(RefCell::new(drtio_routing::config_routing_table(
@ -781,16 +702,9 @@ pub fn main(timer: GlobalTimer, cfg: Config) {
let idle_kernel = Rc::new(cfg.read("idle_kernel").ok());
if let Ok(buffer) = cfg.read("startup_kernel") {
info!("Loading startup kernel...");
let routing_table = drtio_routing_table.borrow();
if let Ok(()) = task::block_on(handle_flash_kernel(
&buffer,
&control,
&up_destinations,
&aux_mutex,
&routing_table,
timer,
)) {
if let Ok(()) = task::block_on(load_kernel(&buffer, &control, None)) {
info!("Starting startup kernel...");
let routing_table = drtio_routing_table.borrow();
let _ = task::block_on(handle_run_kernel(
None,
&control,
@ -838,17 +752,8 @@ pub fn main(timer: GlobalTimer, cfg: Config) {
.map_err(|e| warn!("connection terminated: {}", e));
if let Some(buffer) = &*idle_kernel {
info!("Loading idle kernel");
let res = handle_flash_kernel(&buffer, &control, &up_destinations, &aux_mutex, &routing_table, timer)
.await;
match res {
#[cfg(has_drtio)]
Err(Error::DestinationDown) => {
let mut countdown = timer.countdown();
delay(&mut countdown, Milliseconds(500)).await;
}
Err(_) => warn!("error loading idle kernel"),
_ => (),
}
let _ = load_kernel(&buffer, &control, None)
.await.map_err(|_| warn!("error loading idle kernel"));
info!("Running idle kernel");
let _ = handle_run_kernel(None, &control, &up_destinations, &aux_mutex, &routing_table, timer)
.await.map_err(|_| warn!("error running idle kernel"));

View File

@ -8,7 +8,7 @@
#[macro_use]
extern crate alloc;
#[cfg(all(feature = "target_kasli_soc", has_virtual_leds))]
#[cfg(feature = "target_kasli_soc")]
use core::cell::RefCell;
use ksupport;
@ -21,7 +21,7 @@ use libboard_artiq::{identifier_read, logger, pl};
use libboard_zynq::{gic, mpcore, timer::GlobalTimer};
use libconfig::Config;
use libcortex_a9::l2c::enable_l2_cache;
use libsupport_zynq::{exception_vectors, ram};
use libsupport_zynq::ram;
use log::{info, warn};
mod analyzer;
@ -38,12 +38,7 @@ mod rtio_mgt;
#[cfg(has_drtio)]
mod subkernel;
// linker symbols
extern "C" {
static __exceptions_start: u32;
}
#[cfg(all(feature = "target_kasli_soc", has_virtual_leds))]
#[cfg(feature = "target_kasli_soc")]
async fn io_expanders_service(
i2c_bus: RefCell<&mut libboard_zynq::i2c::I2c>,
io_expander0: RefCell<io_expander::IoExpander>,
@ -67,9 +62,7 @@ mod grabber {
use libasync::delay;
use libboard_artiq::grabber;
use libboard_zynq::time::Milliseconds;
use crate::GlobalTimer;
pub async fn grabber_thread(timer: GlobalTimer) {
pub async fn grabber_thread(mut timer: GlobalTimer) {
let mut countdown = timer.countdown();
loop {
grabber::tick();
@ -82,9 +75,6 @@ static mut LOG_BUFFER: [u8; 1 << 17] = [0; 1 << 17];
#[no_mangle]
pub fn main_core0() {
unsafe {
exception_vectors::set_vector_table(&__exceptions_start as *const u32 as u32);
}
enable_l2_cache(0x8);
let mut timer = GlobalTimer::start();
@ -102,21 +92,20 @@ pub fn main_core0() {
ksupport::i2c::init();
#[cfg(feature = "target_kasli_soc")]
let i2c_bus = unsafe { (ksupport::i2c::I2C_BUS).as_mut().unwrap() };
#[cfg(feature = "target_kasli_soc")]
let (mut io_expander0, mut io_expander1);
#[cfg(feature = "target_kasli_soc")]
{
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_expander1 = io_expander::IoExpander::new(i2c_bus, 1).unwrap();
io_expander0 = io_expander::IoExpander::new(i2c_bus, 0).unwrap();
io_expander1 = io_expander::IoExpander::new(i2c_bus, 1).unwrap();
io_expander0
.init(i2c_bus)
.expect("I2C I/O expander #0 initialization failed");
io_expander1
.init(i2c_bus)
.expect("I2C I/O expander #1 initialization failed");
// Drive CLK_SEL to true
#[cfg(has_si549)]
io_expander0.set(1, 7, true);
// Drive TX_DISABLE to false on SFP0..3
io_expander0.set(0, 1, false);
io_expander1.set(0, 1, false);
@ -124,12 +113,6 @@ pub fn main_core0() {
io_expander1.set(1, 1, false);
io_expander0.service(i2c_bus).unwrap();
io_expander1.service(i2c_bus).unwrap();
#[cfg(has_virtual_leds)]
task::spawn(io_expanders_service(
RefCell::new(i2c_bus),
RefCell::new(io_expander0),
RefCell::new(io_expander1),
));
}
let cfg = match Config::new() {
@ -150,5 +133,11 @@ pub fn main_core0() {
task::spawn(ksupport::report_async_rtio_errors());
#[cfg(feature = "target_kasli_soc")]
task::spawn(io_expanders_service(
RefCell::new(i2c_bus),
RefCell::new(io_expander0),
RefCell::new(io_expander1),
));
comms::main(timer, cfg);
}

View File

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

View File

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

View File

@ -142,9 +142,9 @@ pub mod remote_dma {
}
}
pub async fn playback_done(&mut self, source: u8, error: u8, channel: u32, timestamp: u64) {
pub async fn playback_done(&mut self, destination: u8, error: u8, channel: u32, timestamp: u64) {
let mut traces_locked = self.traces.async_lock().await;
let mut trace = traces_locked.get_mut(&source).unwrap();
let mut trace = traces_locked.get_mut(&destination).unwrap();
trace.state = RemoteState::PlaybackEnded {
error: error,
channel: channel,

View File

@ -1,67 +1,29 @@
use alloc::rc::Rc;
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 libcortex_a9::mutex::Mutex;
#[cfg(has_drtio)]
pub mod drtio {
use alloc::vec::Vec;
use core::fmt;
use embedded_hal::blocking::delay::DelayMs;
use ksupport::{resolve_channel_name, ASYNC_ERROR_BUSY, ASYNC_ERROR_COLLISION, ASYNC_ERROR_SEQUENCE_ERROR,
SEEN_ASYNC_ERRORS};
use libasync::{delay, task};
use libboard_artiq::{drtioaux::Error as DrtioError,
drtioaux_async,
drtioaux_async::Packet,
drtioaux_proto::{PayloadStatus, MASTER_PAYLOAD_MAX_SIZE}};
use libboard_artiq::{drtioaux::Error, drtioaux_async, drtioaux_async::Packet,
drtioaux_proto::MASTER_PAYLOAD_MAX_SIZE};
use libboard_zynq::time::Milliseconds;
use log::{error, info, warn};
use super::*;
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(
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]>>,
timer: GlobalTimer,
) {
@ -79,104 +41,65 @@ pub mod drtio {
unsafe { (csr::DRTIO[linkno].rx_up_read)() == 1 }
}
async fn process_async_packets(linkno: u8, routing_table: &RoutingTable, packet: Packet) -> Option<Packet> {
async fn process_async_packets(aux_mutex: &Mutex<bool>, linkno: u8, packet: Packet) -> Option<Packet> {
// returns None if an async packet has been consumed
match packet {
Packet::DmaPlaybackStatus {
id,
source,
destination: 0,
destination,
error,
channel,
timestamp,
} => {
remote_dma::playback_done(id, source, error, channel, timestamp).await;
remote_dma::playback_done(id, destination, error, channel, timestamp).await;
None
}
Packet::SubkernelFinished {
id,
destination: 0,
with_exception,
exception_src,
} => {
subkernel::subkernel_finished(id, with_exception, exception_src).await;
Packet::SubkernelFinished { id, with_exception } => {
subkernel::subkernel_finished(id, with_exception).await;
None
}
Packet::SubkernelMessage {
id,
source,
destination: 0,
status,
destination: from,
last,
length,
data,
} => {
subkernel::message_handle_incoming(id, status, length as usize, &data).await;
subkernel::message_handle_incoming(id, last, length as usize, &data).await;
// acknowledge receiving part of the message
drtioaux_async::send(linkno, &Packet::SubkernelMessageAck { destination: source })
let _lock = aux_mutex.async_lock().await;
drtioaux_async::send(linkno, &Packet::SubkernelMessageAck { destination: from })
.await
.unwrap();
None
}
// routable packets
Packet::DmaAddTraceRequest { destination, .. }
| Packet::DmaAddTraceReply { destination, .. }
| Packet::DmaRemoveTraceRequest { destination, .. }
| Packet::DmaRemoveTraceReply { destination, .. }
| Packet::DmaPlaybackRequest { destination, .. }
| Packet::DmaPlaybackReply { destination, .. }
| Packet::SubkernelLoadRunRequest { destination, .. }
| Packet::SubkernelLoadRunReply { destination, .. }
| Packet::SubkernelMessage { destination, .. }
| Packet::SubkernelMessageAck { destination, .. }
| Packet::DmaPlaybackStatus { destination, .. }
| Packet::SubkernelFinished { destination, .. } => {
if destination == 0 {
Some(packet)
} else {
let dest_link = routing_table.0[destination as usize][0] - 1;
if dest_link == linkno {
warn!(
"[LINK#{}] Re-routed packet would return to the same link, dropping: {:?}",
linkno, packet
);
} else {
drtioaux_async::send(dest_link, &packet).await.unwrap();
}
None
}
}
other => Some(other),
}
}
async fn recv_aux_timeout(linkno: u8, timeout: u64, timer: GlobalTimer) -> Result<Packet, Error> {
async fn recv_aux_timeout(linkno: u8, timeout: u64, timer: GlobalTimer) -> Result<Packet, &'static str> {
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 {
Ok(packet) => return Ok(packet),
Err(DrtioError::TimedOut) => return Err(Error::Timeout),
Err(_) => return Err(Error::AuxError),
Err(Error::TimedOut) => return Err("timed out"),
Err(_) => return Err("aux packet error"),
}
}
pub async fn aux_transact(
aux_mutex: &Mutex<bool>,
linkno: u8,
routing_table: &RoutingTable,
request: &Packet,
timer: GlobalTimer,
) -> Result<Packet, Error> {
) -> Result<Packet, &'static str> {
if !link_rx_up(linkno).await {
return Err(Error::LinkDown);
return Err("link went down");
}
let _lock = aux_mutex.async_lock().await;
drtioaux_async::send(linkno, request).await.unwrap();
loop {
let packet = recv_aux_timeout(linkno, 200, timer).await?;
if let Some(packet) = process_async_packets(linkno, routing_table, packet).await {
return Ok(packet);
}
}
Ok(recv_aux_timeout(linkno, 200, timer).await?)
}
async fn drain_buffer(linkno: u8, draining_time: Milliseconds, timer: GlobalTimer) {
@ -184,17 +107,12 @@ pub mod drtio {
loop {
if timer.get_time() > max_time {
return;
}
} //could this be cut short?
let _ = drtioaux_async::recv(linkno).await;
}
}
async fn ping_remote(
aux_mutex: &Rc<Mutex<bool>>,
linkno: u8,
routing_table: &RoutingTable,
timer: GlobalTimer,
) -> u32 {
async fn ping_remote(aux_mutex: &Rc<Mutex<bool>>, linkno: u8, timer: GlobalTimer) -> u32 {
let mut count = 0;
loop {
if !link_rx_up(linkno).await {
@ -204,7 +122,7 @@ pub mod drtio {
if count > 100 {
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 {
Ok(Packet::EchoReply) => {
// make sure receive buffer is drained
@ -217,7 +135,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;
unsafe {
@ -228,23 +146,22 @@ pub mod drtio {
// by the satellite, in response to a TSC set on the RT link.
let reply = recv_aux_timeout(linkno, 10000, timer).await?;
if reply == Packet::TSCAck {
Ok(())
return Ok(());
} else {
Err(Error::UnexpectedReply)
return Err("unexpected reply");
}
}
async fn load_routing_table(
aux_mutex: &Rc<Mutex<bool>>,
linkno: u8,
routing_table: &RoutingTable,
routing_table: &drtio_routing::RoutingTable,
timer: GlobalTimer,
) -> Result<(), Error> {
) -> Result<(), &'static str> {
for i in 0..drtio_routing::DEST_COUNT {
let reply = aux_transact(
aux_mutex,
linkno,
routing_table,
&Packet::RoutingSetPath {
destination: i as u8,
hops: routing_table.0[i],
@ -253,7 +170,7 @@ pub mod drtio {
)
.await?;
if reply != Packet::RoutingAck {
return Err(Error::UnexpectedReply);
return Err("unexpected reply");
}
}
Ok(())
@ -263,21 +180,13 @@ pub mod drtio {
aux_mutex: &Rc<Mutex<bool>>,
linkno: u8,
rank: u8,
routing_table: &RoutingTable,
timer: GlobalTimer,
) -> Result<(), Error> {
let reply = aux_transact(
aux_mutex,
linkno,
routing_table,
&Packet::RoutingSetRank { rank: rank },
timer,
)
.await?;
match reply {
Packet::RoutingAck => Ok(()),
_ => Err(Error::UnexpectedReply),
) -> Result<(), &'static str> {
let reply = aux_transact(aux_mutex, linkno, &Packet::RoutingSetRank { rank: rank }, timer).await?;
if reply != Packet::RoutingAck {
return Err("unexpected reply");
}
Ok(())
}
async fn init_buffer_space(destination: u8, linkno: u8) {
@ -296,11 +205,11 @@ 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;
match drtioaux_async::recv(linkno).await {
Ok(Some(packet)) => {
if let Some(packet) = process_async_packets(linkno, routing_table, packet).await {
if let Some(packet) = process_async_packets(aux_mutex, linkno, packet).await {
warn!("[LINK#{}] unsolicited aux packet: {:?}", linkno, packet);
}
}
@ -331,7 +240,7 @@ pub mod drtio {
}
async fn destination_set_up(
routing_table: &RoutingTable,
routing_table: &drtio_routing::RoutingTable,
up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>,
destination: u8,
up: bool,
@ -354,7 +263,7 @@ pub mod drtio {
async fn destination_survey(
aux_mutex: &Rc<Mutex<bool>>,
routing_table: &RoutingTable,
routing_table: &drtio_routing::RoutingTable,
up_links: &[bool],
up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>,
timer: GlobalTimer,
@ -372,54 +281,67 @@ pub mod drtio {
let linkno = hop - 1;
if destination_up(up_destinations, destination).await {
if up_links[linkno as usize] {
let reply = aux_transact(
aux_mutex,
linkno,
routing_table,
&Packet::DestinationStatusRequest {
destination: destination,
},
timer,
)
.await;
match reply {
Ok(Packet::DestinationDownReply) => {
destination_set_up(routing_table, up_destinations, destination, false).await;
remote_dma::destination_changed(aux_mutex, routing_table, timer, destination, false)
.await;
subkernel::destination_changed(aux_mutex, routing_table, timer, destination, false)
loop {
let reply = aux_transact(
aux_mutex,
linkno,
&Packet::DestinationStatusRequest {
destination: destination,
},
timer,
)
.await;
match reply {
Ok(Packet::DestinationDownReply) => {
destination_set_up(routing_table, up_destinations, destination, false).await;
remote_dma::destination_changed(
aux_mutex,
routing_table,
timer,
destination,
false,
)
.await;
subkernel::destination_changed(aux_mutex, routing_table, timer, destination, false)
.await;
}
Ok(Packet::DestinationOkReply) => (),
Ok(Packet::DestinationSequenceErrorReply { channel }) => {
error!(
"[DEST#{}] RTIO sequence error involving channel 0x{:04x}:{}",
destination,
channel,
resolve_channel_name(channel as u32)
);
unsafe { SEEN_ASYNC_ERRORS |= ASYNC_ERROR_SEQUENCE_ERROR };
}
Ok(Packet::DestinationCollisionReply { channel }) => {
error!(
"[DEST#{}] RTIO collision involving channel 0x{:04x}:{}",
destination,
channel,
resolve_channel_name(channel as u32)
);
unsafe { SEEN_ASYNC_ERRORS |= ASYNC_ERROR_COLLISION };
}
Ok(Packet::DestinationBusyReply { channel }) => {
error!(
"[DEST#{}] RTIO busy error involving channel 0x{:04x}:{}",
destination,
channel,
resolve_channel_name(channel as u32)
);
unsafe { SEEN_ASYNC_ERRORS |= ASYNC_ERROR_BUSY };
}
Ok(packet) => match process_async_packets(aux_mutex, linkno, packet).await {
Some(packet) => {
error!("[DEST#{}] received unexpected aux packet: {:?}", destination, packet)
}
None => continue,
},
Err(e) => error!("[DEST#{}] communication failed ({})", destination, e),
}
Ok(Packet::DestinationOkReply) => (),
Ok(Packet::DestinationSequenceErrorReply { channel }) => {
error!(
"[DEST#{}] RTIO sequence error involving channel 0x{:04x}:{}",
destination,
channel,
resolve_channel_name(channel as u32)
);
unsafe { SEEN_ASYNC_ERRORS |= ASYNC_ERROR_SEQUENCE_ERROR };
}
Ok(Packet::DestinationCollisionReply { channel }) => {
error!(
"[DEST#{}] RTIO collision involving channel 0x{:04x}:{}",
destination,
channel,
resolve_channel_name(channel as u32)
);
unsafe { SEEN_ASYNC_ERRORS |= ASYNC_ERROR_COLLISION };
}
Ok(Packet::DestinationBusyReply { channel }) => {
error!(
"[DEST#{}] RTIO busy error involving channel 0x{:04x}:{}",
destination,
channel,
resolve_channel_name(channel as u32)
);
unsafe { SEEN_ASYNC_ERRORS |= ASYNC_ERROR_BUSY };
}
Ok(packet) => error!("[DEST#{}] received unexpected aux packet: {:?}", destination, packet),
Err(e) => error!("[DEST#{}] communication failed ({})", destination, e),
break;
}
} else {
destination_set_up(routing_table, up_destinations, destination, false).await;
@ -431,7 +353,6 @@ pub mod drtio {
let reply = aux_transact(
aux_mutex,
linkno,
routing_table,
&Packet::DestinationStatusRequest {
destination: destination,
},
@ -459,7 +380,7 @@ pub mod drtio {
pub async fn link_task(
aux_mutex: &Rc<Mutex<bool>>,
routing_table: &RoutingTable,
routing_table: &drtio_routing::RoutingTable,
up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>,
timer: GlobalTimer,
) {
@ -470,7 +391,7 @@ pub mod drtio {
if up_links[linkno as usize] {
/* link was previously up */
if link_rx_up(linkno).await {
process_unsolicited_aux(aux_mutex, linkno, routing_table).await;
process_unsolicited_aux(aux_mutex, linkno).await;
process_local_errors(linkno).await;
} else {
info!("[LINK#{}] link is down", linkno);
@ -480,7 +401,7 @@ pub mod drtio {
/* link was previously down */
if link_rx_up(linkno).await {
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 {
info!("[LINK#{}] remote replied after {} packets", linkno, ping_count);
up_links[linkno as usize] = true;
@ -490,7 +411,7 @@ pub mod drtio {
if let Err(e) = load_routing_table(aux_mutex, linkno, routing_table, timer).await {
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);
}
info!("[LINK#{}] link initialization completed", linkno);
@ -507,7 +428,7 @@ pub mod drtio {
}
#[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() {
unsafe {
(csr::DRTIO[linkno].reset_write)(1);
@ -523,13 +444,7 @@ pub mod drtio {
for linkno in 0..csr::DRTIO.len() {
let linkno = linkno as u8;
if task::block_on(link_rx_up(linkno)) {
let reply = task::block_on(aux_transact(
&aux_mutex,
linkno,
routing_table,
&Packet::ResetRequest,
timer,
));
let reply = task::block_on(aux_transact(&aux_mutex, linkno, &Packet::ResetRequest, timer));
match reply {
Ok(Packet::ResetAck) => (),
Ok(_) => error!("[LINK#{}] reset failed, received unexpected aux packet", linkno),
@ -542,15 +457,14 @@ pub mod drtio {
async fn partition_data<PacketF, HandlerF>(
linkno: u8,
aux_mutex: &Rc<Mutex<bool>>,
routing_table: &RoutingTable,
timer: GlobalTimer,
data: &[u8],
packet_f: PacketF,
reply_handler_f: HandlerF,
) -> Result<(), Error>
) -> Result<(), &'static str>
where
PacketF: Fn(&[u8; MASTER_PAYLOAD_MAX_SIZE], PayloadStatus, usize) -> Packet,
HandlerF: Fn(&Packet) -> Result<(), Error>,
PacketF: Fn(&[u8; MASTER_PAYLOAD_MAX_SIZE], bool, usize) -> Packet,
HandlerF: Fn(&Packet) -> Result<(), &'static str>,
{
let mut i = 0;
while i < data.len() {
@ -560,13 +474,11 @@ pub mod drtio {
} else {
data.len() - i
} as usize;
let first = i == 0;
let last = i + len == data.len();
slice[..len].clone_from_slice(&data[i..i + len]);
i += len;
let status = PayloadStatus::from_status(first, last);
let packet = packet_f(&slice, status, len);
let reply = aux_transact(aux_mutex, linkno, routing_table, &packet, timer).await?;
let packet = packet_f(&slice, last, len);
let reply = aux_transact(aux_mutex, linkno, &packet, timer).await?;
reply_handler_f(&reply)?;
}
Ok(())
@ -574,39 +486,29 @@ pub mod drtio {
pub async fn ddma_upload_trace(
aux_mutex: &Rc<Mutex<bool>>,
routing_table: &RoutingTable,
routing_table: &drtio_routing::RoutingTable,
timer: GlobalTimer,
id: u32,
destination: u8,
trace: &Vec<u8>,
) -> Result<(), Error> {
) -> Result<(), &'static str> {
let linkno = routing_table.0[destination as usize][0] - 1;
partition_data(
linkno,
aux_mutex,
routing_table,
timer,
trace,
|slice, status, len| Packet::DmaAddTraceRequest {
|slice, last, len| Packet::DmaAddTraceRequest {
id: id,
source: 0,
destination: destination,
status: status,
last: last,
length: len as u16,
trace: *slice,
},
|reply| match reply {
Packet::DmaAddTraceReply {
destination: 0,
succeeded: true,
..
} => Ok(()),
Packet::DmaAddTraceReply {
destination: 0,
succeeded: false,
..
} => Err(Error::DmaAddTraceFail(destination)),
_ => Err(Error::UnexpectedReply),
Packet::DmaAddTraceReply { succeeded: true } => Ok(()),
Packet::DmaAddTraceReply { succeeded: false } => Err("error adding trace on satellite"),
_ => Err("adding DMA trace failed, unexpected aux packet"),
},
)
.await
@ -614,96 +516,82 @@ pub mod drtio {
pub async fn ddma_send_erase(
aux_mutex: &Rc<Mutex<bool>>,
routing_table: &RoutingTable,
routing_table: &drtio_routing::RoutingTable,
timer: GlobalTimer,
id: u32,
destination: u8,
) -> Result<(), Error> {
) -> Result<(), &'static str> {
let linkno = routing_table.0[destination as usize][0] - 1;
let reply = aux_transact(
aux_mutex,
linkno,
routing_table,
&Packet::DmaRemoveTraceRequest {
id: id,
source: 0,
destination: destination,
},
timer,
)
.await?;
.await;
match reply {
Packet::DmaRemoveTraceReply {
destination: 0,
succeeded: true,
} => Ok(()),
Packet::DmaRemoveTraceReply {
destination: 0,
succeeded: false,
} => Err(Error::DmaEraseFail(destination)),
_ => Err(Error::UnexpectedReply),
Ok(Packet::DmaRemoveTraceReply { succeeded: true }) => Ok(()),
Ok(Packet::DmaRemoveTraceReply { succeeded: false }) => Err("satellite DMA erase error"),
Ok(_) => Err("adding trace failed, unexpected aux packet"),
Err(_) => Err("erasing trace failed, aux error"),
}
}
pub async fn ddma_send_playback(
aux_mutex: &Rc<Mutex<bool>>,
routing_table: &RoutingTable,
routing_table: &drtio_routing::RoutingTable,
timer: GlobalTimer,
id: u32,
destination: u8,
timestamp: u64,
) -> Result<(), Error> {
) -> Result<(), &'static str> {
let linkno = routing_table.0[destination as usize][0] - 1;
let reply = aux_transact(
aux_mutex,
linkno,
routing_table,
&Packet::DmaPlaybackRequest {
id: id,
source: 0,
destination: destination,
timestamp: timestamp,
},
timer,
)
.await?;
.await;
match reply {
Packet::DmaPlaybackReply {
destination: 0,
succeeded: true,
} => Ok(()),
Packet::DmaPlaybackReply {
destination: 0,
succeeded: false,
} => Err(Error::DmaPlaybackFail(destination)),
_ => Err(Error::UnexpectedReply),
Ok(Packet::DmaPlaybackReply { succeeded: true }) => Ok(()),
Ok(Packet::DmaPlaybackReply { succeeded: false }) => Err("error on DMA playback request"),
Ok(_) => Err("received unexpected aux packet during DMA playback"),
Err(_) => Err("aux error on DMA playback"),
}
}
async fn analyzer_get_data(
aux_mutex: &Rc<Mutex<bool>>,
routing_table: &RoutingTable,
routing_table: &drtio_routing::RoutingTable,
timer: GlobalTimer,
destination: u8,
) -> Result<RemoteBuffer, Error> {
) -> Result<RemoteBuffer, &'static str> {
let linkno = routing_table.0[destination as usize][0] - 1;
let reply = aux_transact(
aux_mutex,
linkno,
routing_table,
&Packet::AnalyzerHeaderRequest {
destination: destination,
},
timer,
)
.await?;
.await;
let (sent, total, overflow) = match reply {
Packet::AnalyzerHeader {
Ok(Packet::AnalyzerHeader {
sent_bytes,
total_byte_count,
overflow_occurred,
} => (sent_bytes, total_byte_count, overflow_occurred),
_ => return Err(Error::UnexpectedReply),
}) => (sent_bytes, total_byte_count, overflow_occurred),
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();
@ -713,19 +601,19 @@ pub mod drtio {
let reply = aux_transact(
aux_mutex,
linkno,
routing_table,
&Packet::AnalyzerDataRequest {
destination: destination,
},
timer,
)
.await?;
.await;
match reply {
Packet::AnalyzerData { last, length, data } => {
Ok(Packet::AnalyzerData { last, length, data }) => {
last_packet = last;
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 +628,10 @@ pub mod drtio {
pub async fn analyzer_query(
aux_mutex: &Rc<Mutex<bool>>,
routing_table: &RoutingTable,
routing_table: &drtio_routing::RoutingTable,
up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>,
timer: GlobalTimer,
) -> Result<Vec<RemoteBuffer>, Error> {
) -> Result<Vec<RemoteBuffer>, &'static str> {
let mut remote_buffers: Vec<RemoteBuffer> = Vec::new();
for i in 1..drtio_routing::DEST_COUNT {
if destination_up(up_destinations, i as u8).await {
@ -755,30 +643,29 @@ pub mod drtio {
pub async fn subkernel_upload(
aux_mutex: &Rc<Mutex<bool>>,
routing_table: &RoutingTable,
routing_table: &drtio_routing::RoutingTable,
timer: GlobalTimer,
id: u32,
destination: u8,
data: &Vec<u8>,
) -> Result<(), Error> {
) -> Result<(), &'static str> {
let linkno = routing_table.0[destination as usize][0] - 1;
partition_data(
linkno,
aux_mutex,
routing_table,
timer,
data,
|slice, status, len| Packet::SubkernelAddDataRequest {
|slice, last, len| Packet::SubkernelAddDataRequest {
id: id,
destination: destination,
status: status,
last: last,
length: len as u16,
data: *slice,
},
|reply| match reply {
Packet::SubkernelAddDataReply { succeeded: true } => Ok(()),
Packet::SubkernelAddDataReply { succeeded: false } => Err(Error::SubkernelAddFail(destination)),
_ => Err(Error::UnexpectedReply),
Packet::SubkernelAddDataReply { succeeded: false } => Err("error adding subkernel on satellite"),
_ => Err("adding subkernel failed, unexpected aux packet"),
},
)
.await
@ -786,20 +673,18 @@ pub mod drtio {
pub async fn subkernel_load(
aux_mutex: &Rc<Mutex<bool>>,
routing_table: &RoutingTable,
routing_table: &drtio_routing::RoutingTable,
timer: GlobalTimer,
id: u32,
destination: u8,
run: bool,
) -> Result<(), Error> {
) -> Result<(), &'static str> {
let linkno = routing_table.0[destination as usize][0] - 1;
let reply = aux_transact(
aux_mutex,
linkno,
routing_table,
&Packet::SubkernelLoadRunRequest {
id: id,
source: 0,
destination: destination,
run: run,
},
@ -807,31 +692,24 @@ pub mod drtio {
)
.await?;
match reply {
Packet::SubkernelLoadRunReply {
destination: 0,
succeeded: true,
} => return Ok(()),
Packet::SubkernelLoadRunReply {
destination: 0,
succeeded: false,
} => return Err(Error::SubkernelRunFail(destination)),
_ => Err(Error::UnexpectedReply),
Packet::SubkernelLoadRunReply { succeeded: true } => return Ok(()),
Packet::SubkernelLoadRunReply { succeeded: false } => return Err("error on subkernel run request"),
_ => return Err("received unexpected aux packet during subkernel run"),
}
}
pub async fn subkernel_retrieve_exception(
aux_mutex: &Rc<Mutex<bool>>,
routing_table: &RoutingTable,
routing_table: &drtio_routing::RoutingTable,
timer: GlobalTimer,
destination: u8,
) -> Result<Vec<u8>, Error> {
) -> Result<Vec<u8>, &'static str> {
let linkno = routing_table.0[destination as usize][0] - 1;
let mut remote_data: Vec<u8> = Vec::new();
loop {
let reply = aux_transact(
aux_mutex,
linkno,
routing_table,
&Packet::SubkernelExceptionRequest {
destination: destination,
},
@ -845,37 +723,35 @@ pub mod drtio {
return Ok(remote_data);
}
}
_ => return Err(Error::UnexpectedReply),
_ => return Err("received unexpected aux packet during subkernel exception request"),
}
}
}
pub async fn subkernel_send_message(
aux_mutex: &Rc<Mutex<bool>>,
routing_table: &RoutingTable,
routing_table: &drtio_routing::RoutingTable,
timer: GlobalTimer,
id: u32,
destination: u8,
message: &[u8],
) -> Result<(), Error> {
) -> Result<(), &'static str> {
let linkno = routing_table.0[destination as usize][0] - 1;
partition_data(
linkno,
aux_mutex,
routing_table,
timer,
message,
|slice, status, len| Packet::SubkernelMessage {
source: 0,
|slice, last, len| Packet::SubkernelMessage {
destination: destination,
id: id,
status: status,
last: last,
length: len as u16,
data: *slice,
},
|reply| match reply {
Packet::SubkernelMessageAck { .. } => Ok(()),
_ => Err(Error::UnexpectedReply),
_ => Err("sending message to subkernel failed, unexpected aux packet"),
},
)
.await
@ -888,19 +764,19 @@ pub mod drtio {
pub fn startup(
_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]>>,
_timer: GlobalTimer,
) {
}
#[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(
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]>>,
timer: GlobalTimer,
) {
@ -911,9 +787,9 @@ pub fn startup(
}
#[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 {
csr::rtio_core::reset_write(1);
}
drtio::reset(aux_mutex, routing_table, timer)
drtio::reset(aux_mutex, timer)
}

View File

@ -1,19 +1,18 @@
use alloc::{collections::BTreeMap, rc::Rc, vec::Vec};
use libasync::task;
use libboard_artiq::{drtio_routing::RoutingTable,
drtioaux_proto::{PayloadStatus, MASTER_PAYLOAD_MAX_SIZE}};
use libboard_artiq::{drtio_routing::RoutingTable, drtioaux_proto::MASTER_PAYLOAD_MAX_SIZE};
use libboard_zynq::{time::Milliseconds, timer::GlobalTimer};
use libcortex_a9::mutex::Mutex;
use log::{error, warn};
use log::error;
use crate::rtio_mgt::{drtio, drtio::Error as DrtioError};
use crate::rtio_mgt::drtio;
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum FinishStatus {
Ok,
CommLost,
Exception(u8), // exception source
Exception,
}
#[derive(Debug, PartialEq, Clone, Copy)]
@ -29,13 +28,12 @@ pub enum Error {
Timeout,
IncorrectState,
SubkernelNotFound,
SubkernelException,
CommLost,
DrtioError(DrtioError),
DrtioError(&'static str),
}
impl From<DrtioError> for Error {
fn from(value: DrtioError) -> Error {
impl From<&'static str> for Error {
fn from(value: &'static str) -> Error {
Error::DrtioError(value)
}
}
@ -121,17 +119,15 @@ pub async fn clear_subkernels() {
CURRENT_MESSAGES.async_lock().await.clear();
}
pub async fn subkernel_finished(id: u32, with_exception: bool, exception_src: u8) {
pub async fn subkernel_finished(id: u32, with_exception: bool) {
// called upon receiving DRTIO SubkernelRunDone
// may be None if session ends and is cleared
if let Some(subkernel) = SUBKERNELS.async_lock().await.get_mut(&id) {
if subkernel.state == SubkernelState::Running {
subkernel.state = SubkernelState::Finished {
status: match with_exception {
true => FinishStatus::Exception(exception_src),
false => FinishStatus::Ok,
},
}
subkernel.state = SubkernelState::Finished {
status: match with_exception {
true => FinishStatus::Exception,
false => FinishStatus::Ok,
},
}
}
}
@ -169,34 +165,25 @@ pub async fn await_finish(
routing_table: &RoutingTable,
timer: GlobalTimer,
id: u32,
timeout: i64,
timeout: u64,
) -> Result<SubkernelFinished, Error> {
match SUBKERNELS.async_lock().await.get(&id).unwrap().state {
SubkernelState::Running | SubkernelState::Finished { .. } => (),
_ => return Err(Error::IncorrectState),
}
if timeout > 0 {
let max_time = timer.get_time() + Milliseconds(timeout as u64);
while timer.get_time() < max_time {
let max_time = timer.get_time() + Milliseconds(timeout);
while timer.get_time() < max_time {
{
match SUBKERNELS.async_lock().await.get(&id).unwrap().state {
SubkernelState::Finished { .. } => break,
_ => (),
};
task::r#yield().await;
}
if timer.get_time() >= max_time {
error!("Remote subkernel finish await timed out");
return Err(Error::Timeout);
}
} else {
// no timeout, wait forever
loop {
match SUBKERNELS.async_lock().await.get(&id).unwrap().state {
SubkernelState::Finished { .. } => break,
_ => (),
};
task::r#yield().await;
}
task::r#yield().await;
}
if timer.get_time() >= max_time {
error!("Remote subkernel finish await timed out");
return Err(Error::Timeout);
}
if let Some(subkernel) = SUBKERNELS.async_lock().await.get_mut(&id) {
match subkernel.state {
@ -205,8 +192,11 @@ pub async fn await_finish(
Ok(SubkernelFinished {
id: id,
status: status,
exception: if let FinishStatus::Exception(dest) = status {
Some(drtio::subkernel_retrieve_exception(aux_mutex, routing_table, timer, dest).await?)
exception: if status == FinishStatus::Exception {
Some(
drtio::subkernel_retrieve_exception(aux_mutex, routing_table, timer, subkernel.destination)
.await?,
)
} else {
None
},
@ -222,6 +212,7 @@ pub async fn await_finish(
pub struct Message {
from_id: u32,
pub count: u8,
pub tag: u8,
pub data: Vec<u8>,
}
@ -230,28 +221,13 @@ static MESSAGE_QUEUE: Mutex<Vec<Message>> = Mutex::new(Vec::new());
// currently under construction message(s) (can be from multiple sources)
static CURRENT_MESSAGES: Mutex<BTreeMap<u32, Message>> = Mutex::new(BTreeMap::new());
pub async fn message_handle_incoming(
id: u32,
status: PayloadStatus,
length: usize,
data: &[u8; MASTER_PAYLOAD_MAX_SIZE],
) {
pub async fn message_handle_incoming(id: u32, last: bool, length: usize, data: &[u8; MASTER_PAYLOAD_MAX_SIZE]) {
// called when receiving a message from satellite
{
let subkernel_lock = SUBKERNELS.async_lock().await;
let subkernel = subkernel_lock.get(&id);
if subkernel.is_some() && subkernel.unwrap().state != SubkernelState::Running {
// do not add messages for non-running or deleted subkernels
warn!("received a message for a non-running subkernel #{}", id);
return;
}
if SUBKERNELS.async_lock().await.get(&id).is_none() {
// do not add messages for non-existing or deleted subkernels
return;
}
let mut current_messages = CURRENT_MESSAGES.async_lock().await;
if status.is_first() {
current_messages.remove(&id);
}
match current_messages.get_mut(&id) {
Some(message) => message.data.extend(&data[..length]),
None => {
@ -260,12 +236,13 @@ pub async fn message_handle_incoming(
Message {
from_id: id,
count: data[0],
data: data[1..length].to_vec(),
tag: data[1],
data: data[2..length].to_vec(),
},
);
}
};
if status.is_last() {
if last {
// when done, remove from working queue
MESSAGE_QUEUE
.async_lock()
@ -274,19 +251,16 @@ pub async fn message_handle_incoming(
}
}
pub async fn message_await(id: u32, timeout: i64, timer: GlobalTimer) -> Result<Message, Error> {
let is_subkernel = SUBKERNELS.async_lock().await.get(&id).is_some();
if is_subkernel {
match SUBKERNELS.async_lock().await.get(&id).unwrap().state {
SubkernelState::Finished {
status: FinishStatus::CommLost,
} => return Err(Error::CommLost),
SubkernelState::Running | SubkernelState::Finished { .. } => (),
_ => return Err(Error::IncorrectState),
}
pub async fn message_await(id: u32, timeout: u64, timer: GlobalTimer) -> Result<Message, Error> {
match SUBKERNELS.async_lock().await.get(&id).unwrap().state {
SubkernelState::Finished {
status: FinishStatus::CommLost,
} => return Err(Error::CommLost),
SubkernelState::Running | SubkernelState::Finished { .. } => (),
_ => return Err(Error::IncorrectState),
}
let max_time = timer.get_time() + Milliseconds(timeout as u64);
while timeout < 0 || (timeout > 0 && timer.get_time() < max_time) {
let max_time = timer.get_time() + Milliseconds(timeout);
while timer.get_time() < max_time {
{
let mut message_queue = MESSAGE_QUEUE.async_lock().await;
for i in 0..message_queue.len() {
@ -297,17 +271,6 @@ pub async fn message_await(id: u32, timeout: i64, timer: GlobalTimer) -> Result<
}
}
}
if is_subkernel {
match SUBKERNELS.async_lock().await.get(&id).unwrap().state {
SubkernelState::Finished {
status: FinishStatus::CommLost,
} => return Err(Error::CommLost),
SubkernelState::Finished {
status: FinishStatus::Exception(_),
} => return Err(Error::SubkernelException),
_ => (),
}
}
task::r#yield().await;
}
Err(Error::Timeout)
@ -318,8 +281,9 @@ pub async fn message_send<'a>(
routing_table: &RoutingTable,
timer: GlobalTimer,
id: u32,
destination: u8,
message: Vec<u8>,
) -> Result<(), Error> {
let destination = SUBKERNELS.async_lock().await.get(&id).unwrap().destination;
// rpc data prepared by the kernel core already
Ok(drtio::subkernel_send_message(aux_mutex, routing_table, timer, id, destination, &message).await?)
}

View File

@ -7,7 +7,6 @@ build = "build.rs"
[features]
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"]
calibrate_wrpll_skew = ["libboard_artiq/calibrate_wrpll_skew"]
default = ["target_zc706", ]
[build-dependencies]

View File

@ -1,13 +1,7 @@
use alloc::{collections::btree_map::BTreeMap, string::String, vec::Vec};
use core::mem;
use alloc::{collections::btree_map::BTreeMap, vec::Vec};
use ksupport::kernel::DmaRecorder;
use libboard_artiq::{drtio_routing::RoutingTable,
drtioaux_proto::{Packet, PayloadStatus, MASTER_PAYLOAD_MAX_SIZE},
pl::csr};
use libboard_artiq::pl::csr;
use libcortex_a9::cache::dcci_slice;
use routing::{Router, Sliceable};
use subkernel::Manager as KernelManager;
const ALIGNMENT: usize = 64;
@ -18,20 +12,16 @@ enum ManagerState {
}
pub struct RtioStatus {
pub source: u8,
pub id: u32,
pub error: u8,
pub channel: u32,
pub timestamp: u64,
}
#[derive(Debug)]
pub enum Error {
IdNotFound,
PlaybackInProgress,
EntryNotComplete,
MasterDmaFound,
UploadFail,
}
#[derive(Debug)]
@ -39,228 +29,13 @@ struct Entry {
trace: Vec<u8>,
padding_len: usize,
complete: bool,
duration: i64, // relevant for local DMA
}
impl Entry {
pub fn from_vec(data: Vec<u8>, duration: i64) -> Entry {
let mut entry = Entry {
trace: data,
padding_len: 0,
complete: true,
duration: duration,
};
entry.realign();
entry
}
pub fn id(&self) -> u32 {
self.trace[self.padding_len..].as_ptr() as u32
}
pub fn realign(&mut self) {
self.trace.push(0);
let data_len = self.trace.len();
self.trace.reserve(ALIGNMENT - 1);
let padding = ALIGNMENT - self.trace.as_ptr() as usize % ALIGNMENT;
let padding = if padding == ALIGNMENT { 0 } else { padding };
for _ in 0..padding {
// Vec guarantees that this will not reallocate
self.trace.push(0)
}
for i in 1..data_len + 1 {
self.trace[data_len + padding - i] = self.trace[data_len - i]
}
self.complete = true;
self.padding_len = padding;
dcci_slice(&self.trace);
}
}
#[derive(Debug)]
enum RemoteTraceState {
Unsent,
Sending(usize),
Ready,
Running(usize),
}
#[derive(Debug)]
struct RemoteTraces {
remote_traces: BTreeMap<u8, Sliceable>,
state: RemoteTraceState,
}
impl RemoteTraces {
pub fn new(traces: BTreeMap<u8, Sliceable>) -> RemoteTraces {
RemoteTraces {
remote_traces: traces,
state: RemoteTraceState::Unsent,
}
}
// on subkernel request
pub fn upload_traces(
&mut self,
id: u32,
router: &mut Router,
rank: u8,
self_destination: u8,
routing_table: &RoutingTable,
) -> usize {
let len = self.remote_traces.len();
if len > 0 {
self.state = RemoteTraceState::Sending(self.remote_traces.len());
for (dest, trace) in self.remote_traces.iter_mut() {
// queue up the first packet for all destinations, rest will be sent after first ACK
let mut data_slice: [u8; MASTER_PAYLOAD_MAX_SIZE] = [0; MASTER_PAYLOAD_MAX_SIZE];
let meta = trace.get_slice_master(&mut data_slice);
router.route(
Packet::DmaAddTraceRequest {
source: self_destination,
destination: *dest,
id: id,
status: meta.status,
length: meta.len,
trace: data_slice,
},
routing_table,
rank,
self_destination,
);
}
}
len
}
// on incoming Packet::DmaAddTraceReply
pub fn ack_upload(
&mut self,
kernel_manager: &mut KernelManager,
source: u8,
id: u32,
succeeded: bool,
router: &mut Router,
rank: u8,
self_destination: u8,
routing_table: &RoutingTable,
) {
if let RemoteTraceState::Sending(count) = self.state {
if let Some(trace) = self.remote_traces.get_mut(&source) {
if trace.at_end() {
if count - 1 == 0 {
self.state = RemoteTraceState::Ready;
if let Some((id, timestamp)) = kernel_manager.ddma_remote_uploaded(succeeded) {
self.playback(id, timestamp, router, rank, self_destination, routing_table);
}
} else {
self.state = RemoteTraceState::Sending(count - 1);
}
} else {
// send next slice
let mut data_slice: [u8; MASTER_PAYLOAD_MAX_SIZE] = [0; MASTER_PAYLOAD_MAX_SIZE];
let meta = trace.get_slice_master(&mut data_slice);
router.route(
Packet::DmaAddTraceRequest {
source: self_destination,
destination: meta.destination,
id: id,
status: meta.status,
length: meta.len,
trace: data_slice,
},
routing_table,
rank,
self_destination,
);
}
}
}
}
// on subkernel request
pub fn playback(
&mut self,
id: u32,
timestamp: u64,
router: &mut Router,
rank: u8,
self_destination: u8,
routing_table: &RoutingTable,
) {
// route all the playback requests
// remote traces (local trace runs on core1 unlike mainline firmware)
self.state = RemoteTraceState::Running(self.remote_traces.len());
for (dest, _) in self.remote_traces.iter() {
router.route(
Packet::DmaPlaybackRequest {
source: self_destination,
destination: *dest,
id: id,
timestamp: timestamp,
},
routing_table,
rank,
self_destination,
);
// response will be ignored (succeeded = false handled by the main thread)
}
}
// on incoming Packet::DmaPlaybackDone
pub fn remote_finished(&mut self, kernel_manager: &mut KernelManager, error: u8, channel: u32, timestamp: u64) {
if let RemoteTraceState::Running(count) = self.state {
if error != 0 || count - 1 == 0 {
// notify the kernel about a DDMA error or finish
kernel_manager.ddma_finished(error, channel, timestamp);
self.state = RemoteTraceState::Ready;
// further messages will be ignored (if there was an error)
} else {
// no error and not the last one awaited
self.state = RemoteTraceState::Running(count - 1);
}
}
}
pub fn erase(
&mut self,
id: u32,
router: &mut Router,
rank: u8,
self_destination: u8,
routing_table: &RoutingTable,
) {
for (dest, _) in self.remote_traces.iter() {
router.route(
Packet::DmaRemoveTraceRequest {
source: self_destination,
destination: *dest,
id: id,
},
routing_table,
rank,
self_destination,
);
// response will be ignored as this object will stop existing too
}
}
pub fn has_remote_traces(&self) -> bool {
self.remote_traces.len() > 0
}
}
#[derive(Debug)]
pub struct Manager {
entries: BTreeMap<(u8, u32), Entry>,
entries: BTreeMap<u32, Entry>,
state: ManagerState,
current_id: u32,
current_source: u8,
remote_entries: BTreeMap<u32, RemoteTraces>,
name_map: BTreeMap<String, u32>,
currentid: u32,
}
impl Manager {
@ -270,238 +45,79 @@ impl Manager {
unsafe { while csr::rtio_dma::enable_read() != 0 {} }
Manager {
entries: BTreeMap::new(),
current_id: 0,
current_source: 0,
currentid: 0,
state: ManagerState::Idle,
remote_entries: BTreeMap::new(),
name_map: BTreeMap::new(),
}
}
pub fn add(
&mut self,
source: u8,
id: u32,
status: PayloadStatus,
trace: &[u8],
trace_len: usize,
) -> Result<(), Error> {
let entry = match self.entries.get_mut(&(source, id)) {
pub fn add(&mut self, id: u32, last: bool, trace: &[u8], trace_len: usize) -> Result<(), Error> {
let entry = match self.entries.get_mut(&id) {
Some(entry) => {
if entry.complete || status.is_first() {
if entry.complete {
// replace entry
self.entries.remove(&(source, id));
self.entries.remove(&id);
self.entries.insert(
(source, id),
id,
Entry {
trace: Vec::new(),
padding_len: 0,
complete: false,
duration: 0,
},
);
self.entries.get_mut(&(source, id)).unwrap()
self.entries.get_mut(&id).unwrap()
} else {
entry
}
}
None => {
self.entries.insert(
(source, id),
id,
Entry {
trace: Vec::new(),
padding_len: 0,
complete: false,
duration: 0,
},
);
self.entries.get_mut(&(source, id)).unwrap()
self.entries.get_mut(&id).unwrap()
}
};
entry.trace.extend(&trace[0..trace_len]);
if status.is_last() {
entry.realign();
if last {
entry.trace.push(0);
let data_len = entry.trace.len();
// Realign.
entry.trace.reserve(ALIGNMENT - 1);
let padding = ALIGNMENT - entry.trace.as_ptr() as usize % ALIGNMENT;
let padding = if padding == ALIGNMENT { 0 } else { padding };
for _ in 0..padding {
// Vec guarantees that this will not reallocate
entry.trace.push(0)
}
for i in 1..data_len + 1 {
entry.trace[data_len + padding - i] = entry.trace[data_len - i]
}
entry.complete = true;
entry.padding_len = padding;
dcci_slice(&entry.trace);
}
Ok(())
}
// api for DRTIO
pub fn erase(&mut self, source: u8, id: u32) -> Result<(), Error> {
match self.entries.remove(&(source, id)) {
pub fn erase(&mut self, id: u32) -> Result<(), Error> {
match self.entries.remove(&id) {
Some(_) => Ok(()),
None => Err(Error::IdNotFound),
}
}
// API for subkernel
pub fn erase_name(
&mut self,
name: &str,
router: &mut Router,
rank: u8,
self_destination: u8,
routing_table: &RoutingTable,
) {
if let Some(id) = self.name_map.get(name) {
if let Some(traces) = self.remote_entries.get_mut(&id) {
traces.erase(*id, router, rank, self_destination, routing_table);
self.remote_entries.remove(&id);
}
self.entries.remove(&(self_destination, *id));
self.name_map.remove(name);
}
}
pub fn remote_finished(
&mut self,
kernel_manager: &mut KernelManager,
id: u32,
error: u8,
channel: u32,
timestamp: u64,
) {
if let Some(entry) = self.remote_entries.get_mut(&id) {
entry.remote_finished(kernel_manager, error, channel, timestamp);
}
}
pub fn ack_upload(
&mut self,
kernel_manager: &mut KernelManager,
source: u8,
id: u32,
succeeded: bool,
router: &mut Router,
rank: u8,
self_destination: u8,
routing_table: &RoutingTable,
) {
if let Some(entry) = self.remote_entries.get_mut(&id) {
entry.ack_upload(
kernel_manager,
source,
id,
succeeded,
router,
rank,
self_destination,
routing_table,
);
}
}
// API for subkernel
pub fn upload_traces(
&mut self,
id: u32,
router: &mut Router,
rank: u8,
self_destination: u8,
routing_table: &RoutingTable,
) -> Result<usize, Error> {
let remote_traces = self.remote_entries.get_mut(&id);
let mut len = 0;
if let Some(traces) = remote_traces {
len = traces.upload_traces(id, router, rank, self_destination, routing_table);
}
Ok(len)
}
// API for subkernel
pub fn playback_remote(
&mut self,
id: u32,
timestamp: u64,
router: &mut Router,
rank: u8,
self_destination: u8,
routing_table: &RoutingTable,
) -> Result<(), Error> {
if let Some(traces) = self.remote_entries.get_mut(&id) {
traces.playback(id, timestamp, router, rank, self_destination, routing_table);
Ok(())
} else {
Err(Error::IdNotFound)
}
}
// API for subkernel
pub fn cleanup(&mut self, router: &mut Router, rank: u8, self_destination: u8, routing_table: &RoutingTable) {
// after subkernel ends, remove all self-generated traces
for (_, id) in self.name_map.iter_mut() {
if let Some(traces) = self.remote_entries.get_mut(&id) {
traces.erase(*id, router, rank, self_destination, routing_table);
self.remote_entries.remove(&id);
}
self.entries.remove(&(self_destination, *id));
}
self.name_map.clear();
}
// API for subkernel
pub fn retrieve(&self, self_destination: u8, name: &String) -> Option<(i32, i64, bool)> {
let id = self.name_map.get(name)?;
let duration = self.entries.get(&(self_destination, *id))?.duration;
let uses_ddma = self.has_remote_traces(*id);
Some((*id as i32, duration, uses_ddma))
}
pub fn has_remote_traces(&self, id: u32) -> bool {
match self.remote_entries.get(&id) {
Some(traces) => traces.has_remote_traces(),
_ => false,
}
}
pub fn put_record(&mut self, mut recorder: DmaRecorder, self_destination: u8) -> Result<u32, Error> {
let mut remote_traces: BTreeMap<u8, Sliceable> = BTreeMap::new();
let mut local_trace: Vec<u8> = Vec::new();
// analyze each entry and put in proper buckets, as the kernel core
// sends whole chunks, to limit comms/kernel CPU communication,
// and as only comms core has access to varios DMA buffers.
let mut ptr = 0;
recorder.buffer.push(0);
while recorder.buffer[ptr] != 0 {
// ptr + 3 = tgt >> 24 (destination)
let len = recorder.buffer[ptr] as usize;
let destination = recorder.buffer[ptr + 3];
if destination == 0 {
return Err(Error::MasterDmaFound);
} else if destination == self_destination {
local_trace.extend(&recorder.buffer[ptr..ptr + len]);
} else {
if let Some(remote_trace) = remote_traces.get_mut(&destination) {
remote_trace.extend(&recorder.buffer[ptr..ptr + len]);
} else {
remote_traces.insert(
destination,
Sliceable::new(destination, recorder.buffer[ptr..ptr + len].to_vec()),
);
}
}
// and jump to the next event
ptr += len;
}
let local_entry = Entry::from_vec(local_trace, recorder.duration);
let id = local_entry.id();
self.entries.insert((self_destination, id), local_entry);
self.remote_entries.insert(id, RemoteTraces::new(remote_traces));
let mut name = String::new();
mem::swap(&mut recorder.name, &mut name);
self.name_map.insert(name, id);
Ok(id)
}
pub fn playback(&mut self, source: u8, id: u32, timestamp: u64) -> Result<(), Error> {
pub fn playback(&mut self, id: u32, timestamp: u64) -> Result<(), Error> {
if self.state != ManagerState::Idle {
return Err(Error::PlaybackInProgress);
}
let entry = match self.entries.get(&(source, id)) {
let entry = match self.entries.get(&id) {
Some(entry) => entry,
None => {
return Err(Error::IdNotFound);
@ -514,8 +130,7 @@ impl Manager {
assert!(ptr as u32 % 64 == 0);
self.state = ManagerState::Playback;
self.current_id = id;
self.current_source = source;
self.currentid = id;
unsafe {
csr::rtio_dma::base_address_write(ptr as u32);
@ -547,8 +162,7 @@ impl Manager {
csr::rtio_dma::error_write(1);
}
return Some(RtioStatus {
source: self.current_source,
id: self.current_id,
id: self.currentid,
error: error,
channel: channel,
timestamp: timestamp,

View File

@ -29,8 +29,6 @@ use libboard_artiq::grabber;
use libboard_artiq::io_expander;
#[cfg(has_si5324)]
use libboard_artiq::si5324;
#[cfg(has_si549)]
use libboard_artiq::si549;
use libboard_artiq::{drtio_routing, drtioaux,
drtioaux_proto::{MASTER_PAYLOAD_MAX_SIZE, SAT_PAYLOAD_MAX_SIZE},
identifier_read, logger,
@ -40,21 +38,14 @@ use libboard_zynq::error_led::ErrorLED;
use libboard_zynq::{i2c::I2c, print, println, time::Milliseconds, timer::GlobalTimer};
use libcortex_a9::{l2c::enable_l2_cache, regs::MPIDR};
use libregister::RegisterR;
use libsupport_zynq::{exception_vectors, ram};
use routing::Router;
use libsupport_zynq::ram;
use subkernel::Manager as KernelManager;
mod analyzer;
mod dma;
mod repeater;
mod routing;
mod subkernel;
// linker symbols
extern "C" {
static __exceptions_start: u32;
}
fn drtiosat_reset(reset: bool) {
unsafe {
csr::drtiosat::reset_write(if reset { 1 } else { 0 });
@ -88,11 +79,7 @@ macro_rules! forward {
if hop != 0 {
let repno = (hop - 1) as usize;
if repno < $repeaters.len() {
if $packet.expects_response() {
return $repeaters[repno].aux_forward($packet, $timer);
} else {
return $repeaters[repno].aux_send($packet);
}
return $repeaters[repno].aux_forward($packet, $timer);
} else {
return Err(drtioaux::Error::RoutingError);
}
@ -108,15 +95,13 @@ macro_rules! forward {
fn process_aux_packet(
_repeaters: &mut [repeater::Repeater],
_routing_table: &mut drtio_routing::RoutingTable,
rank: &mut u8,
self_destination: &mut u8,
_rank: &mut u8,
packet: drtioaux::Packet,
timer: &mut GlobalTimer,
i2c: &mut I2c,
dma_manager: &mut DmaManager,
analyzer: &mut Analyzer,
kernel_manager: &mut KernelManager,
router: &mut Router,
) -> Result<(), drtioaux::Error> {
// In the code below, *_chan_sel_write takes an u8 if there are fewer than 256 channels,
// and u16 otherwise; hence the `as _` conversion.
@ -137,39 +122,82 @@ fn process_aux_packet(
drtioaux::Packet::DestinationStatusRequest { destination } => {
#[cfg(has_drtio_routing)]
let hop = _routing_table.0[destination as usize][*rank as usize];
let hop = _routing_table.0[destination as usize][*_rank as usize];
#[cfg(not(has_drtio_routing))]
let hop = 0;
if hop == 0 {
*self_destination = destination;
let errors;
unsafe {
errors = csr::drtiosat::rtio_error_read();
}
if errors & 1 != 0 {
let channel;
unsafe {
channel = csr::drtiosat::sequence_error_channel_read();
csr::drtiosat::rtio_error_write(1);
if let Some(status) = dma_manager.check_state() {
info!(
"playback done, error: {}, channel: {}, timestamp: {}",
status.error, status.channel, status.timestamp
);
drtioaux::send(
0,
&drtioaux::Packet::DmaPlaybackStatus {
destination: destination,
id: status.id,
error: status.error,
channel: status.channel,
timestamp: status.timestamp,
},
)?;
} else if let Some(subkernel_finished) = kernel_manager.get_last_finished() {
info!(
"subkernel {} finished, with exception: {}",
subkernel_finished.id, subkernel_finished.with_exception
);
drtioaux::send(
0,
&drtioaux::Packet::SubkernelFinished {
id: subkernel_finished.id,
with_exception: subkernel_finished.with_exception,
},
)?;
} else if kernel_manager.message_is_ready() {
let mut data_slice: [u8; MASTER_PAYLOAD_MAX_SIZE] = [0; MASTER_PAYLOAD_MAX_SIZE];
match kernel_manager.message_get_slice(&mut data_slice) {
Some(meta) => drtioaux::send(
0,
&drtioaux::Packet::SubkernelMessage {
destination: destination,
id: kernel_manager.get_current_id().unwrap(),
last: meta.last,
length: meta.len as u16,
data: data_slice,
},
)?,
None => warn!("subkernel message is ready but no message is present"),
}
drtioaux::send(0, &drtioaux::Packet::DestinationSequenceErrorReply { channel })?;
} else if errors & 2 != 0 {
let channel;
unsafe {
channel = csr::drtiosat::collision_channel_read();
csr::drtiosat::rtio_error_write(2);
}
drtioaux::send(0, &drtioaux::Packet::DestinationCollisionReply { channel })?;
} else if errors & 4 != 0 {
let channel;
unsafe {
channel = csr::drtiosat::busy_channel_read();
csr::drtiosat::rtio_error_write(4);
}
drtioaux::send(0, &drtioaux::Packet::DestinationBusyReply { channel })?;
} else {
drtioaux::send(0, &drtioaux::Packet::DestinationOkReply)?;
let errors;
unsafe {
errors = csr::drtiosat::rtio_error_read();
}
if errors & 1 != 0 {
let channel;
unsafe {
channel = csr::drtiosat::sequence_error_channel_read();
csr::drtiosat::rtio_error_write(1);
}
drtioaux::send(0, &drtioaux::Packet::DestinationSequenceErrorReply { channel })?;
} else if errors & 2 != 0 {
let channel;
unsafe {
channel = csr::drtiosat::collision_channel_read();
csr::drtiosat::rtio_error_write(2);
}
drtioaux::send(0, &drtioaux::Packet::DestinationCollisionReply { channel })?;
} else if errors & 4 != 0 {
let channel;
unsafe {
channel = csr::drtiosat::busy_channel_read();
csr::drtiosat::rtio_error_write(4);
}
drtioaux::send(0, &drtioaux::Packet::DestinationBusyReply { channel })?;
} else {
drtioaux::send(0, &drtioaux::Packet::DestinationOkReply)?;
}
}
}
@ -214,11 +242,11 @@ fn process_aux_packet(
drtioaux::send(0, &drtioaux::Packet::RoutingAck)
}
#[cfg(has_drtio_routing)]
drtioaux::Packet::RoutingSetRank { rank: new_rank } => {
*rank = new_rank;
drtio_routing::interconnect_enable_all(_routing_table, new_rank);
drtioaux::Packet::RoutingSetRank { rank } => {
*_rank = rank;
drtio_routing::interconnect_enable_all(_routing_table, rank);
let rep_rank = new_rank + 1;
let rep_rank = rank + 1;
for rep in _repeaters.iter() {
if let Err(e) = rep.set_rank(rep_rank, timer) {
error!("failed to set rank ({:?})", e);
@ -244,7 +272,7 @@ fn process_aux_packet(
channel,
probe,
} => {
forward!(_routing_table, _destination, *rank, _repeaters, &packet, timer);
forward!(_routing_table, _destination, *_rank, _repeaters, &packet, timer);
let value;
#[cfg(has_rtio_moninj)]
unsafe {
@ -266,7 +294,7 @@ fn process_aux_packet(
overrd,
value,
} => {
forward!(_routing_table, _destination, *rank, _repeaters, &packet, timer);
forward!(_routing_table, _destination, *_rank, _repeaters, &packet, timer);
#[cfg(has_rtio_moninj)]
unsafe {
csr::rtio_moninj::inj_chan_sel_write(channel as _);
@ -280,7 +308,7 @@ fn process_aux_packet(
channel,
overrd,
} => {
forward!(_routing_table, _destination, *rank, _repeaters, &packet, timer);
forward!(_routing_table, _destination, *_rank, _repeaters, &packet, timer);
let value;
#[cfg(has_rtio_moninj)]
unsafe {
@ -299,7 +327,7 @@ fn process_aux_packet(
destination: _destination,
busno: _busno,
} => {
forward!(_routing_table, _destination, *rank, _repeaters, &packet, timer);
forward!(_routing_table, _destination, *_rank, _repeaters, &packet, timer);
let succeeded = i2c.start().is_ok();
drtioaux::send(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded })
}
@ -307,7 +335,7 @@ fn process_aux_packet(
destination: _destination,
busno: _busno,
} => {
forward!(_routing_table, _destination, *rank, _repeaters, &packet, timer);
forward!(_routing_table, _destination, *_rank, _repeaters, &packet, timer);
let succeeded = i2c.restart().is_ok();
drtioaux::send(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded })
}
@ -315,7 +343,7 @@ fn process_aux_packet(
destination: _destination,
busno: _busno,
} => {
forward!(_routing_table, _destination, *rank, _repeaters, &packet, timer);
forward!(_routing_table, _destination, *_rank, _repeaters, &packet, timer);
let succeeded = i2c.stop().is_ok();
drtioaux::send(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded })
}
@ -324,7 +352,7 @@ fn process_aux_packet(
busno: _busno,
data,
} => {
forward!(_routing_table, _destination, *rank, _repeaters, &packet, timer);
forward!(_routing_table, _destination, *_rank, _repeaters, &packet, timer);
match i2c.write(data) {
Ok(ack) => drtioaux::send(
0,
@ -347,7 +375,7 @@ fn process_aux_packet(
busno: _busno,
ack,
} => {
forward!(_routing_table, _destination, *rank, _repeaters, &packet, timer);
forward!(_routing_table, _destination, *_rank, _repeaters, &packet, timer);
match i2c.read(ack) {
Ok(data) => drtioaux::send(
0,
@ -371,7 +399,7 @@ fn process_aux_packet(
address,
mask,
} => {
forward!(_routing_table, _destination, *rank, _repeaters, &packet, timer);
forward!(_routing_table, _destination, *_rank, _repeaters, &packet, timer);
let ch = match mask {
//decode from mainline, PCA9548-centric API
0x00 => None,
@ -397,7 +425,7 @@ fn process_aux_packet(
div: _div,
cs: _cs,
} => {
forward!(_routing_table, _destination, *rank, _repeaters, &packet, timer);
forward!(_routing_table, _destination, *_rank, _repeaters, &packet, timer);
// todo: reimplement when/if SPI is available
//let succeeded = spi::set_config(busno, flags, length, div, cs).is_ok();
drtioaux::send(0, &drtioaux::Packet::SpiBasicReply { succeeded: false })
@ -407,7 +435,7 @@ fn process_aux_packet(
busno: _busno,
data: _data,
} => {
forward!(_routing_table, _destination, *rank, _repeaters, &packet, timer);
forward!(_routing_table, _destination, *_rank, _repeaters, &packet, timer);
// todo: reimplement when/if SPI is available
//let succeeded = spi::write(busno, data).is_ok();
drtioaux::send(0, &drtioaux::Packet::SpiBasicReply { succeeded: false })
@ -416,7 +444,7 @@ fn process_aux_packet(
destination: _destination,
busno: _busno,
} => {
forward!(_routing_table, _destination, *rank, _repeaters, &packet, timer);
forward!(_routing_table, _destination, *_rank, _repeaters, &packet, timer);
// todo: reimplement when/if SPI is available
// match spi::read(busno) {
// Ok(data) => drtioaux::send(0,
@ -436,7 +464,7 @@ fn process_aux_packet(
drtioaux::Packet::AnalyzerHeaderRequest {
destination: _destination,
} => {
forward!(_routing_table, _destination, *rank, _repeaters, &packet, timer);
forward!(_routing_table, _destination, *_rank, _repeaters, &packet, timer);
let header = analyzer.get_header();
drtioaux::send(
0,
@ -450,7 +478,7 @@ fn process_aux_packet(
drtioaux::Packet::AnalyzerDataRequest {
destination: _destination,
} => {
forward!(_routing_table, _destination, *rank, _repeaters, &packet, timer);
forward!(_routing_table, _destination, *_rank, _repeaters, &packet, timer);
let mut data_slice: [u8; SAT_PAYLOAD_MAX_SIZE] = [0; SAT_PAYLOAD_MAX_SIZE];
let meta = analyzer.get_data(&mut data_slice);
drtioaux::send(
@ -464,135 +492,55 @@ fn process_aux_packet(
}
drtioaux::Packet::DmaAddTraceRequest {
source,
destination,
destination: _destination,
id,
status,
last,
length,
trace,
} => {
forward!(_routing_table, destination, *rank, _repeaters, &packet, timer);
*self_destination = destination;
let succeeded = dma_manager.add(source, id, status, &trace, length as usize).is_ok();
router.send(
drtioaux::Packet::DmaAddTraceReply {
source: *self_destination,
destination: source,
id: id,
succeeded: succeeded,
},
_routing_table,
*rank,
*self_destination,
)
}
drtioaux::Packet::DmaAddTraceReply {
source,
destination: _destination,
id,
succeeded,
} => {
forward!(_routing_table, _destination, *rank, _repeaters, &packet, timer);
dma_manager.ack_upload(
kernel_manager,
source,
id,
succeeded,
router,
*rank,
*self_destination,
_routing_table,
);
Ok(())
forward!(_routing_table, _destination, *_rank, _repeaters, &packet, timer);
let succeeded = dma_manager.add(id, last, &trace, length as usize).is_ok();
drtioaux::send(0, &drtioaux::Packet::DmaAddTraceReply { succeeded: succeeded })
}
drtioaux::Packet::DmaRemoveTraceRequest {
source,
destination: _destination,
id,
} => {
forward!(_routing_table, _destination, *rank, _repeaters, &packet, timer);
let succeeded = dma_manager.erase(source, id).is_ok();
router.send(
drtioaux::Packet::DmaRemoveTraceReply {
destination: source,
succeeded: succeeded,
},
_routing_table,
*rank,
*self_destination,
)
}
drtioaux::Packet::DmaRemoveTraceReply {
destination: _destination,
succeeded: _,
} => {
forward!(_routing_table, _destination, *rank, _repeaters, &packet, timer);
Ok(())
forward!(_routing_table, _destination, *_rank, _repeaters, &packet, timer);
let succeeded = dma_manager.erase(id).is_ok();
drtioaux::send(0, &drtioaux::Packet::DmaRemoveTraceReply { succeeded: succeeded })
}
drtioaux::Packet::DmaPlaybackRequest {
source,
destination: _destination,
id,
timestamp,
} => {
forward!(_routing_table, _destination, *rank, _repeaters, &packet, timer);
forward!(_routing_table, _destination, *_rank, _repeaters, &packet, timer);
let succeeded = if !kernel_manager.running() {
dma_manager.playback(source, id, timestamp).is_ok()
dma_manager.playback(id, timestamp).is_ok()
} else {
false
};
router.send(
drtioaux::Packet::DmaPlaybackReply {
destination: source,
succeeded: succeeded,
},
_routing_table,
*rank,
*self_destination,
)
}
drtioaux::Packet::DmaPlaybackReply {
destination: _destination,
succeeded,
} => {
forward!(_routing_table, _destination, *rank, _repeaters, &packet, timer);
if !succeeded {
kernel_manager.ddma_nack();
}
Ok(())
}
drtioaux::Packet::DmaPlaybackStatus {
source: _,
destination: _destination,
id,
error,
channel,
timestamp,
} => {
forward!(_routing_table, _destination, *rank, _repeaters, &packet, timer);
dma_manager.remote_finished(kernel_manager, id, error, channel, timestamp);
Ok(())
drtioaux::send(0, &drtioaux::Packet::DmaPlaybackReply { succeeded: succeeded })
}
drtioaux::Packet::SubkernelAddDataRequest {
destination,
destination: _destination,
id,
status,
last,
length,
data,
} => {
forward!(_routing_table, destination, *rank, _repeaters, &packet, timer);
*self_destination = destination;
let succeeded = kernel_manager.add(id, status, &data, length as usize).is_ok();
forward!(_routing_table, _destination, *_rank, _repeaters, &packet, timer);
let succeeded = kernel_manager.add(id, last, &data, length as usize).is_ok();
drtioaux::send(0, &drtioaux::Packet::SubkernelAddDataReply { succeeded: succeeded })
}
drtioaux::Packet::SubkernelLoadRunRequest {
source,
destination: _destination,
id,
run,
} => {
forward!(_routing_table, _destination, *rank, _repeaters, &packet, timer);
forward!(_routing_table, _destination, *_rank, _repeaters, &packet, timer);
let mut succeeded = kernel_manager.load(id).is_ok();
// allow preloading a kernel with delayed run
if run {
@ -600,91 +548,59 @@ fn process_aux_packet(
// cannot run kernel while DDMA is running
succeeded = false;
} else {
succeeded |= kernel_manager.run(source, id).is_ok();
succeeded |= kernel_manager.run(id).is_ok();
}
}
router.send(
drtioaux::Packet::SubkernelLoadRunReply {
destination: source,
succeeded: succeeded,
},
_routing_table,
*rank,
*self_destination,
)
}
drtioaux::Packet::SubkernelLoadRunReply {
destination: _destination,
succeeded,
} => {
forward!(_routing_table, _destination, *rank, _repeaters, &packet, timer);
// received if local subkernel started another, remote subkernel
kernel_manager.subkernel_load_run_reply(succeeded);
Ok(())
}
drtioaux::Packet::SubkernelFinished {
destination: _destination,
id,
with_exception,
exception_src,
} => {
forward!(_routing_table, _destination, *rank, _repeaters, &packet, timer);
kernel_manager.remote_subkernel_finished(id, with_exception, exception_src);
Ok(())
drtioaux::send(0, &drtioaux::Packet::SubkernelLoadRunReply { succeeded: succeeded })
}
drtioaux::Packet::SubkernelExceptionRequest {
destination: _destination,
} => {
forward!(_routing_table, _destination, *rank, _repeaters, &packet, timer);
forward!(_routing_table, _destination, *_rank, _repeaters, &packet, timer);
let mut data_slice: [u8; SAT_PAYLOAD_MAX_SIZE] = [0; SAT_PAYLOAD_MAX_SIZE];
let meta = kernel_manager.exception_get_slice(&mut data_slice);
drtioaux::send(
0,
&drtioaux::Packet::SubkernelException {
last: meta.status.is_last(),
last: meta.last,
length: meta.len,
data: data_slice,
},
)
}
drtioaux::Packet::SubkernelMessage {
source,
destination: _destination,
id,
status,
destination,
id: _id,
last,
length,
data,
} => {
forward!(_routing_table, _destination, *rank, _repeaters, &packet, timer);
kernel_manager.message_handle_incoming(status, id, length as usize, &data);
router.send(
drtioaux::Packet::SubkernelMessageAck { destination: source },
_routing_table,
*rank,
*self_destination,
forward!(_routing_table, destination, *_rank, _repeaters, &packet, timer);
kernel_manager.message_handle_incoming(last, length as usize, &data);
drtioaux::send(
0,
&drtioaux::Packet::SubkernelMessageAck {
destination: destination,
},
)
}
drtioaux::Packet::SubkernelMessageAck {
destination: _destination,
} => {
forward!(_routing_table, _destination, *rank, _repeaters, &packet, timer);
forward!(_routing_table, _destination, *_rank, _repeaters, &packet, timer);
if kernel_manager.message_ack_slice() {
let mut data_slice: [u8; MASTER_PAYLOAD_MAX_SIZE] = [0; MASTER_PAYLOAD_MAX_SIZE];
if let Some(meta) = kernel_manager.message_get_slice(&mut data_slice) {
// route and not send immediately as ACKs are not a beginning of a transaction
router.route(
drtioaux::Packet::SubkernelMessage {
source: *self_destination,
destination: meta.destination,
drtioaux::send(
0,
&drtioaux::Packet::SubkernelMessage {
destination: *_rank,
id: kernel_manager.get_current_id().unwrap(),
status: meta.status,
last: meta.last,
length: meta.len as u16,
data: data_slice,
},
_routing_table,
*rank,
*self_destination,
);
)?;
} else {
error!("Error receiving message slice");
}
@ -692,8 +608,8 @@ fn process_aux_packet(
Ok(())
}
p => {
warn!("received unexpected aux packet: {:?}", p);
_ => {
warn!("received unexpected aux packet");
Ok(())
}
}
@ -703,35 +619,32 @@ fn process_aux_packets(
repeaters: &mut [repeater::Repeater],
routing_table: &mut drtio_routing::RoutingTable,
rank: &mut u8,
self_destination: &mut u8,
timer: &mut GlobalTimer,
i2c: &mut I2c,
dma_manager: &mut DmaManager,
analyzer: &mut Analyzer,
kernel_manager: &mut KernelManager,
router: &mut Router,
) {
let result = drtioaux::recv(0).and_then(|packet| {
if let Some(packet) = packet.or_else(|| router.get_local_packet()) {
if let Some(packet) = packet {
process_aux_packet(
repeaters,
routing_table,
rank,
self_destination,
packet,
timer,
i2c,
dma_manager,
analyzer,
kernel_manager,
router,
)
} else {
Ok(())
}
});
if let Err(e) = result {
warn!("aux packet error ({:?})", e);
match result {
Ok(()) => (),
Err(e) => warn!("aux packet error ({:?})", e),
}
}
@ -816,43 +729,10 @@ const SI5324_SETTINGS: si5324::FrequencySettings = si5324::FrequencySettings {
crystal_as_ckin2: true,
};
#[cfg(all(has_si549, rtio_frequency = "125.0"))]
const SI549_SETTINGS: si549::FrequencySetting = si549::FrequencySetting {
main: si549::DividerConfig {
hsdiv: 0x058,
lsdiv: 0,
fbdiv: 0x04815791F25,
},
helper: si549::DividerConfig {
// 125MHz*32767/32768
hsdiv: 0x058,
lsdiv: 0,
fbdiv: 0x04814E8F442,
},
};
#[cfg(all(has_si549, rtio_frequency = "100.0"))]
const SI549_SETTINGS: si549::FrequencySetting = si549::FrequencySetting {
main: si549::DividerConfig {
hsdiv: 0x06C,
lsdiv: 0,
fbdiv: 0x046C5F49797,
},
helper: si549::DividerConfig {
// 100MHz*32767/32768
hsdiv: 0x06C,
lsdiv: 0,
fbdiv: 0x046C5670BBD,
},
};
static mut LOG_BUFFER: [u8; 1 << 17] = [0; 1 << 17];
#[no_mangle]
pub extern "C" fn main_core0() -> i32 {
unsafe {
exception_vectors::set_vector_table(&__exceptions_start as *const u32 as u32);
}
enable_l2_cache(0x8);
let mut timer = GlobalTimer::start();
@ -882,11 +762,6 @@ pub extern "C" fn main_core0() -> i32 {
io_expander1
.init(&mut i2c)
.expect("I2C I/O expander #1 initialization failed");
// Drive CLK_SEL to true
#[cfg(has_si549)]
io_expander0.set(1, 7, true);
// Drive TX_DISABLE to false on SFP0..3
io_expander0.set(0, 1, false);
io_expander1.set(0, 1, false);
@ -898,8 +773,6 @@ pub extern "C" fn main_core0() -> i32 {
#[cfg(has_si5324)]
si5324::setup(&mut i2c, &SI5324_SETTINGS, si5324::Input::Ckin1, &mut timer).expect("cannot initialize Si5324");
#[cfg(has_si549)]
si549::main_setup(&mut timer, &SI549_SETTINGS).expect("cannot initialize main Si549");
timer.delay_us(100_000);
info!("Switching SYS clocks...");
@ -917,8 +790,6 @@ pub extern "C" fn main_core0() -> i32 {
unsafe {
csr::gt_drtio::txenable_write(0xffffffffu32 as _);
}
#[cfg(has_si549)]
si549::helper_setup(&mut timer, &SI549_SETTINGS).expect("cannot initialize helper Si549");
#[cfg(has_drtio_routing)]
let mut repeaters = [repeater::Repeater::default(); csr::DRTIOREP.len()];
@ -929,20 +800,17 @@ pub extern "C" fn main_core0() -> i32 {
}
let mut routing_table = drtio_routing::RoutingTable::default_empty();
let mut rank = 1;
let mut destination = 1;
let mut hardware_tick_ts = 0;
let mut control = ksupport::kernel::Control::start();
loop {
let mut router = Router::new();
while !drtiosat_link_rx_up() {
drtiosat_process_errors();
#[allow(unused_mut)]
for mut rep in repeaters.iter_mut() {
rep.service(&routing_table, rank, destination, &mut router, &mut timer);
rep.service(&routing_table, rank, &mut timer);
}
#[cfg(feature = "target_kasli_soc")]
{
@ -964,9 +832,6 @@ pub extern "C" fn main_core0() -> i32 {
si5324::siphaser::calibrate_skew(&mut timer).expect("failed to calibrate skew");
}
#[cfg(has_wrpll)]
si549::wrpll::select_recovered_clock(true, &mut timer);
// Various managers created here, so when link is dropped, all DMA traces
// are cleared out for a clean slate on subsequent connections,
// without a manual intervention.
@ -984,17 +849,15 @@ pub extern "C" fn main_core0() -> i32 {
&mut repeaters,
&mut routing_table,
&mut rank,
&mut destination,
&mut timer,
&mut i2c,
&mut dma_manager,
&mut analyzer,
&mut kernel_manager,
&mut router,
);
#[allow(unused_mut)]
for mut rep in repeaters.iter_mut() {
rep.service(&routing_table, rank, destination, &mut router, &mut timer);
rep.service(&routing_table, rank, &mut timer);
}
#[cfg(feature = "target_kasli_soc")]
{
@ -1017,45 +880,7 @@ pub extern "C" fn main_core0() -> i32 {
error!("aux packet error: {:?}", e);
}
}
if let Some(status) = dma_manager.check_state() {
info!(
"playback done, error: {}, channel: {}, timestamp: {}",
status.error, status.channel, status.timestamp
);
router.route(
drtioaux::Packet::DmaPlaybackStatus {
source: destination,
destination: status.source,
id: status.id,
error: status.error,
channel: status.channel,
timestamp: status.timestamp,
},
&routing_table,
rank,
destination,
);
}
kernel_manager.process_kern_requests(
&mut router,
&routing_table,
rank,
destination,
&mut dma_manager,
&timer,
);
#[cfg(has_drtio_routing)]
if let Some((repno, packet)) = router.get_downstream_packet() {
if let Err(e) = repeaters[repno].aux_send(&packet) {
warn!("[REP#{}] Error when sending packet to satellite ({:?})", repno, e)
}
}
if let Some(packet) = router.get_upstream_packet() {
drtioaux::send(0, &packet).unwrap();
}
kernel_manager.process_kern_requests(rank, timer);
}
drtiosat_reset_phy(true);
@ -1064,8 +889,6 @@ pub extern "C" fn main_core0() -> i32 {
info!("uplink is down, switching to local oscillator clock");
#[cfg(has_siphaser)]
si5324::siphaser::select_recovered_clock(&mut i2c, false, &mut timer).expect("failed to switch clocks");
#[cfg(has_wrpll)]
si549::wrpll::select_recovered_clock(false, &mut timer);
}
}

View File

@ -6,7 +6,6 @@ use libboard_artiq::{drtio_routing, drtioaux};
#[cfg(has_drtio_routing)]
use libboard_zynq::time::Milliseconds;
use libboard_zynq::timer::GlobalTimer;
use routing::Router;
#[cfg(has_drtio_routing)]
fn rep_link_rx_up(repno: u8) -> bool {
@ -54,14 +53,7 @@ impl Repeater {
self.state == RepeaterState::Up
}
pub fn service(
&mut self,
routing_table: &drtio_routing::RoutingTable,
rank: u8,
destination: u8,
router: &mut Router,
timer: &mut GlobalTimer,
) {
pub fn service(&mut self, routing_table: &drtio_routing::RoutingTable, rank: u8, timer: &mut GlobalTimer) {
self.process_local_errors();
match self.state {
@ -119,7 +111,7 @@ impl Repeater {
}
}
RepeaterState::Up => {
self.process_unsolicited_aux(routing_table, rank, destination, router);
self.process_unsolicited_aux();
if !rep_link_rx_up(self.repno) {
info!("[REP#{}] link is down", self.repno);
self.state = RepeaterState::Down;
@ -134,15 +126,9 @@ impl Repeater {
}
}
fn process_unsolicited_aux(
&self,
routing_table: &drtio_routing::RoutingTable,
rank: u8,
destination: u8,
router: &mut Router,
) {
fn process_unsolicited_aux(&self) {
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) => (),
Err(_) => warn!("[REP#{}] aux packet error", self.repno),
}
@ -205,17 +191,13 @@ impl Repeater {
}
pub fn aux_forward(&self, request: &drtioaux::Packet, timer: &mut GlobalTimer) -> Result<(), drtioaux::Error> {
self.aux_send(request)?;
let reply = self.recv_aux_timeout(200, timer)?;
drtioaux::send(0, &reply).unwrap();
Ok(())
}
pub fn aux_send(&self, request: &drtioaux::Packet) -> Result<(), drtioaux::Error> {
if self.state != RepeaterState::Up {
return Err(drtioaux::Error::LinkDown);
}
drtioaux::send(self.auxno, request)
drtioaux::send(self.auxno, request).unwrap();
let reply = self.recv_aux_timeout(200, timer)?;
drtioaux::send(0, &reply).unwrap();
Ok(())
}
pub fn sync_tsc(&self, timer: &mut GlobalTimer) -> Result<(), drtioaux::Error> {
@ -320,15 +302,7 @@ impl Repeater {
Repeater::default()
}
pub fn service(
&self,
_routing_table: &drtio_routing::RoutingTable,
_rank: u8,
_destination: u8,
_router: &mut Router,
_timer: &mut GlobalTimer,
) {
}
pub fn service(&self, _routing_table: &drtio_routing::RoutingTable, _rank: u8, _timer: &mut GlobalTimer) {}
pub fn sync_tsc(&self, _timer: &mut GlobalTimer) -> Result<(), drtioaux::Error> {
Ok(())

View File

@ -1,174 +0,0 @@
use alloc::{collections::vec_deque::VecDeque, vec::Vec};
use core::cmp::min;
#[cfg(has_drtio_routing)]
use libboard_artiq::pl::csr;
use libboard_artiq::{drtio_routing, drtioaux,
drtioaux_proto::{PayloadStatus, MASTER_PAYLOAD_MAX_SIZE, SAT_PAYLOAD_MAX_SIZE}};
pub struct SliceMeta {
pub destination: u8,
pub len: u16,
pub status: PayloadStatus,
}
/* represents data that has to be sent to Master */
#[derive(Debug)]
pub struct Sliceable {
it: usize,
data: Vec<u8>,
destination: u8,
}
macro_rules! get_slice_fn {
($name:tt, $size:expr) => {
pub fn $name(&mut self, data_slice: &mut [u8; $size]) -> SliceMeta {
let first = self.it == 0;
let len = min($size, self.data.len() - self.it);
let last = self.it + len == self.data.len();
let status = PayloadStatus::from_status(first, last);
data_slice[..len].clone_from_slice(&self.data[self.it..self.it + len]);
self.it += len;
SliceMeta {
destination: self.destination,
len: len as u16,
status: status,
}
}
};
}
impl Sliceable {
pub fn new(destination: u8, data: Vec<u8>) -> Sliceable {
Sliceable {
it: 0,
data: data,
destination: destination,
}
}
pub fn at_end(&self) -> bool {
self.it == self.data.len()
}
pub fn extend(&mut self, data: &[u8]) {
self.data.extend(data);
}
get_slice_fn!(get_slice_sat, SAT_PAYLOAD_MAX_SIZE);
get_slice_fn!(get_slice_master, MASTER_PAYLOAD_MAX_SIZE);
}
// Packets from downstream (further satellites) are received and routed appropriately.
// they're passed as soon as possible downstream (within the subtree), or sent upstream,
// which is notified about pending packets.
// for rank 1 (connected to master) satellites, these packets are passed as an answer to DestinationStatusRequest;
// for higher ranks, after getting a notification, it will transact with downstream to get the pending packets.
// forward! macro is not deprecated, as routable packets are only these that can originate
// from both master and satellite, e.g. DDMA and Subkernel.
pub struct Router {
upstream_queue: VecDeque<drtioaux::Packet>,
local_queue: VecDeque<drtioaux::Packet>,
#[cfg(has_drtio_routing)]
downstream_queue: VecDeque<(usize, drtioaux::Packet)>,
}
impl Router {
pub fn new() -> Router {
Router {
upstream_queue: VecDeque::new(),
local_queue: VecDeque::new(),
#[cfg(has_drtio_routing)]
downstream_queue: VecDeque::new(),
}
}
// Called by local sources (DDMA, kernel) and by repeaters on receiving async data;
// messages are always buffered for both upstream and downstream
pub fn route(
&mut self,
packet: drtioaux::Packet,
_routing_table: &drtio_routing::RoutingTable,
_rank: u8,
self_destination: u8,
) {
let destination = packet.routable_destination();
#[cfg(has_drtio_routing)]
{
if let Some(destination) = destination {
let hop = _routing_table.0[destination as usize][_rank as usize] as usize;
if destination == self_destination {
self.local_queue.push_back(packet);
} else if hop > 0 && hop < csr::DRTIOREP.len() {
let repno = (hop - 1) as usize;
self.downstream_queue.push_back((repno, packet));
} else {
self.upstream_queue.push_back(packet);
}
} else {
error!("Received an unroutable packet: {:?}", packet);
}
}
#[cfg(not(has_drtio_routing))]
{
if destination == Some(self_destination) {
self.local_queue.push_back(packet);
} else {
self.upstream_queue.push_back(packet);
}
}
}
// Sends a packet to a required destination, routing if necessary
pub fn send(
&mut self,
packet: drtioaux::Packet,
_routing_table: &drtio_routing::RoutingTable,
_rank: u8,
_destination: u8,
) -> Result<(), drtioaux::Error> {
#[cfg(has_drtio_routing)]
{
let destination = packet.routable_destination();
if let Some(destination) = destination {
let hop = _routing_table.0[destination as usize][_rank as usize] as usize;
if destination == 0 {
// response is needed immediately if master required it
drtioaux::send(0, &packet)?;
} else if !(hop > 0 && hop < csr::DRTIOREP.len()) {
// higher rank can wait
self.upstream_queue.push_back(packet);
} else {
let repno = (hop - 1) as usize;
// transaction will occur at closest possible opportunity
self.downstream_queue.push_back((repno, packet));
}
Ok(())
} else {
// packet not supported in routing, fallback - sent directly
drtioaux::send(0, &packet)
}
}
#[cfg(not(has_drtio_routing))]
{
drtioaux::send(0, &packet)
}
}
pub fn get_upstream_packet(&mut self) -> Option<drtioaux::Packet> {
self.upstream_queue.pop_front()
}
#[cfg(has_drtio_routing)]
pub fn get_downstream_packet(&mut self) -> Option<(usize, drtioaux::Packet)> {
self.downstream_queue.pop_front()
}
pub fn get_local_packet(&mut self) -> Option<drtioaux::Packet> {
self.local_queue.pop_front()
}
}

View File

@ -1,52 +1,26 @@
use alloc::{collections::BTreeMap,
use alloc::{collections::{BTreeMap, VecDeque},
format,
string::{String, ToString},
vec::Vec};
use core::{option::NoneError, slice, str};
use core::{cmp::min, option::NoneError, slice, str};
use core_io::{Error as IoError, Write};
use cslice::AsCSlice;
use dma::{Error as DmaError, Manager as DmaManager};
use io::{Cursor, ProtoWrite};
use io::{Cursor, ProtoRead, ProtoWrite};
use ksupport::{eh_artiq, kernel, rpc};
use libboard_artiq::{drtio_routing::RoutingTable,
drtioaux,
drtioaux_proto::{PayloadStatus, MASTER_PAYLOAD_MAX_SIZE, SAT_PAYLOAD_MAX_SIZE},
use libboard_artiq::{drtioaux_proto::{MASTER_PAYLOAD_MAX_SIZE, SAT_PAYLOAD_MAX_SIZE},
pl::csr};
use libboard_zynq::{time::Milliseconds, timer::GlobalTimer};
use libcortex_a9::sync_channel::Receiver;
use log::warn;
use routing::{Router, SliceMeta, Sliceable};
#[derive(Debug, Clone, PartialEq)]
#[derive(Debug, Clone, Copy, PartialEq)]
enum KernelState {
Absent,
Loaded,
Running,
MsgAwait {
max_time: Option<Milliseconds>,
id: u32,
tags: Vec<u8>,
},
MsgAwait(Milliseconds),
MsgSending,
SubkernelAwaitLoad,
SubkernelAwaitFinish {
max_time: Option<Milliseconds>,
id: u32,
},
DmaUploading,
DmaPendingPlayback {
id: u32,
timestamp: u64,
},
DmaPendingAwait {
id: u32,
timestamp: u64,
max_time: Milliseconds,
},
DmaAwait {
max_time: Milliseconds,
},
}
#[derive(Debug)]
@ -57,9 +31,7 @@ pub enum Error {
NoMessage,
AwaitingMessage,
SubkernelIoError,
DrtioError,
KernelException(Sliceable),
DmaError(DmaError),
}
impl From<NoneError> for Error {
@ -74,38 +46,34 @@ impl From<IoError> for Error {
}
}
impl From<DmaError> for Error {
fn from(value: DmaError) -> Error {
Error::DmaError(value)
}
}
impl From<()> for Error {
fn from(_: ()) -> Error {
Error::NoMessage
}
}
impl From<drtioaux::Error> for Error {
fn from(_value: drtioaux::Error) -> Error {
Error::DrtioError
}
}
macro_rules! unexpected {
($($arg:tt)*) => (return Err(Error::Unexpected(format!($($arg)*))));
}
/* represents data that has to be sent to Master */
#[derive(Debug)]
pub struct Sliceable {
it: usize,
data: Vec<u8>,
}
/* represents interkernel messages */
struct Message {
count: u8,
id: u32,
tag: u8,
data: Vec<u8>,
}
#[derive(PartialEq)]
enum OutMessageState {
NoMessage,
MessageReady,
MessageBeingSent,
MessageSent,
MessageAcknowledged,
@ -115,7 +83,7 @@ enum OutMessageState {
struct MessageManager {
out_message: Option<Sliceable>,
out_state: OutMessageState,
in_queue: Vec<Message>,
in_queue: VecDeque<Message>,
in_buffer: Option<Message>,
}
@ -125,8 +93,6 @@ struct Session {
kernel_state: KernelState,
last_exception: Option<Sliceable>,
messages: MessageManager,
source: u8, // which destination requested running the kernel
subkernels_finished: Vec<u32>,
}
impl Session {
@ -136,15 +102,13 @@ impl Session {
kernel_state: KernelState::Absent,
last_exception: None,
messages: MessageManager::new(),
source: 0,
subkernels_finished: Vec::new(),
}
}
fn running(&self) -> bool {
match self.kernel_state {
KernelState::Absent | KernelState::Loaded => false,
_ => true,
KernelState::Running | KernelState::MsgAwait { .. } | KernelState::MsgSending => true,
}
}
}
@ -166,8 +130,40 @@ pub struct Manager<'a> {
pub struct SubkernelFinished {
pub id: u32,
pub with_exception: bool,
pub exception_source: u8,
pub source: u8,
}
pub struct SliceMeta {
pub len: u16,
pub last: bool,
}
macro_rules! get_slice_fn {
($name:tt, $size:expr) => {
pub fn $name(&mut self, data_slice: &mut [u8; $size]) -> SliceMeta {
if self.data.len() == 0 {
return SliceMeta { len: 0, last: true };
}
let len = min($size, self.data.len() - self.it);
let last = self.it + len == self.data.len();
data_slice[..len].clone_from_slice(&self.data[self.it..self.it + len]);
self.it += len;
SliceMeta {
len: len as u16,
last: last,
}
}
};
}
impl Sliceable {
pub fn new(data: Vec<u8>) -> Sliceable {
Sliceable { it: 0, data: data }
}
get_slice_fn!(get_slice_sat, SAT_PAYLOAD_MAX_SIZE);
get_slice_fn!(get_slice_master, MASTER_PAYLOAD_MAX_SIZE);
}
impl MessageManager {
@ -175,35 +171,37 @@ impl MessageManager {
MessageManager {
out_message: None,
out_state: OutMessageState::NoMessage,
in_queue: Vec::new(),
in_queue: VecDeque::new(),
in_buffer: None,
}
}
pub fn handle_incoming(
&mut self,
status: PayloadStatus,
id: u32,
length: usize,
data: &[u8; MASTER_PAYLOAD_MAX_SIZE],
) {
pub fn handle_incoming(&mut self, last: bool, length: usize, data: &[u8; MASTER_PAYLOAD_MAX_SIZE]) {
// called when receiving a message from master
if status.is_first() {
self.in_buffer = None;
}
match self.in_buffer.as_mut() {
Some(message) => message.data.extend(&data[..length]),
None => {
self.in_buffer = Some(Message {
count: data[0],
id: id,
data: data[1..length].to_vec(),
tag: data[1],
data: data[2..length].to_vec(),
});
}
};
if status.is_last() {
if last {
// when done, remove from working queue
self.in_queue.push(self.in_buffer.take().unwrap());
self.in_queue.push_back(self.in_buffer.take().unwrap());
}
}
pub fn is_outgoing_ready(&mut self) -> bool {
// called by main loop, to see if there's anything to send, will send it afterwards
match self.out_state {
OutMessageState::MessageReady => {
self.out_state = OutMessageState::MessageBeingSent;
true
}
_ => false,
}
}
@ -222,7 +220,7 @@ impl MessageManager {
return None;
}
let meta = self.out_message.as_mut()?.get_slice_master(data_slice);
if meta.status.is_last() {
if meta.last {
// clear the message slot
self.out_message = None;
// notify kernel with a flag that message is sent
@ -246,44 +244,15 @@ impl MessageManager {
}
}
pub fn accept_outgoing(
&mut self,
id: u32,
self_destination: u8,
destination: u8,
message: Vec<u8>,
routing_table: &RoutingTable,
rank: u8,
router: &mut Router,
) -> Result<(), Error> {
self.out_message = Some(Sliceable::new(destination, message));
let mut data_slice: [u8; MASTER_PAYLOAD_MAX_SIZE] = [0; MASTER_PAYLOAD_MAX_SIZE];
self.out_state = OutMessageState::MessageBeingSent;
let meta = self.get_outgoing_slice(&mut data_slice).unwrap();
router.route(
drtioaux::Packet::SubkernelMessage {
source: self_destination,
destination: destination,
id: id,
status: meta.status,
length: meta.len as u16,
data: data_slice,
},
routing_table,
rank,
self_destination,
);
pub fn accept_outgoing(&mut self, message: Vec<u8>) -> Result<(), Error> {
// service tag skipped in kernel
self.out_message = Some(Sliceable::new(message));
self.out_state = OutMessageState::MessageReady;
Ok(())
}
pub fn get_incoming(&mut self, id: u32) -> Option<Message> {
for i in 0..self.in_queue.len() {
if self.in_queue[i].id == id {
return Some(self.in_queue.remove(i));
}
}
None
pub fn get_incoming(&mut self) -> Option<Message> {
self.in_queue.pop_front()
}
}
@ -298,10 +267,10 @@ impl<'a> Manager<'_> {
}
}
pub fn add(&mut self, id: u32, status: PayloadStatus, data: &[u8], data_len: usize) -> Result<(), Error> {
pub fn add(&mut self, id: u32, last: bool, data: &[u8], data_len: usize) -> Result<(), Error> {
let kernel = match self.kernels.get_mut(&id) {
Some(kernel) => {
if kernel.complete || status.is_first() {
if kernel.complete {
// replace entry
self.kernels.remove(&id);
self.kernels.insert(
@ -329,7 +298,7 @@ impl<'a> Manager<'_> {
};
kernel.library.extend(&data[0..data_len]);
kernel.complete = status.is_last();
kernel.complete = last;
Ok(())
}
@ -344,12 +313,12 @@ impl<'a> Manager<'_> {
}
}
pub fn run(&mut self, source: u8, id: u32) -> Result<(), Error> {
pub fn run(&mut self, id: u32) -> Result<(), Error> {
info!("starting subkernel #{}", id);
if self.session.kernel_state != KernelState::Loaded || self.session.id != id {
self.load(id)?;
}
self.session.kernel_state = KernelState::Running;
self.session.source = source;
unsafe {
csr::cri_con::selected_write(2);
}
@ -358,17 +327,11 @@ impl<'a> Manager<'_> {
Ok(())
}
pub fn message_handle_incoming(
&mut self,
status: PayloadStatus,
id: u32,
length: usize,
slice: &[u8; MASTER_PAYLOAD_MAX_SIZE],
) {
pub fn message_handle_incoming(&mut self, last: bool, length: usize, slice: &[u8; MASTER_PAYLOAD_MAX_SIZE]) {
if !self.running() {
return;
}
self.session.messages.handle_incoming(status, id, length, slice);
self.session.messages.handle_incoming(last, length, slice);
}
pub fn message_get_slice(&mut self, slice: &mut [u8; MASTER_PAYLOAD_MAX_SIZE]) -> Option<SliceMeta> {
@ -386,6 +349,10 @@ impl<'a> Manager<'_> {
self.session.messages.ack_slice()
}
pub fn message_is_ready(&mut self) -> bool {
self.session.messages.is_outgoing_ready()
}
pub fn load(&mut self, id: u32) -> Result<(), Error> {
if self.session.id == id && self.session.kernel_state == KernelState::Loaded {
return Ok(());
@ -413,14 +380,14 @@ impl<'a> Manager<'_> {
pub fn exception_get_slice(&mut self, data_slice: &mut [u8; SAT_PAYLOAD_MAX_SIZE]) -> SliceMeta {
match self.session.last_exception.as_mut() {
Some(exception) => exception.get_slice_sat(data_slice),
None => SliceMeta {
destination: 0,
len: 0,
status: PayloadStatus::FirstAndLast,
},
None => SliceMeta { len: 0, last: true },
}
}
pub fn get_last_finished(&mut self) -> Option<SubkernelFinished> {
self.last_finished.take()
}
fn kernel_stop(&mut self) {
self.session.kernel_state = KernelState::Absent;
unsafe {
@ -450,92 +417,13 @@ impl<'a> Manager<'_> {
&[],
0,
) {
Ok(_) => self.session.last_exception = Some(Sliceable::new(0, writer.into_inner())),
Ok(_) => self.session.last_exception = Some(Sliceable::new(writer.into_inner())),
Err(_) => error!("Error writing exception data"),
}
self.kernel_stop();
}
pub fn ddma_finished(&mut self, error: u8, channel: u32, timestamp: u64) {
if let KernelState::DmaAwait { .. } = self.session.kernel_state {
self.control.tx.send(kernel::Message::DmaAwaitRemoteReply {
timeout: false,
error: error,
channel: channel,
timestamp: timestamp,
});
self.session.kernel_state = KernelState::Running;
}
}
pub fn ddma_nack(&mut self) {
// for simplicity treat it as a timeout...
if let KernelState::DmaAwait { .. } = self.session.kernel_state {
self.control.tx.send(kernel::Message::DmaAwaitRemoteReply {
timeout: true,
error: 0,
channel: 0,
timestamp: 0,
});
self.session.kernel_state = KernelState::Running;
}
}
pub fn ddma_remote_uploaded(&mut self, succeeded: bool) -> Option<(u32, u64)> {
// returns a tuple of id, timestamp in case a playback needs to be started immediately
if !succeeded {
self.kernel_stop();
self.runtime_exception(Error::DmaError(DmaError::UploadFail));
}
let res = match self.session.kernel_state {
KernelState::DmaPendingPlayback { id, timestamp } => {
self.session.kernel_state = KernelState::Running;
Some((id, timestamp))
}
KernelState::DmaPendingAwait {
id,
timestamp,
max_time,
} => {
self.session.kernel_state = KernelState::DmaAwait { max_time: max_time };
Some((id, timestamp))
}
KernelState::DmaUploading => {
self.session.kernel_state = KernelState::Running;
None
}
_ => None,
};
res
}
pub fn process_kern_requests(
&mut self,
router: &mut Router,
routing_table: &RoutingTable,
rank: u8,
destination: u8,
dma_manager: &mut DmaManager,
timer: &GlobalTimer,
) {
if let Some(subkernel_finished) = self.last_finished.take() {
info!(
"subkernel {} finished, with exception: {}",
subkernel_finished.id, subkernel_finished.with_exception
);
router.route(
drtioaux::Packet::SubkernelFinished {
destination: subkernel_finished.source,
id: subkernel_finished.id,
with_exception: subkernel_finished.with_exception,
exception_src: subkernel_finished.exception_source,
},
&routing_table,
rank,
destination,
);
}
pub fn process_kern_requests(&mut self, rank: u8, timer: GlobalTimer) {
if !self.running() {
return;
}
@ -548,8 +436,6 @@ impl<'a> Manager<'_> {
self.last_finished = Some(SubkernelFinished {
id: self.session.id,
with_exception: true,
exception_source: destination,
source: self.session.source,
});
}
Err(e) => {
@ -558,19 +444,15 @@ impl<'a> Manager<'_> {
self.last_finished = Some(SubkernelFinished {
id: self.session.id,
with_exception: true,
exception_source: destination,
source: self.session.source,
});
}
}
match self.process_kern_message(router, routing_table, rank, destination, dma_manager, timer) {
match self.process_kern_message(rank, timer) {
Ok(true) => {
self.last_finished = Some(SubkernelFinished {
id: self.session.id,
with_exception: false,
exception_source: 0,
source: self.session.source,
});
}
Ok(false) | Err(Error::NoMessage) => (),
@ -579,8 +461,6 @@ impl<'a> Manager<'_> {
self.last_finished = Some(SubkernelFinished {
id: self.session.id,
with_exception: true,
exception_source: destination,
source: self.session.source,
});
}
Err(e) => {
@ -589,52 +469,16 @@ impl<'a> Manager<'_> {
self.last_finished = Some(SubkernelFinished {
id: self.session.id,
with_exception: true,
exception_source: destination,
source: self.session.source,
});
}
}
}
pub fn subkernel_load_run_reply(&mut self, succeeded: bool) {
if self.session.kernel_state == KernelState::SubkernelAwaitLoad {
self.control
.tx
.send(kernel::Message::SubkernelLoadRunReply { succeeded: succeeded });
self.session.kernel_state = KernelState::Running;
} else {
warn!("received unsolicited SubkernelLoadRunReply");
}
}
pub fn remote_subkernel_finished(&mut self, id: u32, with_exception: bool, exception_source: u8) {
if with_exception {
self.kernel_stop();
self.last_finished = Some(SubkernelFinished {
source: self.session.source,
id: self.session.id,
with_exception: true,
exception_source: exception_source,
})
} else {
self.session.subkernels_finished.push(id);
}
}
fn process_kern_message(
&mut self,
router: &mut Router,
routing_table: &RoutingTable,
rank: u8,
self_destination: u8,
dma_manager: &mut DmaManager,
timer: &GlobalTimer,
) -> Result<bool, Error> {
fn process_kern_message(&mut self, rank: u8, timer: GlobalTimer) -> Result<bool, Error> {
let reply = self.control.rx.try_recv()?;
match reply {
kernel::Message::KernelFinished(_async_errors) => {
self.kernel_stop();
dma_manager.cleanup(router, rank, self_destination, routing_table);
return Ok(true);
}
kernel::Message::KernelException(exceptions, stack_pointers, backtrace, async_errors) => {
@ -651,7 +495,7 @@ impl<'a> Manager<'_> {
Err(_) => error!("Error writing exception data"),
}
self.kernel_stop();
return Err(Error::KernelException(Sliceable::new(0, writer.into_inner())));
return Err(Error::KernelException(Sliceable::new(writer.into_inner())));
}
kernel::Message::CachePutRequest(key, value) => {
self.cache.insert(key, value);
@ -661,117 +505,18 @@ impl<'a> Manager<'_> {
let value = self.cache.get(&key).unwrap_or(&DEFAULT).clone();
self.control.tx.send(kernel::Message::CacheGetReply(value));
}
kernel::Message::DmaPutRequest(recorder) => {
// ddma is always used on satellites
if let Ok(id) = dma_manager.put_record(recorder, self_destination) {
dma_manager.upload_traces(id, router, rank, self_destination, routing_table)?;
self.session.kernel_state = KernelState::DmaUploading;
} else {
unexpected!("DMAError: found an unsupported call to RTIO devices on master")
}
}
kernel::Message::DmaEraseRequest(name) => {
dma_manager.erase_name(&name, router, rank, self_destination, routing_table);
}
kernel::Message::DmaGetRequest(name) => {
let dma_meta = dma_manager.retrieve(self_destination, &name);
self.control.tx.send(kernel::Message::DmaGetReply(dma_meta));
}
kernel::Message::DmaStartRemoteRequest { id, timestamp } => {
if self.session.kernel_state != KernelState::DmaUploading {
dma_manager.playback_remote(
id as u32,
timestamp as u64,
router,
rank,
self_destination,
routing_table,
)?;
} else {
self.session.kernel_state = KernelState::DmaPendingPlayback {
id: id as u32,
timestamp: timestamp as u64,
};
}
}
kernel::Message::DmaAwaitRemoteRequest(_id) => {
let max_time = timer.get_time() + Milliseconds(10000);
self.session.kernel_state = match self.session.kernel_state {
// if we are still waiting for the traces to be uploaded, extend the state by timeout
KernelState::DmaPendingPlayback { id, timestamp } => KernelState::DmaPendingAwait {
id: id,
timestamp: timestamp,
max_time: max_time,
},
_ => KernelState::DmaAwait { max_time: max_time },
};
}
kernel::Message::SubkernelMsgSend {
id: _id,
destination: msg_dest,
data,
} => {
let msg_dest = msg_dest.or(Some(self.session.source)).unwrap();
self.session.messages.accept_outgoing(
self.session.id,
self_destination,
msg_dest,
data,
routing_table,
rank,
router,
)?;
kernel::Message::SubkernelMsgSend { id: _, data } => {
self.session.messages.accept_outgoing(data)?;
self.session.kernel_state = KernelState::MsgSending;
}
kernel::Message::SubkernelMsgRecvRequest { id, timeout, tags } => {
let id = if id == -1 { self.session.id } else { id as u32 };
let max_time = if timeout > 0 {
Some(timer.get_time() + Milliseconds(timeout as u64))
} else {
None
};
self.session.kernel_state = KernelState::MsgAwait {
max_time: max_time,
id: id,
tags: tags,
};
}
kernel::Message::SubkernelLoadRunRequest {
id,
destination: sk_destination,
run,
} => {
self.session.kernel_state = KernelState::SubkernelAwaitLoad;
router.route(
drtioaux::Packet::SubkernelLoadRunRequest {
source: self_destination,
destination: sk_destination,
id: id,
run: run,
},
routing_table,
rank,
self_destination,
);
}
kernel::Message::SubkernelAwaitFinishRequest { id, timeout } => {
let max_time = if timeout > 0 {
Some(timer.get_time() + Milliseconds(timeout as u64))
} else {
None
};
self.session.kernel_state = KernelState::SubkernelAwaitFinish {
max_time: max_time,
id: id,
};
kernel::Message::SubkernelMsgRecvRequest { id: _, timeout } => {
let max_time = timer.get_time() + Milliseconds(timeout);
self.session.kernel_state = KernelState::MsgAwait(max_time);
}
kernel::Message::UpDestinationsRequest(destination) => {
self.control.tx.send(kernel::Message::UpDestinationsReply(
destination == (self_destination as i32),
));
self.control
.tx
.send(kernel::Message::UpDestinationsReply(destination == (rank as i32)));
}
_ => {
unexpected!("unexpected message from core1 while kernel was running: {:?}", reply);
@ -780,27 +525,24 @@ impl<'a> Manager<'_> {
Ok(false)
}
fn process_external_messages(&mut self, timer: &GlobalTimer) -> Result<(), Error> {
match &self.session.kernel_state {
KernelState::MsgAwait { max_time, id, tags } => {
if let Some(max_time) = *max_time {
if timer.get_time() > max_time {
self.control.tx.send(kernel::Message::SubkernelMsgRecvReply {
status: kernel::SubkernelStatus::Timeout,
count: 0,
});
self.session.kernel_state = KernelState::Running;
return Ok(());
}
fn process_external_messages(&mut self, timer: GlobalTimer) -> Result<(), Error> {
match self.session.kernel_state {
KernelState::MsgAwait(timeout) => {
if timer.get_time() > timeout {
self.control.tx.send(kernel::Message::SubkernelMsgRecvReply {
status: kernel::SubkernelStatus::Timeout,
count: 0,
});
self.session.kernel_state = KernelState::Running;
return Ok(());
}
if let Some(message) = self.session.messages.get_incoming(*id) {
if let Some(message) = self.session.messages.get_incoming() {
self.control.tx.send(kernel::Message::SubkernelMsgRecvReply {
status: kernel::SubkernelStatus::NoError,
count: message.count,
});
let tags = tags.clone();
self.session.kernel_state = KernelState::Running;
self.pass_message_to_kernel(&message, tags, timer)
self.pass_message_to_kernel(&message, timer)
} else {
Err(Error::AwaitingMessage)
}
@ -814,49 +556,13 @@ impl<'a> Manager<'_> {
Err(Error::AwaitingMessage)
}
}
KernelState::SubkernelAwaitFinish { max_time, id } => {
if let Some(max_time) = *max_time {
if timer.get_time() > max_time {
self.control.tx.send(kernel::Message::SubkernelAwaitFinishReply {
status: kernel::SubkernelStatus::Timeout,
});
self.session.kernel_state = KernelState::Running;
return Ok(());
}
}
let mut i = 0;
for status in &self.session.subkernels_finished {
if *status == *id {
self.control.tx.send(kernel::Message::SubkernelAwaitFinishReply {
status: kernel::SubkernelStatus::NoError,
});
self.session.kernel_state = KernelState::Running;
self.session.subkernels_finished.swap_remove(i);
break;
}
i += 1;
}
Ok(())
}
KernelState::DmaAwait { max_time } | KernelState::DmaPendingAwait { max_time, .. } => {
if timer.get_time() > *max_time {
self.control.tx.send(kernel::Message::DmaAwaitRemoteReply {
timeout: true,
error: 0,
channel: 0,
timestamp: 0,
});
self.session.kernel_state = KernelState::Running;
}
Ok(())
}
_ => Ok(()),
}
}
fn pass_message_to_kernel(&mut self, message: &Message, tags: Vec<u8>, timer: &GlobalTimer) -> Result<(), Error> {
fn pass_message_to_kernel(&mut self, message: &Message, timer: GlobalTimer) -> Result<(), Error> {
let mut reader = Cursor::new(&message.data);
let mut current_tags: &[u8] = &tags;
let mut tag: [u8; 1] = [message.tag];
let mut i = message.count;
loop {
let slot = match recv_w_timeout(&mut self.control.rx, timer, 100)? {
@ -865,7 +571,7 @@ impl<'a> Manager<'_> {
};
let mut exception: Option<Sliceable> = None;
let mut unexpected: Option<String> = None;
let remaining_tags = rpc::recv_return(&mut reader, current_tags, slot, &mut |size| {
rpc::recv_return(&mut reader, &tag, slot, &mut |size| {
if size == 0 {
0 as *mut ()
} else {
@ -877,7 +583,7 @@ impl<'a> Manager<'_> {
let mut writer = Cursor::new(buf);
match write_exception(&mut writer, exceptions, stack_pointers, backtrace, async_errors) {
Ok(()) => {
exception = Some(Sliceable::new(0, writer.into_inner()));
exception = Some(Sliceable::new(writer.into_inner()));
}
Err(_) => {
unexpected = Some("Error writing exception data".to_string());
@ -904,7 +610,8 @@ impl<'a> Manager<'_> {
if i == 0 {
break;
} else {
current_tags = remaining_tags;
// update the tag for next read
tag[0] = reader.read_u8()?;
}
}
Ok(())
@ -971,7 +678,7 @@ where
fn recv_w_timeout(
rx: &mut Receiver<'_, kernel::Message>,
timer: &GlobalTimer,
timer: GlobalTimer,
timeout: u64,
) -> Result<kernel::Message, Error> {
let max_time = timer.get_time() + Milliseconds(timeout);