1
0
Fork 0

Compare commits

...

10 Commits

Author SHA1 Message Date
linuswck 0e3987c887 kasli_soc & zc706: Fix GTX Clock Path during INIT 2023-11-07 15:44:49 +08:00
linuswck 4a2d9dc597 zynq_clocking: Allow ext signal to set cur_clk csr
- for example, current_clock csr can be connected to tx_init.done
2023-11-07 15:43:43 +08:00
linuswck d507b6f60f zynq_clocking: add ext_async_rst to AsyncRstSYNCR 2023-11-06 12:24:44 +08:00
linuswck e3a4c13944 zynq_clocking: expose mmcm_locked for SYSCRG
- mmcm_locked -> self.mmcm_locked
2023-11-06 12:16:39 +08:00
morgan 4a34777b97 refactor i2c, io_expander, task under the same cfg 2023-10-25 11:52:04 +08:00
morgan 43e4527392 fix kasli-soc demo compilation warning 2023-10-25 11:45:13 +08:00
Sebastien Bourdeauducq a08a42c954 flake: update dependencies 2023-10-20 17:46:37 +08:00
mwojcik 0a3bfc9a61 subkernel: separate tags and data 2023-10-18 12:03:43 +08:00
Egor Savkin d3fbfd75b0 Fix grabber build and warning
Signed-off-by: Egor Savkin <es@m-labs.hk>
2023-10-18 11:24:43 +08:00
Egor Savkin b768d5648c Add grabber module
Signed-off-by: Egor Savkin <es@m-labs.hk>
2023-10-16 14:35:20 +08:00
15 changed files with 347 additions and 95 deletions

View File

@ -11,11 +11,11 @@
"src-pythonparser": "src-pythonparser" "src-pythonparser": "src-pythonparser"
}, },
"locked": { "locked": {
"lastModified": 1697013694, "lastModified": 1697537883,
"narHash": "sha256-jmr+pFeyV0+nUbFY8/g2Aw4kU06i5CG0XhLobI8vUR8=", "narHash": "sha256-GfadmYHFkczltX+rPf08YpAHjYa/31ZmmVD578BcFow=",
"ref": "refs/heads/master", "ref": "refs/heads/master",
"rev": "f7abc156cbc0a371452148d11436e5f241798092", "rev": "b168f0bb4be1697ff100475c20ee304dcc31fcc2",
"revCount": 8569, "revCount": 8573,
"type": "git", "type": "git",
"url": "https://github.com/m-labs/artiq.git" "url": "https://github.com/m-labs/artiq.git"
}, },
@ -103,11 +103,11 @@
"mozilla-overlay_3": { "mozilla-overlay_3": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1690536331, "lastModified": 1695805681,
"narHash": "sha256-aRIf2FB2GTdfF7gl13WyETmiV/J7EhBGkSWXfZvlxcA=", "narHash": "sha256-1ElPLD8eFfnuIk0G52HGGpRtQZ4QPCjChRlEOfkZ5ro=",
"owner": "mozilla", "owner": "mozilla",
"repo": "nixpkgs-mozilla", "repo": "nixpkgs-mozilla",
"rev": "db89c8707edcffefcd8e738459d511543a339ff5", "rev": "6eabade97bc28d707a8b9d82ad13ef143836736e",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -118,11 +118,11 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1696697597, "lastModified": 1697226376,
"narHash": "sha256-q26Qv4DQ+h6IeozF2o1secyQG0jt2VUT3V0K58jr3pg=", "narHash": "sha256-cumLLb1QOUtWieUnLGqo+ylNt3+fU8Lcv5Zl+tYbRUE=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "5a237aecb57296f67276ac9ab296a41c23981f56", "rev": "898cb2064b6e98b8c5499f37e81adbdf2925f7c5",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -147,11 +147,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1693473454, "lastModified": 1697528004,
"narHash": "sha256-kr8Ur6JNW/xVRHdPn3ou980IAxg/n+f3ZQBHuJ1uaC4=", "narHash": "sha256-FFa2MbhAJEjwY58uOs0swvgymfjubHyWba6Q0X6CbB0=",
"owner": "m-labs", "owner": "m-labs",
"repo": "sipyco", "repo": "sipyco",
"rev": "5467dcf9738673ab9a49e6f2377bda7c551b5f90", "rev": "c0a7ed350ccfb85474217057fc47b3f258ca8d99",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -234,11 +234,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1693479539, "lastModified": 1697795161,
"narHash": "sha256-MppR7yxs3cjG7tQc82vX0MhyN71CJL2QWkM65F5hrFU=", "narHash": "sha256-p89w9eoFJ2VFTDZ5Mrv5vsH0E1Ko9z1C6Ett281hCHg=",
"ref": "refs/heads/master", "ref": "refs/heads/master",
"rev": "c15b54f92b3d4e125ae47a0dce7abe4b2bc9e054", "rev": "be672ab662d8134ee11412a651864824f6483d4a",
"revCount": 628, "revCount": 630,
"type": "git", "type": "git",
"url": "https://git.m-labs.hk/m-labs/zynq-rs" "url": "https://git.m-labs.hk/m-labs/zynq-rs"
}, },

