forked from M-Labs/artiq
1
0
Fork 0

add channel names to RTIO errors

This commit is contained in:
Egor Savkin 2022-12-02 16:27:03 +08:00 committed by GitHub
parent c591e7e305
commit 1852491102
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 281 additions and 34 deletions

View File

@ -15,6 +15,7 @@ Highlights:
* Sampler: adjusted ADC MU to Volt conversion base for Sampler since v2.2. * Sampler: adjusted ADC MU to Volt conversion base for Sampler since v2.2.
For earlier version please explicitly define it as an argument in the device database file For earlier version please explicitly define it as an argument in the device database file
(e.g. ``"hw_rev": "v2.1"``). (e.g. ``"hw_rev": "v2.1"``).
* Added channel names to RTIO errors.
ARTIQ-7 ARTIQ-7
------- -------

View File

@ -80,6 +80,10 @@ class AD9914:
self.set_x_duration_mu = 7 * self.write_duration_mu self.set_x_duration_mu = 7 * self.write_duration_mu
self.exit_x_duration_mu = 3 * self.write_duration_mu self.exit_x_duration_mu = 3 * self.write_duration_mu
@staticmethod
def get_rtio_channels(bus_channel, **kwargs):
return [(bus_channel, None)]
@kernel @kernel
def write(self, addr, data): def write(self, addr, data):
rtio_output((self.bus_channel << 8) | addr, data) rtio_output((self.bus_channel << 8) | addr, data)

View File

@ -73,6 +73,10 @@ class ADF5356:
self._init_registers() self._init_registers()
@staticmethod
def get_rtio_channels(channel, **kwargs):
return [(channel, None)]
@kernel @kernel
def init(self, blind=False): def init(self, blind=False):
""" """

View File

@ -91,6 +91,10 @@ class EdgeCounter:
self.channel = channel self.channel = channel
self.counter_max = (1 << (gateware_width - 1)) - 1 self.counter_max = (1 << (gateware_width - 1)) - 1
@staticmethod
def get_rtio_channels(channel, **kwargs):
return [(channel, None)]
@kernel @kernel
def gate_rising(self, duration): def gate_rising(self, duration):
"""Count rising edges for the given duration and request the total at """Count rising edges for the given duration and request the total at

View File

@ -52,6 +52,10 @@ class Fastino:
assert self.core.ref_period == 1*ns assert self.core.ref_period == 1*ns
self.t_frame = int64(14*7*4) self.t_frame = int64(14*7*4)
@staticmethod
def get_rtio_channels(channel, **kwargs):
return [(channel, None)]
@kernel @kernel
def init(self): def init(self):
"""Initialize the device. """Initialize the device.

View File

@ -25,6 +25,10 @@ class Grabber:
# ROI engine outputs for one video frame. # ROI engine outputs for one video frame.
self.sentinel = int32(int64(2**count_width)) self.sentinel = int32(int64(2**count_width))
@staticmethod
def get_rtio_channels(channel_base, **kwargs):
return [(channel_base, "ROI coordinates"), (channel_base + 1, "ROI mask")]
@kernel @kernel
def setup_roi(self, n, x0, y0, x1, y1): def setup_roi(self, n, x0, y0, x1, y1):
""" """

View File