View File

@ -107,6 +107,7 @@ class GTPBootstrapClock(Module):
class GenericStandalone(SoCCore): class GenericStandalone(SoCCore):
def __init__(self, description, acpki=False): def __init__(self, description, acpki=False):
self.acpki = acpki self.acpki = acpki
clk_freq = description["rtio_frequency"]
platform = kasli_soc.Platform() platform = kasli_soc.Platform()
platform.toolchain.bitstream_commands.extend([ platform.toolchain.bitstream_commands.extend([
@ -138,7 +139,8 @@ class GenericStandalone(SoCCore):
Instance("BUFG", i_I=clk_synth_se, o_O=clk_synth_se_buf), Instance("BUFG", i_I=clk_synth_se, o_O=clk_synth_se_buf),
] ]
fix_serdes_timing_path(platform) fix_serdes_timing_path(platform)
self.submodules.bootstrap = GTPBootstrapClock(self.platform, description["rtio_frequency"]) self.submodules.bootstrap = GTPBootstrapClock(self.platform, clk_freq)
self.config["CLOCK_FREQUENCY"] = int(clk_freq)
self.submodules.sys_crg = zynq_clocking.SYSCRG(self.platform, self.ps7, clk_synth_se_buf) self.submodules.sys_crg = zynq_clocking.SYSCRG(self.platform, self.ps7, clk_synth_se_buf)
platform.add_false_path_constraints( platform.add_false_path_constraints(
@ -229,17 +231,22 @@ class GenericMaster(SoCCore):
pads=data_pads, pads=data_pads,
clk_freq=clk_freq) clk_freq=clk_freq)
self.csr_devices.append("gt_drtio") self.csr_devices.append("gt_drtio")
self.config["CLOCK_FREQUENCY"] = int(clk_freq)
txout_buf = Signal() txout_buf = Signal()
gtx0 = self.gt_drtio.gtxs[0] gtx0 = self.gt_drtio.gtxs[0]
self.specials += Instance("BUFG", i_I=gtx0.txoutclk, o_O=txout_buf) 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.bootstrap = GTPBootstrapClock(self.platform, clk_freq)
self.submodules.sys_crg = zynq_clocking.SYSCRG( self.submodules.sys_crg = zynq_clocking.SYSCRG(
self.platform, self.platform,
self.ps7, self.ps7,
txout_buf, txout_buf,
clk_sw=gtx0.tx_init.done) clk_sw=self.gt_drtio.stable_clkin.storage,
clk_sw_status=gtx0.tx_init.done,
ext_async_rst=ext_async_rst)
self.csr_devices.append("sys_crg") self.csr_devices.append("sys_crg")
self.crg = self.ps7 # HACK for eem_7series to find the clock self.crg = self.ps7 # HACK for eem_7series to find the clock
self.crg.cd_sys = self.sys_crg.cd_sys self.crg.cd_sys = self.sys_crg.cd_sys
@ -247,6 +254,9 @@ class GenericMaster(SoCCore):
self.bootstrap.cd_bootstrap.clk, self.sys_crg.cd_sys.clk) self.bootstrap.cd_bootstrap.clk, self.sys_crg.cd_sys.clk)
fix_serdes_timing_path(platform) 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.config["HAS_SI5324"] = None self.config["HAS_SI5324"] = None
self.config["SI5324_SOFT_RESET"] = None self.config["SI5324_SOFT_RESET"] = None
@ -416,12 +426,16 @@ class GenericSatellite(SoCCore):
gtx0 = self.gt_drtio.gtxs[0] gtx0 = self.gt_drtio.gtxs[0]
self.specials += Instance("BUFG", i_I=gtx0.txoutclk, o_O=txout_buf) 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.bootstrap = GTPBootstrapClock(self.platform, clk_freq)
self.submodules.sys_crg = zynq_clocking.SYSCRG( self.submodules.sys_crg = zynq_clocking.SYSCRG(
self.platform, self.platform,
self.ps7, self.ps7,
txout_buf, txout_buf,
clk_sw=gtx0.tx_init.done) clk_sw=self.gt_drtio.stable_clkin.storage,
clk_sw_status=gtx0.tx_init.done,
ext_async_rst=ext_async_rst)
platform.add_false_path_constraints( platform.add_false_path_constraints(
self.bootstrap.cd_bootstrap.clk, self.sys_crg.cd_sys.clk) self.bootstrap.cd_bootstrap.clk, self.sys_crg.cd_sys.clk)
self.csr_devices.append("sys_crg") self.csr_devices.append("sys_crg")
@ -430,6 +444,9 @@ class GenericSatellite(SoCCore):
fix_serdes_timing_path(platform) 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 = [] self.rtio_channels = []
has_grabber = any(peripheral["type"] == "grabber" for peripheral in description["peripherals"]) has_grabber = any(peripheral["type"] == "grabber" for peripheral in description["peripherals"])
if has_grabber: if has_grabber:
@ -532,6 +549,7 @@ class GenericSatellite(SoCCore):
rtio_clk_period = 1e9/clk_freq rtio_clk_period = 1e9/clk_freq
self.config["RTIO_FREQUENCY"] = str(clk_freq/1e6) self.config["RTIO_FREQUENCY"] = str(clk_freq/1e6)
self.config["CLOCK_FREQUENCY"] = int(clk_freq)
self.submodules.siphaser = SiPhaser7Series( self.submodules.siphaser = SiPhaser7Series(
si5324_clkin=platform.request("cdr_clk"), si5324_clkin=platform.request("cdr_clk"),

View File

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

View File

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

View File

@ -0,0 +1,163 @@
use log::info;
use crate::pl::csr;
#[derive(PartialEq, Clone, Copy)]
enum State {
Reset,
ExitReset,
Lock,
Align,
Watch,
}
#[derive(Clone, Copy)]
struct Info {
state: State,
frame_size: (u16, u16),
}
static mut INFO: [Info; csr::GRABBER_LEN] = [Info {
state: State::Reset,
frame_size: (0, 0),
}; csr::GRABBER_LEN];
fn get_pll_reset(g: usize) -> bool {
unsafe { (csr::GRABBER[g].pll_reset_read)() != 0 }
}
fn set_pll_reset(g: usize, reset: bool) {
let val = if reset { 1 } else { 0 };
unsafe { (csr::GRABBER[g].pll_reset_write)(val) }
}
fn pll_locked(g: usize) -> bool {
unsafe { (csr::GRABBER[g].pll_locked_read)() != 0 }
}
fn clock_pattern_ok(g: usize) -> bool {
unsafe { (csr::GRABBER[g].clk_sampled_read)() == 0b1100011 }
}
fn clock_pattern_ok_filter(g: usize) -> bool {
for _ in 0..128 {
if !clock_pattern_ok(g) {
return false;
}
}
true
}
fn phase_shift(g: usize, direction: u8) {
unsafe {
(csr::GRABBER[g].phase_shift_write)(direction);
while (csr::GRABBER[g].phase_shift_done_read)() == 0 {}
}
}
fn clock_align(g: usize) -> bool {
while clock_pattern_ok_filter(g) {
phase_shift(g, 1);
}
phase_shift(g, 1);
let mut count = 0;
while !clock_pattern_ok_filter(g) {
phase_shift(g, 1);
count += 1;
if count > 1024 {
return false;
}
}
let mut window = 1;
phase_shift(g, 1);
while clock_pattern_ok_filter(g) {
phase_shift(g, 1);
window += 1;
}
for _ in 0..window / 2 {
phase_shift(g, 0);
}
true
}
fn get_last_pixels(g: usize) -> (u16, u16) {
unsafe { ((csr::GRABBER[g].last_x_read)(), (csr::GRABBER[g].last_y_read)()) }
}
fn get_video_clock(g: usize) -> u32 {
let freq_count = unsafe { (csr::GRABBER[g].freq_count_read)() } as u32;
2 * freq_count * (csr::CONFIG_CLOCK_FREQUENCY / 1000) / (511 * 1000)
}
pub fn tick() {
for g in 0..csr::GRABBER.len() {
let next = match unsafe { INFO[g].state } {
State::Reset => {
set_pll_reset(g, true);
unsafe {
INFO[g].frame_size = (0, 0);
}
State::ExitReset
}
State::ExitReset => {
if get_pll_reset(g) {
set_pll_reset(g, false);
State::Lock
} else {
State::ExitReset
}
}
State::Lock => {
if pll_locked(g) {
info!("grabber{} locked: {}MHz", g, get_video_clock(g));
State::Align
} else {
State::Lock
}
}
State::Align => {
if pll_locked(g) {
if clock_align(g) {
info!("grabber{} alignment success", g);
State::Watch
} else {
info!("grabber{} alignment failure", g);
State::Reset
}
} else {
info!("grabber{} lock lost", g);
State::Reset
}
}
State::Watch => {
if pll_locked(g) {
if clock_pattern_ok(g) {
let last_xy = get_last_pixels(g);
if last_xy != unsafe { INFO[g].frame_size } {
// x capture is on ~LVAL which is after
// the last increment on DVAL
// y capture is on ~FVAL which coincides with the
// last increment on ~LVAL
info!("grabber{} frame size: {}x{}", g, last_xy.0, last_xy.1 + 1);
unsafe { INFO[g].frame_size = last_xy }
}
State::Watch
} else {
info!("grabber{} alignment lost", g);
State::Reset
}
} else {
info!("grabber{} lock lost", g);
State::Reset
}
}
};
unsafe {
INFO[g].state = next;
}
}
}

View File

@ -19,7 +19,7 @@ pub mod drtioaux;
#[cfg(has_drtio)] #[cfg(has_drtio)]
pub mod drtioaux_async; pub mod drtioaux_async;
pub mod drtioaux_proto; pub mod drtioaux_proto;
#[cfg(feature = "target_kasli_soc")] #[cfg(all(feature = "target_kasli_soc", has_drtio))]
pub mod io_expander; pub mod io_expander;
pub mod logger; pub mod logger;
#[cfg(has_drtio)] #[cfg(has_drtio)]
@ -31,6 +31,8 @@ pub mod mem;
pub mod pl; pub mod pl;
#[cfg(has_drtio_eem)] #[cfg(has_drtio_eem)]
pub mod drtio_eem; pub mod drtio_eem;
#[cfg(has_grabber)]
pub mod grabber;
#[cfg(has_si5324)] #[cfg(has_si5324)]
pub mod si5324; pub mod si5324;

View File

@ -103,6 +103,7 @@ pub enum Message {
SubkernelMsgRecvRequest { SubkernelMsgRecvRequest {
id: u32, id: u32,
timeout: u64, timeout: u64,
tags: Vec<u8>,
}, },
#[cfg(has_drtio)] #[cfg(has_drtio)]
SubkernelMsgRecvReply { 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 ()) { 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 core1_tx = unsafe { KERNEL_CHANNEL_1TO0.as_mut().unwrap() };
let mut buffer = Vec::<u8>::new(); let mut buffer = Vec::<u8>::new();
send_args(&mut buffer, service, tag.as_ref(), data).expect("RPC encoding failed"); send_args(&mut buffer, service, tag.as_ref(), data, true).expect("RPC encoding failed");
core1_tx.send(Message::RpcSend { is_async, data: buffer }); core1_tx.send(Message::RpcSend { is_async, data: buffer });
} }

View File

@ -53,7 +53,7 @@ pub extern "C" fn await_finish(id: u32, timeout: u64) {
pub extern "C" fn send_message(id: u32, 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(); let mut buffer = Vec::<u8>::new();
send_args(&mut buffer, 0, tag.as_ref(), data).expect("RPC encoding failed"); send_args(&mut buffer, 0, tag.as_ref(), data, false).expect("RPC encoding failed");
// overwrite service tag, include how many tags are in the message // overwrite service tag, include how many tags are in the message
buffer[3] = count; buffer[3] = count;
unsafe { unsafe {
@ -68,7 +68,7 @@ pub extern "C" fn send_message(id: u32, count: u8, tag: &CSlice<u8>, data: *cons
} }
} }
pub extern "C" fn await_message(id: u32, timeout: u64, min: u8, max: u8) { pub extern "C" fn await_message(id: u32, timeout: u64, tags: &CSlice<u8>, min: u8, max: u8) {
unsafe { unsafe {
KERNEL_CHANNEL_1TO0 KERNEL_CHANNEL_1TO0
.as_mut() .as_mut()
@ -76,6 +76,7 @@ pub extern "C" fn await_message(id: u32, timeout: u64, min: u8, max: u8) {
.send(Message::SubkernelMsgRecvRequest { .send(Message::SubkernelMsgRecvRequest {
id: id, id: id,
timeout: timeout, timeout: timeout,
tags: tags.as_ref().to_vec(),
}); });
} }
match unsafe { KERNEL_CHANNEL_0TO1.as_mut().unwrap() }.recv() { match unsafe { KERNEL_CHANNEL_0TO1.as_mut().unwrap() }.recv() {

View File

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

View File

@ -5,7 +5,7 @@ use core_io::Error as IoError;
use cslice::CSlice; use cslice::CSlice;
use futures::{future::FutureExt, select_biased}; use futures::{future::FutureExt, select_biased};
#[cfg(has_drtio)] #[cfg(has_drtio)]
use io::{Cursor, ProtoRead}; use io::Cursor;
#[cfg(has_drtio)] #[cfg(has_drtio)]
use ksupport::rpc; use ksupport::rpc;
use ksupport::{kernel, resolve_channel_name}; use ksupport::{kernel, resolve_channel_name};
@ -451,7 +451,7 @@ async fn handle_run_kernel(
.await; .await;
} }
#[cfg(has_drtio)] #[cfg(has_drtio)]
kernel::Message::SubkernelMsgRecvRequest { id, timeout } => { kernel::Message::SubkernelMsgRecvRequest { id, timeout, tags } => {
let message_received = subkernel::message_await(id, timeout, timer).await; let message_received = subkernel::message_await(id, timeout, timer).await;
let (status, count) = match message_received { let (status, count) = match message_received {
Ok(ref message) => (kernel::SubkernelStatus::NoError, message.count), Ok(ref message) => (kernel::SubkernelStatus::NoError, message.count),
@ -471,7 +471,7 @@ async fn handle_run_kernel(
if let Ok(message) = message_received { if let Ok(message) = message_received {
// receive code almost identical to RPC recv, except we are not reading from a stream // receive code almost identical to RPC recv, except we are not reading from a stream
let mut reader = Cursor::new(message.data); let mut reader = Cursor::new(message.data);
let mut tag: [u8; 1] = [message.tag]; let mut current_tags: &[u8] = &tags;
let mut i = 0; let mut i = 0;
loop { loop {
// kernel has to consume all arguments in the whole message // kernel has to consume all arguments in the whole message
@ -479,7 +479,7 @@ async fn handle_run_kernel(
kernel::Message::RpcRecvRequest(slot) => slot, kernel::Message::RpcRecvRequest(slot) => slot,
other => panic!("expected root value slot from core1, not {:?}", other), other => panic!("expected root value slot from core1, not {:?}", other),
}; };
rpc::recv_return(&mut reader, &tag, slot, &mut |size| { let remaining_tags = rpc::recv_return(&mut reader, &current_tags, slot, &mut |size| {
if size == 0 { if size == 0 {
0 as *mut () 0 as *mut ()
} else { } else {
@ -500,7 +500,7 @@ async fn handle_run_kernel(
.await; .await;
i += 1; i += 1;
if i < count { if i < count {
tag[0] = reader.read_u8()?; current_tags = remaining_tags;
} else { } else {
break; break;
} }

View File

@ -8,14 +8,14 @@
#[macro_use] #[macro_use]
extern crate alloc; extern crate alloc;
#[cfg(feature = "target_kasli_soc")] #[cfg(all(feature = "target_kasli_soc", has_drtio))]
use core::cell::RefCell; use core::cell::RefCell;
use ksupport; use ksupport;
use libasync::task; use libasync::task;
#[cfg(has_drtio_eem)] #[cfg(has_drtio_eem)]
use libboard_artiq::drtio_eem; use libboard_artiq::drtio_eem;
#[cfg(feature = "target_kasli_soc")] #[cfg(all(feature = "target_kasli_soc", has_drtio))]
use libboard_artiq::io_expander; use libboard_artiq::io_expander;
use libboard_artiq::{identifier_read, logger, pl}; use libboard_artiq::{identifier_read, logger, pl};
use libboard_zynq::{gic, mpcore, timer::GlobalTimer}; use libboard_zynq::{gic, mpcore, timer::GlobalTimer};
@ -38,7 +38,7 @@ mod rtio_mgt;
#[cfg(has_drtio)] #[cfg(has_drtio)]
mod subkernel; mod subkernel;
#[cfg(feature = "target_kasli_soc")] #[cfg(all(feature = "target_kasli_soc", has_drtio))]
async fn io_expanders_service( async fn io_expanders_service(
i2c_bus: RefCell<&mut libboard_zynq::i2c::I2c>, i2c_bus: RefCell<&mut libboard_zynq::i2c::I2c>,
io_expander0: RefCell<io_expander::IoExpander>, io_expander0: RefCell<io_expander::IoExpander>,
@ -57,6 +57,22 @@ async fn io_expanders_service(
} }
} }
#[cfg(has_grabber)]
mod grabber {
use libasync::delay;
use libboard_artiq::grabber;
use libboard_zynq::time::Milliseconds;
use crate::GlobalTimer;
pub async fn grabber_thread(timer: GlobalTimer) {
let mut countdown = timer.countdown();
loop {
grabber::tick();
delay(&mut countdown, Milliseconds(200)).await;
}
}
}
static mut LOG_BUFFER: [u8; 1 << 17] = [0; 1 << 17]; static mut LOG_BUFFER: [u8; 1 << 17] = [0; 1 << 17];
#[no_mangle] #[no_mangle]
@ -77,15 +93,11 @@ pub fn main_core0() {
info!("gateware ident: {}", identifier_read(&mut [0; 64])); info!("gateware ident: {}", identifier_read(&mut [0; 64]));
ksupport::i2c::init(); ksupport::i2c::init();
#[cfg(feature = "target_kasli_soc")] #[cfg(all(feature = "target_kasli_soc", has_drtio))]
let i2c_bus = unsafe { (ksupport::i2c::I2C_BUS).as_mut().unwrap() };
#[cfg(feature = "target_kasli_soc")]
let (mut io_expander0, mut io_expander1);
#[cfg(feature = "target_kasli_soc")]
{ {
io_expander0 = io_expander::IoExpander::new(i2c_bus, 0).unwrap(); let i2c_bus = unsafe { (ksupport::i2c::I2C_BUS).as_mut().unwrap() };
io_expander1 = io_expander::IoExpander::new(i2c_bus, 1).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_expander0
.init(i2c_bus) .init(i2c_bus)
.expect("I2C I/O expander #0 initialization failed"); .expect("I2C I/O expander #0 initialization failed");
@ -99,6 +111,11 @@ pub fn main_core0() {
io_expander1.set(1, 1, false); io_expander1.set(1, 1, false);
io_expander0.service(i2c_bus).unwrap(); io_expander0.service(i2c_bus).unwrap();
io_expander1.service(i2c_bus).unwrap(); io_expander1.service(i2c_bus).unwrap();
task::spawn(io_expanders_service(
RefCell::new(i2c_bus),
RefCell::new(io_expander0),
RefCell::new(io_expander1),
));
} }
let cfg = match Config::new() { let cfg = match Config::new() {
@ -114,13 +131,10 @@ pub fn main_core0() {
#[cfg(has_drtio_eem)] #[cfg(has_drtio_eem)]
drtio_eem::init(&mut timer, &cfg); drtio_eem::init(&mut timer, &cfg);
#[cfg(has_grabber)]
task::spawn(grabber::grabber_thread(timer));
task::spawn(ksupport::report_async_rtio_errors()); 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); comms::main(timer, cfg);
} }

View File

@ -212,7 +212,6 @@ pub async fn await_finish(
pub struct Message { pub struct Message {
from_id: u32, from_id: u32,
pub count: u8, pub count: u8,
pub tag: u8,
pub data: Vec<u8>, pub data: Vec<u8>,
} }
@ -236,8 +235,7 @@ pub async fn message_handle_incoming(id: u32, last: bool, length: usize, data: &
Message { Message {
from_id: id, from_id: id,
count: data[0], count: data[0],
tag: data[1], data: data[1..length].to_vec(),
data: data[2..length].to_vec(),
}, },
); );
} }

View File

@ -23,6 +23,8 @@ extern crate alloc;
use analyzer::Analyzer; use analyzer::Analyzer;
use dma::Manager as DmaManager; use dma::Manager as DmaManager;
use embedded_hal::blocking::delay::DelayUs; use embedded_hal::blocking::delay::DelayUs;
#[cfg(has_grabber)]
use libboard_artiq::grabber;
#[cfg(feature = "target_kasli_soc")] #[cfg(feature = "target_kasli_soc")]
use libboard_artiq::io_expander; use libboard_artiq::io_expander;
#[cfg(has_si5324)] #[cfg(has_si5324)]
@ -698,6 +700,8 @@ fn hardware_tick(ts: &mut u64, timer: &mut GlobalTimer) {
if now > ts_ms { if now > ts_ms {
ts_ms = now + Milliseconds(200); ts_ms = now + Milliseconds(200);
*ts = ts_ms.0; *ts = ts_ms.0;
#[cfg(has_grabber)]
grabber::tick();
} }
} }

View File

@ -6,7 +6,7 @@ use core::{cmp::min, option::NoneError, slice, str};
use core_io::{Error as IoError, Write}; use core_io::{Error as IoError, Write};
use cslice::AsCSlice; use cslice::AsCSlice;
use io::{Cursor, ProtoRead, ProtoWrite}; use io::{Cursor, ProtoWrite};
use ksupport::{eh_artiq, kernel, rpc}; use ksupport::{eh_artiq, kernel, rpc};
use libboard_artiq::{drtioaux_proto::{MASTER_PAYLOAD_MAX_SIZE, SAT_PAYLOAD_MAX_SIZE}, use libboard_artiq::{drtioaux_proto::{MASTER_PAYLOAD_MAX_SIZE, SAT_PAYLOAD_MAX_SIZE},
pl::csr}; pl::csr};
@ -14,12 +14,12 @@ use libboard_zynq::{time::Milliseconds, timer::GlobalTimer};
use libcortex_a9::sync_channel::Receiver; use libcortex_a9::sync_channel::Receiver;
use log::warn; use log::warn;
#[derive(Debug, Clone, Copy, PartialEq)] #[derive(Debug, Clone, PartialEq)]
enum KernelState { enum KernelState {
Absent, Absent,
Loaded, Loaded,
Running, Running,
MsgAwait(Milliseconds), MsgAwait(Milliseconds, Vec<u8>),
MsgSending, MsgSending,
} }
@ -66,7 +66,6 @@ pub struct Sliceable {
/* represents interkernel messages */ /* represents interkernel messages */
struct Message { struct Message {
count: u8, count: u8,
tag: u8,
data: Vec<u8>, data: Vec<u8>,
} }
@ -183,8 +182,7 @@ impl MessageManager {
None => { None => {
self.in_buffer = Some(Message { self.in_buffer = Some(Message {
count: data[0], count: data[0],
tag: data[1], data: data[1..length].to_vec(),
data: data[2..length].to_vec(),
}); });
} }
}; };
@ -509,9 +507,9 @@ impl<'a> Manager<'_> {
self.session.messages.accept_outgoing(data)?; self.session.messages.accept_outgoing(data)?;
self.session.kernel_state = KernelState::MsgSending; self.session.kernel_state = KernelState::MsgSending;
} }
kernel::Message::SubkernelMsgRecvRequest { id: _, timeout } => { kernel::Message::SubkernelMsgRecvRequest { id: _, timeout, tags } => {
let max_time = timer.get_time() + Milliseconds(timeout); let max_time = timer.get_time() + Milliseconds(timeout);
self.session.kernel_state = KernelState::MsgAwait(max_time); self.session.kernel_state = KernelState::MsgAwait(max_time, tags);
} }
kernel::Message::UpDestinationsRequest(destination) => { kernel::Message::UpDestinationsRequest(destination) => {
self.control self.control
@ -526,9 +524,9 @@ impl<'a> Manager<'_> {
} }
fn process_external_messages(&mut self, timer: GlobalTimer) -> Result<(), Error> { fn process_external_messages(&mut self, timer: GlobalTimer) -> Result<(), Error> {
match self.session.kernel_state { match &self.session.kernel_state {
KernelState::MsgAwait(timeout) => { KernelState::MsgAwait(timeout, tags) => {
if timer.get_time() > timeout { if timer.get_time() > *timeout {
self.control.tx.send(kernel::Message::SubkernelMsgRecvReply { self.control.tx.send(kernel::Message::SubkernelMsgRecvReply {
status: kernel::SubkernelStatus::Timeout, status: kernel::SubkernelStatus::Timeout,
count: 0, count: 0,
@ -541,8 +539,9 @@ impl<'a> Manager<'_> {
status: kernel::SubkernelStatus::NoError, status: kernel::SubkernelStatus::NoError,
count: message.count, count: message.count,
}); });
let tags = tags.clone();
self.session.kernel_state = KernelState::Running; self.session.kernel_state = KernelState::Running;
self.pass_message_to_kernel(&message, timer) self.pass_message_to_kernel(&message, tags, timer)
} else { } else {
Err(Error::AwaitingMessage) Err(Error::AwaitingMessage)
} }
@ -560,9 +559,9 @@ impl<'a> Manager<'_> {
} }
} }
fn pass_message_to_kernel(&mut self, message: &Message, timer: GlobalTimer) -> Result<(), Error> { fn pass_message_to_kernel(&mut self, message: &Message, tags: Vec<u8>, timer: GlobalTimer) -> Result<(), Error> {
let mut reader = Cursor::new(&message.data); let mut reader = Cursor::new(&message.data);
let mut tag: [u8; 1] = [message.tag]; let mut current_tags: &[u8] = &tags;
let mut i = message.count; let mut i = message.count;
loop { loop {
let slot = match recv_w_timeout(&mut self.control.rx, timer, 100)? { let slot = match recv_w_timeout(&mut self.control.rx, timer, 100)? {
@ -571,7 +570,7 @@ impl<'a> Manager<'_> {
}; };
let mut exception: Option<Sliceable> = None; let mut exception: Option<Sliceable> = None;
let mut unexpected: Option<String> = None; let mut unexpected: Option<String> = None;
rpc::recv_return(&mut reader, &tag, slot, &mut |size| { let remaining_tags = rpc::recv_return(&mut reader, current_tags, slot, &mut |size| {
if size == 0 { if size == 0 {
0 as *mut () 0 as *mut ()
} else { } else {
@ -610,8 +609,7 @@ impl<'a> Manager<'_> {
if i == 0 { if i == 0 {
break; break;
} else { } else {
// update the tag for next read current_tags = remaining_tags;
tag[0] = reader.read_u8()?;
} }
} }
Ok(()) Ok(())