@ -229,7 +229,7 @@ class Phaser:
"dac_mmap"} "dac_mmap"}
def __init__(self, dmgr, channel_base, miso_delay=1, tune_fifo_offset=True, def __init__(self, dmgr, channel_base, miso_delay=1, tune_fifo_offset=True,
clk_sel=0, sync_dly=0, dac=None, trf0=None, trf1=None, clk_sel=0, sync_dly=0, dac=None, trf0=None, trf1=None, gw_rev=PHASER_GW_BASE,
core_device="core"): core_device="core"):
self.channel_base = channel_base self.channel_base = channel_base
self.core = dmgr.get(core_device) self.core = dmgr.get(core_device)
@ -243,13 +243,25 @@ class Phaser:
self.clk_sel = clk_sel self.clk_sel = clk_sel
self.tune_fifo_offset = tune_fifo_offset self.tune_fifo_offset = tune_fifo_offset
self.sync_dly = sync_dly self.sync_dly = sync_dly
self.gw_rev = -1 # discovered in init() self.gw_rev = gw_rev # verified in init()
self.dac_mmap = DAC34H84(dac).get_mmap() self.dac_mmap = DAC34H84(dac).get_mmap()
self.channel = [PhaserChannel(self, ch, trf) self.channel = [PhaserChannel(self, ch, trf)
for ch, trf in enumerate([trf0, trf1])] for ch, trf in enumerate([trf0, trf1])]
@staticmethod
def get_rtio_channels(channel_base, gw_rev=PHASER_GW_BASE, **kwargs):
if gw_rev == PHASER_GW_MIQRO:
return [(channel_base, "base"), (channel_base + 1, "ch0"), (channel_base + 2, "ch1")]
elif gw_rev == PHASER_GW_BASE:
return [(channel_base, "base"),
(channel_base + 1, "ch0 frequency"),
(channel_base + 2, "ch0 phase amplitude"),
(channel_base + 3, "ch1 frequency"),
(channel_base + 4, "ch1 phase amplitude")]
raise ValueError("invalid gw_rev `{}`".format(gw_rev))
@kernel @kernel
def init(self, debug=False): def init(self, debug=False):
"""Initialize the board. """Initialize the board.
@ -267,10 +279,11 @@ class Phaser:
delay(.1*ms) # slack delay(.1*ms) # slack
is_baseband = hw_rev & PHASER_HW_REV_VARIANT is_baseband = hw_rev & PHASER_HW_REV_VARIANT
self.gw_rev = self.read8(PHASER_ADDR_GW_REV) gw_rev = self.read8(PHASER_ADDR_GW_REV)
if debug: if debug:
print("gw_rev:", self.gw_rev) print("gw_rev:", self.gw_rev)
self.core.break_realtime() self.core.break_realtime()
assert gw_rev == self.gw_rev
delay(.1*ms) # slack delay(.1*ms) # slack
# allow a few errors during startup and alignment since boot # allow a few errors during startup and alignment since boot

View File

@ -334,6 +334,19 @@ class SAWG:
self.phase0 = Spline(width, time_width, channel_base + 9, self.phase0 = Spline(width, time_width, channel_base + 9,
self.core, 1.) self.core, 1.)
@staticmethod
def get_rtio_channels(channel_base, **kwargs):
return [(channel_base, "base"),
(channel_base+1, "offset"),
(channel_base+2, "amplitude 1"),
(channel_base+3, "frequency 1"),
(channel_base+4, "phase 1"),
(channel_base+5, "amplitude 2"),
(channel_base+6, "frequency 2"),
(channel_base+7, "phase 2"),
(channel_base+8, "frequency 0"),
(channel_base+9, "phase0")]
@kernel @kernel
def reset(self): def reset(self):
"""Re-establish initial conditions. """Re-establish initial conditions.

View File

@ -72,6 +72,10 @@ class SPIMaster:
self.channel = channel self.channel = channel
self.update_xfer_duration_mu(div, length) self.update_xfer_duration_mu(div, length)
@staticmethod
def get_rtio_channels(channel, **kwargs):
return [(channel, None)]
@portable @portable
def frequency_to_div(self, f): def frequency_to_div(self, f):
"""Convert a SPI clock frequency to the closest SPI clock divider.""" """Convert a SPI clock frequency to the closest SPI clock divider."""

View File

@ -41,6 +41,10 @@ class Spline:
self.time_scale = float((1 << time_width) * self.time_scale = float((1 << time_width) *
core_device.coarse_ref_period) core_device.coarse_ref_period)
@staticmethod
def get_rtio_channels(channel, **kwargs):
return [(channel, None)]
@portable(flags={"fast-math"}) @portable(flags={"fast-math"})
def to_mu(self, value: TFloat) -> TInt32: def to_mu(self, value: TFloat) -> TInt32:
"""Convert floating point ``value`` from physical units to 32 bit """Convert floating point ``value`` from physical units to 32 bit

View File

@ -85,6 +85,10 @@ class SUServo:
self.corrected_fs = sampler.Sampler.use_corrected_fs(sampler_hw_rev) self.corrected_fs = sampler.Sampler.use_corrected_fs(sampler_hw_rev)
assert self.ref_period_mu == self.core.ref_multiplier assert self.ref_period_mu == self.core.ref_multiplier
@staticmethod
def get_rtio_channels(channel, **kwargs):
return [(channel, None)]
@kernel @kernel
def init(self): def init(self):
"""Initialize the servo, Sampler and both Urukuls. """Initialize the servo, Sampler and both Urukuls.
@ -257,6 +261,10 @@ class Channel:
self.servo.channel) self.servo.channel)
self.dds = self.servo.ddses[self.servo_channel // 4] self.dds = self.servo.ddses[self.servo_channel // 4]
@staticmethod
def get_rtio_channels(channel, **kwargs):
return [(channel, None)]
@kernel @kernel
def set(self, en_out, en_iir=0, profile=0): def set(self, en_out, en_iir=0, profile=0):
"""Operate channel. """Operate channel.

View File

@ -36,6 +36,10 @@ class TTLOut:
self.channel = channel self.channel = channel
self.target_o = channel << 8 self.target_o = channel << 8
@staticmethod
def get_rtio_channels(channel, **kwargs):
return [(channel, None)]
@kernel @kernel
def output(self): def output(self):
pass pass
@ -128,6 +132,10 @@ class TTLInOut:
self.target_sens = (channel << 8) + 2 self.target_sens = (channel << 8) + 2
self.target_sample = (channel << 8) + 3 self.target_sample = (channel << 8) + 3
@staticmethod
def get_rtio_channels(channel, **kwargs):
return [(channel, None)]
@kernel @kernel
def set_oe(self, oe): def set_oe(self, oe):
rtio_output(self.target_oe, 1 if oe else 0) rtio_output(self.target_oe, 1 if oe else 0)
@ -465,6 +473,10 @@ class TTLClockGen:
self.acc_width = numpy.int64(acc_width) self.acc_width = numpy.int64(acc_width)
@staticmethod
def get_rtio_channels(channel, **kwargs):
return [(channel, None)]
@portable @portable
def frequency_to_ftw(self, frequency): def frequency_to_ftw(self, frequency):
"""Returns the frequency tuning word corresponding to the given """Returns the frequency tuning word corresponding to the given

View File

@ -414,13 +414,13 @@ extern fn dma_playback(timestamp: i64, ptr: i32) {
csr::rtio_dma::error_write(1); csr::rtio_dma::error_write(1);
if error & 1 != 0 { if error & 1 != 0 {
raise!("RTIOUnderflow", raise!("RTIOUnderflow",
"RTIO underflow at {0} mu, channel {1}", "RTIO underflow at channel {rtio_channel_info:0}, {1} mu",
timestamp as i64, channel as i64, 0); channel as i64, timestamp as i64, 0);
} }
if error & 2 != 0 { if error & 2 != 0 {
raise!("RTIODestinationUnreachable", raise!("RTIODestinationUnreachable",
"RTIO destination unreachable, output, at {0} mu, channel {1}", "RTIO destination unreachable, output, at channel {rtio_channel_info:0}, {1} mu",
timestamp as i64, channel as i64, 0); channel as i64, timestamp as i64, 0);
} }
} }
} }

View File

@ -67,13 +67,13 @@ mod imp {
} }
if status & RTIO_O_STATUS_UNDERFLOW != 0 { if status & RTIO_O_STATUS_UNDERFLOW != 0 {
raise!("RTIOUnderflow", raise!("RTIOUnderflow",
"RTIO underflow at {0} mu, channel {1}, slack {2} mu", "RTIO underflow at channel {rtio_channel_info:0}, {1} mu, slack {2} mu",
timestamp, channel as i64, timestamp - get_counter()); channel as i64, timestamp, timestamp - get_counter());
} }
if status & RTIO_O_STATUS_DESTINATION_UNREACHABLE != 0 { if status & RTIO_O_STATUS_DESTINATION_UNREACHABLE != 0 {
raise!("RTIODestinationUnreachable", raise!("RTIODestinationUnreachable",
"RTIO destination unreachable, output, at {0} mu, channel {1}", "RTIO destination unreachable, output, at channel {rtio_channel_info:0}, {1} mu",
timestamp, channel as i64, 0); channel as i64, timestamp, 0);
} }
} }
@ -115,7 +115,7 @@ mod imp {
if status & RTIO_I_STATUS_OVERFLOW != 0 { if status & RTIO_I_STATUS_OVERFLOW != 0 {
raise!("RTIOOverflow", raise!("RTIOOverflow",
"RTIO input overflow on channel {0}", "RTIO input overflow on channel {rtio_channel_info:0}",
channel as i64, 0, 0); channel as i64, 0, 0);
} }
if status & RTIO_I_STATUS_WAIT_EVENT != 0 { if status & RTIO_I_STATUS_WAIT_EVENT != 0 {
@ -123,7 +123,7 @@ mod imp {
} }
if status & RTIO_I_STATUS_DESTINATION_UNREACHABLE != 0 { if status & RTIO_I_STATUS_DESTINATION_UNREACHABLE != 0 {
raise!("RTIODestinationUnreachable", raise!("RTIODestinationUnreachable",
"RTIO destination unreachable, input, on channel {0}", "RTIO destination unreachable, input, on channel {rtio_channel_info:0}",
channel as i64, 0, 0); channel as i64, 0, 0);
} }
@ -143,12 +143,12 @@ mod imp {
if status & RTIO_I_STATUS_OVERFLOW != 0 { if status & RTIO_I_STATUS_OVERFLOW != 0 {
raise!("RTIOOverflow", raise!("RTIOOverflow",
"RTIO input overflow on channel {0}", "RTIO input overflow on channel {rtio_channel_info:0}",
channel as i64, 0, 0); channel as i64, 0, 0);
} }
if status & RTIO_I_STATUS_DESTINATION_UNREACHABLE != 0 { if status & RTIO_I_STATUS_DESTINATION_UNREACHABLE != 0 {
raise!("RTIODestinationUnreachable", raise!("RTIODestinationUnreachable",
"RTIO destination unreachable, input, on channel {0}", "RTIO destination unreachable, input, on channel {rtio_channel_info:0}",
channel as i64, 0, 0); channel as i64, 0, 0);
} }
@ -168,7 +168,7 @@ mod imp {
if status & RTIO_I_STATUS_OVERFLOW != 0 { if status & RTIO_I_STATUS_OVERFLOW != 0 {
raise!("RTIOOverflow", raise!("RTIOOverflow",
"RTIO input overflow on channel {0}", "RTIO input overflow on channel {rtio_channel_info:0}",
channel as i64, 0, 0); channel as i64, 0, 0);
} }
if status & RTIO_I_STATUS_WAIT_EVENT != 0 { if status & RTIO_I_STATUS_WAIT_EVENT != 0 {
@ -176,7 +176,7 @@ mod imp {
} }
if status & RTIO_I_STATUS_DESTINATION_UNREACHABLE != 0 { if status & RTIO_I_STATUS_DESTINATION_UNREACHABLE != 0 {
raise!("RTIODestinationUnreachable", raise!("RTIODestinationUnreachable",
"RTIO destination unreachable, input, on channel {0}", "RTIO destination unreachable, input, on channel {rtio_channel_info:0}",
channel as i64, 0, 0); channel as i64, 0, 0);
} }

View File

@ -1,4 +1,4 @@
#![feature(lang_items, panic_info_message)] #![feature(lang_items, panic_info_message, const_btree_new, iter_advance_by)]
#![no_std] #![no_std]
extern crate eh; extern crate eh;

View File

@ -1,15 +1,20 @@
use alloc::collections::BTreeMap;
use alloc::string::String;
use core::cell::RefCell; use core::cell::RefCell;
use urc::Urc; use urc::Urc;
use board_misoc::csr; use board_misoc::{csr, config};
#[cfg(has_drtio)] #[cfg(has_drtio)]
use board_misoc::clock; use board_misoc::clock;
use board_artiq::drtio_routing; use board_artiq::drtio_routing;
use sched::Io; use sched::Io;
use sched::Mutex; use sched::Mutex;
use io::{Cursor, ProtoRead};
const ASYNC_ERROR_COLLISION: u8 = 1 << 0; const ASYNC_ERROR_COLLISION: u8 = 1 << 0;
const ASYNC_ERROR_BUSY: u8 = 1 << 1; const ASYNC_ERROR_BUSY: u8 = 1 << 1;
const ASYNC_ERROR_SEQUENCE_ERROR: u8 = 1 << 2; const ASYNC_ERROR_SEQUENCE_ERROR: u8 = 1 << 2;
static mut RTIO_DEVICE_MAP: BTreeMap<u32, String> = BTreeMap::new();
#[cfg(has_drtio)] #[cfg(has_drtio)]
pub mod drtio { pub mod drtio {
use super::*; use super::*;
@ -215,15 +220,15 @@ pub mod drtio {
destination_set_up(routing_table, up_destinations, destination, false), destination_set_up(routing_table, up_destinations, destination, false),
Ok(drtioaux::Packet::DestinationOkReply) => (), Ok(drtioaux::Packet::DestinationOkReply) => (),
Ok(drtioaux::Packet::DestinationSequenceErrorReply { channel }) => { Ok(drtioaux::Packet::DestinationSequenceErrorReply { channel }) => {
error!("[DEST#{}] RTIO sequence error involving channel 0x{:04x}", destination, channel); error!("[DEST#{}] RTIO sequence error involving channel {} 0x{:04x}", destination, resolve_channel_name(channel as u32), channel);
unsafe { SEEN_ASYNC_ERRORS |= ASYNC_ERROR_SEQUENCE_ERROR }; unsafe { SEEN_ASYNC_ERRORS |= ASYNC_ERROR_SEQUENCE_ERROR };
} }
Ok(drtioaux::Packet::DestinationCollisionReply { channel }) => { Ok(drtioaux::Packet::DestinationCollisionReply { channel }) => {
error!("[DEST#{}] RTIO collision involving channel 0x{:04x}", destination, channel); error!("[DEST#{}] RTIO collision involving channel {} 0x{:04x}", destination, resolve_channel_name(channel as u32), channel);
unsafe { SEEN_ASYNC_ERRORS |= ASYNC_ERROR_COLLISION }; unsafe { SEEN_ASYNC_ERRORS |= ASYNC_ERROR_COLLISION };
} }
Ok(drtioaux::Packet::DestinationBusyReply { channel }) => { Ok(drtioaux::Packet::DestinationBusyReply { channel }) => {
error!("[DEST#{}] RTIO busy error involving channel 0x{:04x}", destination, channel); error!("[DEST#{}] RTIO busy error involving channel {} 0x{:04x}", destination, resolve_channel_name(channel as u32), channel);
unsafe { SEEN_ASYNC_ERRORS |= ASYNC_ERROR_BUSY }; unsafe { SEEN_ASYNC_ERRORS |= ASYNC_ERROR_BUSY };
} }
Ok(packet) => error!("[DEST#{}] received unexpected aux packet: {:?}", destination, packet), Ok(packet) => error!("[DEST#{}] received unexpected aux packet: {:?}", destination, packet),
@ -349,16 +354,16 @@ fn async_error_thread(io: Io) {
io.until(|| csr::rtio_core::async_error_read() != 0).unwrap(); io.until(|| csr::rtio_core::async_error_read() != 0).unwrap();
let errors = csr::rtio_core::async_error_read(); let errors = csr::rtio_core::async_error_read();
if errors & ASYNC_ERROR_COLLISION != 0 { if errors & ASYNC_ERROR_COLLISION != 0 {
error!("RTIO collision involving channel {}", let channel = csr::rtio_core::collision_channel_read();
csr::rtio_core::collision_channel_read()); error!("RTIO collision involving channel {}:{}", channel, resolve_channel_name(channel as u32));
} }
if errors & ASYNC_ERROR_BUSY != 0 { if errors & ASYNC_ERROR_BUSY != 0 {
error!("RTIO busy error involving channel {}", let channel = csr::rtio_core::busy_channel_read();
csr::rtio_core::busy_channel_read()); error!("RTIO busy error involving channel {}:{}", channel, resolve_channel_name(channel as u32));
} }
if errors & ASYNC_ERROR_SEQUENCE_ERROR != 0 { if errors & ASYNC_ERROR_SEQUENCE_ERROR != 0 {
error!("RTIO sequence error involving channel {}", let channel = csr::rtio_core::sequence_error_channel_read();
csr::rtio_core::sequence_error_channel_read()); error!("RTIO sequence error involving channel {}:{}", channel, resolve_channel_name(channel as u32));
} }
SEEN_ASYNC_ERRORS = errors; SEEN_ASYNC_ERRORS = errors;
csr::rtio_core::async_error_write(errors); csr::rtio_core::async_error_write(errors);
@ -366,9 +371,47 @@ fn async_error_thread(io: Io) {
} }
} }
fn read_device_map() -> BTreeMap<u32, String> {
let mut device_map: BTreeMap<u32, String> = BTreeMap::new();
config::read("device_map", |value: Result<&[u8], config::Error>| {
let mut bytes = match value {
Ok(val) => if val.len() > 0 { Cursor::new(val) } else {
error!("read_device_map: `device_map` was not found in the config");
return;
},
Err(err) => {
error!("read_device_map: error reading `device_map` from config: {}", err);
return;
}
};
let size = bytes.read_u32().unwrap();
for _ in 0..size {
let channel = bytes.read_u32().unwrap();
let device_name= bytes.read_string().unwrap();
if let Some(old_entry) = device_map.insert(channel, device_name.clone()) {
error!("conflicting entries for channel {}: `{}` and `{}`",
channel, old_entry, device_name);
}
}
});
device_map
}
fn _resolve_channel_name(channel: u32, device_map: &BTreeMap<u32, String>) -> String {
match device_map.get(&channel) {
Some(val) => val.clone(),
None => String::from("unknown")
}
}
pub fn resolve_channel_name(channel: u32) -> String {
_resolve_channel_name(channel, unsafe{&RTIO_DEVICE_MAP})
}
pub fn startup(io: &Io, aux_mutex: &Mutex, pub fn startup(io: &Io, aux_mutex: &Mutex,
routing_table: &Urc<RefCell<drtio_routing::RoutingTable>>, routing_table: &Urc<RefCell<drtio_routing::RoutingTable>>,
up_destinations: &Urc<RefCell<[bool; drtio_routing::DEST_COUNT]>>) { up_destinations: &Urc<RefCell<[bool; drtio_routing::DEST_COUNT]>>) {
unsafe { RTIO_DEVICE_MAP = read_device_map(); }
drtio::startup(io, aux_mutex, routing_table, up_destinations); drtio::startup(io, aux_mutex, routing_table, up_destinations);
unsafe { unsafe {
csr::rtio_core::reset_phy_write(1); csr::rtio_core::reset_phy_write(1);

View File

@ -1,4 +1,4 @@
use core::{mem, str, cell::{Cell, RefCell}, fmt::Write as FmtWrite}; use core::{mem, str, cell::{Cell, RefCell}, fmt::Write as FmtWrite, slice};
use alloc::{vec::Vec, string::String}; use alloc::{vec::Vec, string::String};
use byteorder::{ByteOrder, NativeEndian}; use byteorder::{ByteOrder, NativeEndian};
use cslice::CSlice; use cslice::CSlice;
@ -10,7 +10,7 @@ use urc::Urc;
use sched::{ThreadHandle, Io, Mutex, TcpListener, TcpStream, Error as SchedError}; use sched::{ThreadHandle, Io, Mutex, TcpListener, TcpStream, Error as SchedError};
use rtio_clocking; use rtio_clocking;
use rtio_dma::Manager as DmaManager; use rtio_dma::Manager as DmaManager;
use rtio_mgt::get_async_errors; use rtio_mgt::{get_async_errors, resolve_channel_name};
use cache::Cache; use cache::Cache;
use kern_hwreq; use kern_hwreq;
use board_artiq::drtio_routing; use board_artiq::drtio_routing;
@ -449,6 +449,25 @@ fn process_kern_message(io: &Io, aux_mutex: &Mutex,
session.kernel_state = KernelState::Absent; session.kernel_state = KernelState::Absent;
unsafe { session.congress.cache.unborrow() } unsafe { session.congress.cache.unborrow() }
let exceptions_with_channel: Vec<Option<eh::eh_artiq::Exception>> = exceptions.iter()
.map(|exception| {
if let Some(exn) = exception {
let msg = str::from_utf8(unsafe{slice::from_raw_parts(exn.message.as_ptr(), exn.message.len())})
.unwrap()
.replace("{rtio_channel_info:0}", &format!("{}:{}", exn.param[0], resolve_channel_name(exn.param[0] as u32)));
Some(eh::eh_artiq::Exception {
id: exn.id,
file: exn.file,
line: exn.line,
column: exn.column,
function: exn.function,
message: unsafe {CSlice::new(msg.as_ptr(), msg.len())},
param: exn.param
})
} else { None }
})
.collect();
match stream { match stream {
None => { None => {
error!("exception in flash kernel"); error!("exception in flash kernel");
@ -459,7 +478,7 @@ fn process_kern_message(io: &Io, aux_mutex: &Mutex,
}, },
Some(ref mut stream) => { Some(ref mut stream) => {
host_write(stream, host::Reply::KernelException { host_write(stream, host::Reply::KernelException {
exceptions: exceptions, exceptions: &exceptions_with_channel,
stack_pointers: stack_pointers, stack_pointers: stack_pointers,
backtrace: backtrace, backtrace: backtrace,
async_errors: unsafe { get_async_errors() } async_errors: unsafe { get_async_errors() }

View File

@ -8,6 +8,7 @@ from itertools import count
from artiq import __version__ as artiq_version from artiq import __version__ as artiq_version
from artiq.coredevice import jsondesc from artiq.coredevice import jsondesc
from artiq.coredevice.phaser import PHASER_GW_MIQRO, PHASER_GW_BASE
def process_header(output, description): def process_header(output, description):
@ -566,10 +567,10 @@ class PeripheralManager:
def process_phaser(self, rtio_offset, peripheral): def process_phaser(self, rtio_offset, peripheral):
mode = peripheral.get("mode", "base") mode = peripheral.get("mode", "base")
if mode == "miqro": if mode == "miqro":
dac = ', "dac": {"pll_m": 16, "pll_n": 3, "interpolation": 2}' dac = f', "dac": {{"pll_m": 16, "pll_n": 3, "interpolation": 2}}, "gw_rev"={PHASER_GW_MIQRO}'
n_channels = 3 n_channels = 3
else: else:
dac = "" dac = f', "gw_rev"={PHASER_GW_BASE}'
n_channels = 5 n_channels = 5
self.gen(""" self.gen("""
device_db["{name}"] = {{ device_db["{name}"] = {{

89
artiq/frontend/artiq_rtiomap.py Executable file
View File

@ -0,0 +1,89 @@
#!/usr/bin/env python3
import argparse
import importlib
import struct
from sipyco import common_args
from artiq import __version__ as artiq_version
from artiq.master.databases import DeviceDB
def get_argparser():
parser = argparse.ArgumentParser(description="ARTIQ RTIO channel name map encoder tool")
parser.add_argument("--version", action="version",
version="ARTIQ v{}".format(artiq_version),
help="print the ARTIQ version number")
common_args.verbosity_args(parser)
parser.add_argument("--device-db", default="device_db.py",
help="device database file (default: '%(default)s')")
parser.add_argument("file", metavar="FILE", default=None,
help="write the result into the specified file, or read from it to show the map (see `--show`)")
parser.add_argument("--show", default=False, action="store_true",
help="show the channel mapping from the specified file, instead of writing to it")
return parser
def get_rtio_channels(desc):
if desc["type"] == "local":
module = importlib.import_module(desc["module"])
device_class = getattr(module, desc["class"])
return getattr(device_class, "get_rtio_channels", lambda **kwargs: [])(**desc.get("arguments", {}))
return []
def get_channel_map(device_db):
reversed_map = {}
for dev_name, device in device_db.items():
try:
channels = get_rtio_channels(device)
except Exception as e:
raise Exception(f"failed to process the device `{dev_name}`") from e
for chan, suffix in channels:
assert chan not in reversed_map
reversed_map[chan] = dev_name + (" " + suffix if suffix is not None else "")
return reversed_map
def serialize_device_map(channel_map, outfile):
outfile.write(struct.pack("<I", len(channel_map)))
for dev_num, dev_name in channel_map.items():
dev_name_bytes = dev_name.encode("utf-8")
outfile.write(struct.pack("<II{}s".format(len(dev_name_bytes)), dev_num, len(dev_name_bytes), dev_name_bytes))
def deserialize_device_map(infile):
result_map = dict()
ch_count, = struct.unpack_from("<I", infile.read(4))
for _ in range(ch_count):
dev_num, dev_name_len = struct.unpack_from("<II", infile.read(8))
dev_name = struct.unpack_from("<{}s".format(dev_name_len), infile.read(dev_name_len))[0].decode("utf-8")
assert dev_num not in result_map
result_map[dev_num] = dev_name
return result_map
def main():
args = get_argparser().parse_args()
common_args.init_logger_from_args(args)
if args.show:
with open(args.file, "rb") as infile:
chan_map = deserialize_device_map(infile)
for chan, device in sorted(chan_map.items(), key=lambda x: x[0]):
print(f"{chan} -> {device}")
else:
ddb = DeviceDB(args.device_db)
chan_map = get_channel_map(ddb.get_device_db())
with open(args.file, "wb") as outfile:
serialize_device_map(chan_map, outfile)
if __name__ == "__main__":
main()

View File

@ -13,7 +13,7 @@ class TestFrontends(unittest.TestCase):
], ],
"artiq": [ "artiq": [
"client", "compile", "coreanalyzer", "coremgmt", "client", "compile", "coreanalyzer", "coremgmt",
"flash", "master", "mkfs", "route", "flash", "master", "mkfs", "route", "rtiomap",
"rtiomon", "run", "session", "browser", "dashboard" "rtiomon", "run", "session", "browser", "dashboard"
] ]
} }

View File

@ -340,3 +340,13 @@ Other options include:
- ``ext0_bypass_125`` and ``ext0_bypass_100`` - explicit aliases for ``ext0_bypass``. - ``ext0_bypass_125`` and ``ext0_bypass_100`` - explicit aliases for ``ext0_bypass``.
Availability of these options depends on the board and their configuration - specific setting may or may not be supported. Availability of these options depends on the board and their configuration - specific setting may or may not be supported.
* Setup resolving RTIO channels to their names
This feature allows you to print the channels' respective names alongside with their numbers in RTIO error messages. To enable it, run the ``artiq_rtiomap`` tool and write its result into the device config at the ``device_map`` key: ::
$ artiq_rtiomap dev_map.bin
$ artiq_coremgmt config write -f device_map dev_map.bin
.. note:: You can find more information about how to use the ``artiq_rtiomap`` utility on the :ref:`Utilities <rtiomap-tool>` page.

View File

@ -116,6 +116,15 @@ Moninj proxy
:ref: artiq.frontend.aqctl_moninj_proxy.get_argparser :ref: artiq.frontend.aqctl_moninj_proxy.get_argparser
:prog: aqctl_moninj_proxy :prog: aqctl_moninj_proxy
.. _rtiomap-tool:
RTIO channel name map tool
--------------------------
.. argparse::
:ref: artiq.frontend.artiq_rtiomap.get_argparser
:prog: artiq_rtiomap
.. _core-device-rtio-analyzer-tool: .. _core-device-rtio-analyzer-tool:

View File

@ -23,6 +23,7 @@ console_scripts = [
"artiq_compile = artiq.frontend.artiq_compile:main", "artiq_compile = artiq.frontend.artiq_compile:main",
"artiq_coreanalyzer = artiq.frontend.artiq_coreanalyzer:main", "artiq_coreanalyzer = artiq.frontend.artiq_coreanalyzer:main",
"artiq_coremgmt = artiq.frontend.artiq_coremgmt:main", "artiq_coremgmt = artiq.frontend.artiq_coremgmt:main",
"artiq_rtiomap = artiq.frontend.artiq_rtiomap:main",
"artiq_ddb_template = artiq.frontend.artiq_ddb_template:main", "artiq_ddb_template = artiq.frontend.artiq_ddb_template:main",
"artiq_master = artiq.frontend.artiq_master:main", "artiq_master = artiq.frontend.artiq_master:main",
"artiq_mkfs = artiq.frontend.artiq_mkfs:main", "artiq_mkfs = artiq.frontend.artiq_mkfs:main",