diff --git a/RELEASE_NOTES.rst b/RELEASE_NOTES.rst index de797aaff..a14fafd11 100644 --- a/RELEASE_NOTES.rst +++ b/RELEASE_NOTES.rst @@ -13,31 +13,35 @@ Highlights: - HVAMP_8CH 8 channel HV amplifier for Fastino / Zotinos - Almazny mezzanine board for Mirny * Softcore targets now use the RISC-V architecture (VexRiscv) instead of OR1K (mor1kx). +* Gateware FPU is supported on KC705 and Kasli 2.0. * Faster compilation for large arrays/lists. * Phaser: - Improved documentation - Expose the DAC coarse mixer and ``sif_sync`` - Exposes upconverter calibration and enabling/disabling of upconverter LO & RF outputs. - Add helpers to align Phaser updates to the RTIO timeline (``get_next_frame_mu()``) -* ``get()``, ``get_mu()``, ``get_att()``, and ``get_att_mu()`` functions added for AD9910 and AD9912 +* Core device moninj is now proxied via the ``aqctl_moninj_proxy`` controller. +* The configuration entry ``rtio_clock`` supports multiple clocking settings, deprecating the usage + of compile-time options. +* Packaging via Nix Flakes. +* Firmware and gateware can now be built on-demand on the M-Labs server using ``afws_client`` + (subscribers only). +* Extended Kasli gateware JSON description with configuration for SPI over DIO. +* ``get()``, ``get_mu()``, ``get_att()``, and ``get_att_mu()`` functions added for AD9910 and AD9912. * On Kasli, the number of FIFO lanes in the scalable events dispatcher (SED) can now be configured in the JSON hardware description file. * ``artiq_ddb_template`` generates edge-counter keys that start with the key of the corresponding TTL device (e.g. ``ttl_0_counter`` for the edge counter on TTL device ``ttl_0``). * ``artiq_master`` now has an ``--experiment-subdir`` option to scan only a subdirectory of the repository when building the list of experiments. -* The configuration entry ``rtio_clock`` supports multiple clocking settings, deprecating the usage - of compile-time options. -* DRTIO: added support for 100MHz clock. +* Added support for 100MHz RTIO clock in DRTIO. * Previously detected RTIO async errors are reported to the host after each kernel terminates and a warning is logged. The warning is additional to the one already printed in the core device log upon detection of the error. -* Removed worker DB warning for writing a dataset that is also in the archive -* Extended Kasli gateware JSON description with configuration for SPI over DIO. - See: https://github.com/m-labs/artiq/pull/1800 +* Removed worker DB warning for writing a dataset that is also in the archive. * ``PCA9548`` I2C switch class renamed to ``I2CSwitch``, to accomodate support for PCA9547, and possibly other switches in future. Readback has been removed, and now only one channel per - switch is supported. + switch is supported. Breaking changes: @@ -51,7 +55,6 @@ Breaking changes: * Phaser: fixed coarse mixer frequency configuration * Mirny: Added extra delays in ``ADF5356.sync()``. This avoids the need of an extra delay before calling `ADF5356.init()`. -* DRTIO: Changed message alignment from 32-bits to 64-bits. * The deprecated ``set_dataset(..., save=...)`` is no longer supported. ARTIQ-6 diff --git a/artiq/browser/files.py b/artiq/browser/files.py index 103ca28db..e03f26483 100644 --- a/artiq/browser/files.py +++ b/artiq/browser/files.py @@ -107,7 +107,7 @@ class Hdf5FileSystemModel(QtWidgets.QFileSystemModel): v = ("artiq_version: {}\nrepo_rev: {}\nfile: {}\n" "class_name: {}\nrid: {}\nstart_time: {}").format( h5["artiq_version"][()], expid["repo_rev"], - expid["file"], expid["class_name"], + expid.get("file", ""), expid["class_name"], h5["rid"][()], start_time) return v except: @@ -179,7 +179,7 @@ class FilesDock(QtWidgets.QDockWidget): v = { "artiq_version": f["artiq_version"][()], "repo_rev": expid["repo_rev"], - "file": expid["file"], + "file": expid.get("file", ""), "class_name": expid["class_name"], "rid": f["rid"][()], "start_time": start_time, diff --git a/artiq/coredevice/comm_kernel.py b/artiq/coredevice/comm_kernel.py index 7db34453c..34151288f 100644 --- a/artiq/coredevice/comm_kernel.py +++ b/artiq/coredevice/comm_kernel.py @@ -277,6 +277,17 @@ class CoreException: traceback_str +\ '\n\nEnd of Core Device Traceback\n' + +def incompatible_versions(v1, v2): + if v1.endswith(".beta") or v2.endswith(".beta"): + # Beta branches may introduce breaking changes. Check version strictly. + return v1 != v2 + else: + # On stable branches, runtime/software protocol backward compatibility is kept. + # Runtime and software with the same major version number are compatible. + return v1.split(".", maxsplit=1)[0] != v2.split(".", maxsplit=1)[0] + + class CommKernel: warned_of_mismatch = False @@ -453,7 +464,7 @@ class CommKernel: runtime_id = self._read(4) if runtime_id == b"AROR": gateware_version = self._read_string().split(";")[0] - if gateware_version != software_version and not self.warned_of_mismatch: + if not self.warned_of_mismatch and incompatible_versions(gateware_version, software_version): logger.warning("Mismatch between gateware (%s) " "and software (%s) versions", gateware_version, software_version) diff --git a/artiq/coredevice/comm_mgmt.py b/artiq/coredevice/comm_mgmt.py index 7d8ef6f38..793b44a75 100644 --- a/artiq/coredevice/comm_mgmt.py +++ b/artiq/coredevice/comm_mgmt.py @@ -169,7 +169,7 @@ class CommMgmt: self._write_bytes(value) ty = self._read_header() if ty == Reply.Error: - raise IOError("Flash storage is full") + raise IOError("Device failed to write config. More information may be available in the log.") elif ty != Reply.Success: raise IOError("Incorrect reply from device: {} (expected {})". format(ty, Reply.Success)) diff --git a/artiq/coredevice/comm_moninj.py b/artiq/coredevice/comm_moninj.py index f03e91bbc..a6b95983e 100644 --- a/artiq/coredevice/comm_moninj.py +++ b/artiq/coredevice/comm_moninj.py @@ -33,14 +33,6 @@ class CommMonInj: try: self._writer.write(b"ARTIQ moninj\n") - # get device endian - endian = await self._reader.read(1) - if endian == b"e": - self.endian = "<" - elif endian == b"E": - self.endian = ">" - else: - raise IOError("Incorrect reply from device: expected e/E.") self._receive_task = asyncio.ensure_future(self._receive_cr()) except: self._writer.close() @@ -62,19 +54,19 @@ class CommMonInj: del self._writer def monitor_probe(self, enable, channel, probe): - packet = struct.pack(self.endian + "bblb", 0, enable, channel, probe) + packet = struct.pack("") elif column == 7: if v["expid"]["class_name"] is None: return "" diff --git a/artiq/examples/kasli_suservo/device_db.py b/artiq/examples/kasli_suservo/device_db.py index f0d3a48a2..c52b82a94 100644 --- a/artiq/examples/kasli_suservo/device_db.py +++ b/artiq/examples/kasli_suservo/device_db.py @@ -13,6 +13,13 @@ device_db = { "port": 1068, "command": "aqctl_corelog -p {port} --bind {bind} " + core_addr }, + "core_moninj": { + "type": "controller", + "host": "::1", + "port_proxy": 1383, + "port": 1384, + "command": "aqctl_moninj_proxy --port-proxy {port_proxy} --port-control {port} --bind {bind} " + core_addr + }, "core_cache": { "type": "local", "module": "artiq.coredevice.cache", diff --git a/artiq/examples/kc705_nist_clock/device_db.py b/artiq/examples/kc705_nist_clock/device_db.py index bf9637d32..1930f584b 100644 --- a/artiq/examples/kc705_nist_clock/device_db.py +++ b/artiq/examples/kc705_nist_clock/device_db.py @@ -17,6 +17,13 @@ device_db = { "port": 1068, "command": "aqctl_corelog -p {port} --bind {bind} " + core_addr }, + "core_moninj": { + "type": "controller", + "host": "::1", + "port_proxy": 1383, + "port": 1384, + "command": "aqctl_moninj_proxy --port-proxy {port_proxy} --port-control {port} --bind {bind} " + core_addr + }, "core_cache": { "type": "local", "module": "artiq.coredevice.cache", diff --git a/artiq/firmware/ksupport/api.rs b/artiq/firmware/ksupport/api.rs index 3e99731b4..1682f818b 100644 --- a/artiq/firmware/ksupport/api.rs +++ b/artiq/firmware/ksupport/api.rs @@ -63,7 +63,10 @@ static mut API: &'static [(&'static str, *const ())] = &[ api!(__powidf2), /* libc */ - api!(memcmp, extern { fn memcmp(a: *const u8, b: *mut u8, size: usize); }), + api!(memcpy, extern { fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8; }), + api!(memmove, extern { fn memmove(dest: *mut u8, src: *const u8, n: usize) -> *mut u8; }), + api!(memset, extern { fn memset(s: *mut u8, c: i32, n: usize) -> *mut u8; }), + api!(memcmp, extern { fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32; }), /* libm */ // commented out functions are not available with the libm used here, but are available in NAR3. diff --git a/artiq/firmware/libboard_artiq/drtio_routing.rs b/artiq/firmware/libboard_artiq/drtio_routing.rs index 10ce489b1..68836386f 100644 --- a/artiq/firmware/libboard_artiq/drtio_routing.rs +++ b/artiq/firmware/libboard_artiq/drtio_routing.rs @@ -64,12 +64,14 @@ pub fn config_routing_table(default_n_links: usize) -> RoutingTable { } } return true; + } else { + warn!("length of the configured routing table is incorrect"); } } false }); if !ok { - warn!("could not read routing table from configuration, using default"); + info!("could not read routing table from configuration, using default"); } info!("routing table: {}", ret); ret diff --git a/artiq/firmware/libproto_artiq/drtioaux_proto.rs b/artiq/firmware/libproto_artiq/drtioaux_proto.rs index 36e2cb45b..dbfe4a5ad 100644 --- a/artiq/firmware/libproto_artiq/drtioaux_proto.rs +++ b/artiq/firmware/libproto_artiq/drtioaux_proto.rs @@ -34,7 +34,7 @@ pub enum Packet { RoutingAck, MonitorRequest { destination: u8, channel: u16, probe: u8 }, - MonitorReply { value: u32 }, + MonitorReply { value: u64 }, InjectionRequest { destination: u8, channel: u16, overrd: u8, value: u8 }, InjectionStatusRequest { destination: u8, channel: u16, overrd: u8 }, InjectionStatusReply { value: u8 }, @@ -105,7 +105,7 @@ impl Packet { probe: reader.read_u8()? }, 0x41 => Packet::MonitorReply { - value: reader.read_u32()? + value: reader.read_u64()? }, 0x50 => Packet::InjectionRequest { destination: reader.read_u8()?, @@ -259,7 +259,7 @@ impl Packet { }, Packet::MonitorReply { value } => { writer.write_u8(0x41)?; - writer.write_u32(value)?; + writer.write_u64(value)?; }, Packet::InjectionRequest { destination, channel, overrd, value } => { writer.write_u8(0x50)?; diff --git a/artiq/firmware/libproto_artiq/moninj_proto.rs b/artiq/firmware/libproto_artiq/moninj_proto.rs index dba2f84bc..c5b76f2bd 100644 --- a/artiq/firmware/libproto_artiq/moninj_proto.rs +++ b/artiq/firmware/libproto_artiq/moninj_proto.rs @@ -40,7 +40,7 @@ pub enum HostMessage { #[derive(Debug)] pub enum DeviceMessage { - MonitorStatus { channel: u32, probe: u8, value: u32 }, + MonitorStatus { channel: u32, probe: u8, value: u64 }, InjectionStatus { channel: u32, overrd: u8, value: u8 } } @@ -82,7 +82,7 @@ impl DeviceMessage { writer.write_u8(0)?; writer.write_u32(channel)?; writer.write_u8(probe)?; - writer.write_u32(value)?; + writer.write_u64(value)?; }, DeviceMessage::InjectionStatus { channel, overrd, value } => { writer.write_u8(1)?; diff --git a/artiq/firmware/runtime/moninj.rs b/artiq/firmware/runtime/moninj.rs index c1bba04fc..6feb7ec55 100644 --- a/artiq/firmware/runtime/moninj.rs +++ b/artiq/firmware/runtime/moninj.rs @@ -2,7 +2,6 @@ use alloc::collections::btree_map::BTreeMap; use core::cell::RefCell; use io::Error as IoError; -use io::Write; use moninj_proto::*; use sched::{Io, Mutex, TcpListener, TcpStream, Error as SchedError}; use urc::Urc; @@ -13,12 +12,12 @@ use board_artiq::drtio_routing; mod local_moninj { use board_misoc::csr; - pub fn read_probe(channel: u16, probe: u8) -> u32 { + pub fn read_probe(channel: u16, probe: u8) -> u64 { unsafe { csr::rtio_moninj::mon_chan_sel_write(channel as _); csr::rtio_moninj::mon_probe_sel_write(probe); csr::rtio_moninj::mon_value_update_write(1); - csr::rtio_moninj::mon_value_read() as u32 + csr::rtio_moninj::mon_value_read() as u64 } } @@ -41,7 +40,7 @@ mod local_moninj { #[cfg(not(has_rtio_moninj))] mod local_moninj { - pub fn read_probe(_channel: u16, _probe: u8) -> u32 { 0 } + pub fn read_probe(_channel: u16, _probe: u8) -> u64 { 0 } pub fn inject(_channel: u16, _overrd: u8, _value: u8) { } @@ -54,7 +53,7 @@ mod remote_moninj { use rtio_mgt::drtio; use sched::{Io, Mutex}; - pub fn read_probe(io: &Io, aux_mutex: &Mutex, linkno: u8, destination: u8, channel: u16, probe: u8) -> u32 { + pub fn read_probe(io: &Io, aux_mutex: &Mutex, linkno: u8, destination: u8, channel: u16, probe: u8) -> u64 { let reply = drtio::aux_transact(io, aux_mutex, linkno, &drtioaux::Packet::MonitorRequest { destination: destination, channel: channel, @@ -123,7 +122,6 @@ fn connection_worker(io: &Io, _aux_mutex: &Mutex, _routing_table: &drtio_routing let mut next_check = 0; read_magic(&mut stream)?; - stream.write_all("e".as_bytes())?; info!("new connection from {}", stream.remote_endpoint()); loop { diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index e4a81eef9..e869cdc82 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -201,13 +201,13 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater], csr::rtio_moninj::mon_chan_sel_write(channel as _); csr::rtio_moninj::mon_probe_sel_write(probe); csr::rtio_moninj::mon_value_update_write(1); - value = csr::rtio_moninj::mon_value_read(); + value = csr::rtio_moninj::mon_value_read() as u64; } #[cfg(not(has_rtio_moninj))] { value = 0; } - let reply = drtioaux::Packet::MonitorReply { value: value as u32 }; + let reply = drtioaux::Packet::MonitorReply { value: value }; drtioaux::send(0, &reply) }, drtioaux::Packet::InjectionRequest { destination: _destination, channel, overrd, value } => { diff --git a/artiq/frontend/aqctl_moninj_proxy.py b/artiq/frontend/aqctl_moninj_proxy.py new file mode 100755 index 000000000..0ce317fba --- /dev/null +++ b/artiq/frontend/aqctl_moninj_proxy.py @@ -0,0 +1,224 @@ +#!/usr/bin/env python3 + +import argparse +import logging +import asyncio +import struct +from enum import Enum + +from sipyco.asyncio_tools import AsyncioServer +from sipyco.pc_rpc import Server +from sipyco import common_args + +from artiq.coredevice.comm_moninj import CommMonInj + + +logger = logging.getLogger(__name__) + + +class EventType(Enum): + PROBE = 0 + INJECTION = 1 + + +class MonitorMux: + def __init__(self): + self.listeners = dict() + self.comm_moninj = None + + def _monitor(self, listener, event): + try: + listeners = self.listeners[event] + except KeyError: + listeners = [] + self.listeners[event] = listeners + if event[0] == EventType.PROBE: + logger.debug("starting monitoring channel %d probe %d", event[1], event[2]) + self.comm_moninj.monitor_probe(True, event[1], event[2]) + elif event[0] == EventType.INJECTION: + logger.debug("starting monitoring channel %d injection %d", event[1], event[2]) + self.comm_moninj.monitor_injection(True, event[1], event[2]) + else: + raise ValueError + if listener in listeners: + logger.warning("listener trying to subscribe twice to %s", event) + else: + listeners.append(listener) + + def _unmonitor(self, listener, event): + try: + listeners = self.listeners[event] + except KeyError: + listeners = [] + try: + listeners.remove(listener) + except ValueError: + logger.warning("listener trying to unsubscribe from %s, but was not subscribed", event) + return + if not listeners: + del self.listeners[event] + if event[0] == EventType.PROBE: + logger.debug("stopped monitoring channel %d probe %d", event[1], event[2]) + self.comm_moninj.monitor_probe(False, event[1], event[2]) + elif event[0] == EventType.INJECTION: + logger.debug("stopped monitoring channel %d injection %d", event[1], event[2]) + self.comm_moninj.monitor_injection(False, event[1], event[2]) + else: + raise ValueError + + def monitor_probe(self, listener, enable, channel, probe): + if enable: + self._monitor(listener, (EventType.PROBE, channel, probe)) + else: + self._unmonitor(listener, (EventType.PROBE, channel, probe)) + + def monitor_injection(self, listener, enable, channel, overrd): + if enable: + self._monitor(listener, (EventType.INJECTION, channel, overrd)) + else: + self._unmonitor(listener, (EventType.INJECTION, channel, overrd)) + + def _event_cb(self, event, value): + try: + listeners = self.listeners[event] + except KeyError: + # We may still receive buffered events shortly after an unsubscription. They can be ignored. + logger.debug("received event %s but no listener", event) + listeners = [] + for listener in listeners: + if event[0] == EventType.PROBE: + listener.monitor_cb(event[1], event[2], value) + elif event[0] == EventType.INJECTION: + listener.injection_status_cb(event[1], event[2], value) + else: + raise ValueError + + def monitor_cb(self, channel, probe, value): + self._event_cb((EventType.PROBE, channel, probe), value) + + def injection_status_cb(self, channel, override, value): + self._event_cb((EventType.INJECTION, channel, override), value) + + def remove_listener(self, listener): + for event, listeners in list(self.listeners.items()): + try: + listeners.remove(listener) + except ValueError: + pass + if not listeners: + del self.listeners[event] + if event[0] == EventType.PROBE: + logger.debug("stopped monitoring channel %d probe %d", event[1], event[2]) + self.comm_moninj.monitor_probe(False, event[1], event[2]) + elif event[0] == EventType.INJECTION: + logger.debug("stopped monitoring channel %d injection %d", event[1], event[2]) + self.comm_moninj.monitor_injection(False, event[1], event[2]) + else: + raise ValueError + + +class ProxyConnection: + def __init__(self, monitor_mux, reader, writer): + self.monitor_mux = monitor_mux + self.reader = reader + self.writer = writer + + async def handle(self): + try: + while True: + ty = await self.reader.read(1) + if not ty: + return + if ty == b"\x00": # MonitorProbe + packet = await self.reader.readexactly(6) + enable, channel, probe = struct.unpack("")) if expid["class_name"] is None: row.append("") else: diff --git a/artiq/frontend/artiq_ddb_template.py b/artiq/frontend/artiq_ddb_template.py index b17b1d661..592834e7f 100755 --- a/artiq/frontend/artiq_ddb_template.py +++ b/artiq/frontend/artiq_ddb_template.py @@ -38,6 +38,13 @@ def process_header(output, description): "port": 1068, "command": "aqctl_corelog -p {{port}} --bind {{bind}} " + core_addr }}, + "core_moninj": {{ + "type": "controller", + "host": "::1", + "port_proxy": 1383, + "port": 1384, + "command": "aqctl_moninj_proxy --port-proxy {{port_proxy}} --port-control {{port}} --bind {{bind}} " + core_addr + }}, "core_cache": {{ "type": "local", "module": "artiq.coredevice.cache", diff --git a/artiq/master/worker.py b/artiq/master/worker.py index 36d5a202f..1267626ca 100644 --- a/artiq/master/worker.py +++ b/artiq/master/worker.py @@ -74,7 +74,7 @@ class Worker: return None def _get_log_source(self): - return "worker({},{})".format(self.rid, self.filename) + return "worker({},{})".format(self.rid, self.filename if self.filename is not None else "") async def _create_process(self, log_level): if self.ipc is not None: @@ -260,7 +260,8 @@ class Worker: async def build(self, rid, pipeline_name, wd, expid, priority, timeout=15.0): self.rid = rid - self.filename = os.path.basename(expid["file"]) + if "file" in expid: + self.filename = os.path.basename(expid["file"]) await self._create_process(expid["log_level"]) await self._worker_action( {"action": "build", diff --git a/artiq/master/worker_impl.py b/artiq/master/worker_impl.py index 50896a946..84c29a6d4 100644 --- a/artiq/master/worker_impl.py +++ b/artiq/master/worker_impl.py @@ -13,6 +13,8 @@ import inspect import logging import traceback from collections import OrderedDict +import importlib.util +import linecache import h5py @@ -129,11 +131,39 @@ class CCB: issue = staticmethod(make_parent_action("ccb_issue")) -def get_experiment(file, class_name): +def get_experiment_from_file(file, class_name): module = tools.file_import(file, prefix="artiq_worker_") return tools.get_experiment(module, class_name) +class StringLoader: + def __init__(self, fake_filename, content): + self.fake_filename = fake_filename + self.content = content + + def get_source(self, fullname): + return self.content + + def create_module(self, spec): + return None + + def exec_module(self, module): + code = compile(self.get_source(self.fake_filename), self.fake_filename, "exec") + exec(code, module.__dict__) + + +def get_experiment_from_content(content, class_name): + fake_filename = "expcontent" + spec = importlib.util.spec_from_loader( + "expmodule", + StringLoader(fake_filename, content) + ) + module = importlib.util.module_from_spec(spec) + spec.loader.exec_module(module) + linecache.lazycache(fake_filename, module.__dict__) + return tools.get_experiment(module, class_name) + + register_experiment = make_parent_action("register_experiment") @@ -246,14 +276,17 @@ def main(): start_time = time.time() rid = obj["rid"] expid = obj["expid"] - if obj["wd"] is not None: - # Using repository - experiment_file = os.path.join(obj["wd"], expid["file"]) - repository_path = obj["wd"] + if "file" in expid: + if obj["wd"] is not None: + # Using repository + experiment_file = os.path.join(obj["wd"], expid["file"]) + repository_path = obj["wd"] + else: + experiment_file = expid["file"] + repository_path = None + exp = get_experiment_from_file(experiment_file, expid["class_name"]) else: - experiment_file = expid["file"] - repository_path = None - exp = get_experiment(experiment_file, expid["class_name"]) + exp = get_experiment_from_content(expid["content"], expid["class_name"]) device_mgr.virtual_devices["scheduler"].set_run_info( rid, obj["pipeline_name"], expid, obj["priority"]) start_local_time = time.localtime(start_time) diff --git a/artiq/test/test_frontends.py b/artiq/test/test_frontends.py index a52d4a17c..622c7a010 100644 --- a/artiq/test/test_frontends.py +++ b/artiq/test/test_frontends.py @@ -9,7 +9,7 @@ class TestFrontends(unittest.TestCase): """Test --help as a simple smoke test against catastrophic breakage.""" commands = { "aqctl": [ - "corelog" + "corelog", "moninj_proxy" ], "artiq": [ "client", "compile", "coreanalyzer", "coremgmt", diff --git a/doc/manual/default_network_ports.rst b/doc/manual/default_network_ports.rst index 7f08af003..6ed9b4fbf 100644 --- a/doc/manual/default_network_ports.rst +++ b/doc/manual/default_network_ports.rst @@ -10,7 +10,9 @@ Default network ports +---------------------------------+--------------+ | Core device (analyzer) | 1382 | +---------------------------------+--------------+ -| Core device (mon/inj) | 1383 | +| Moninj (core device or proxy) | 1383 | ++---------------------------------+--------------+ +| Moninj (proxy control) | 1384 | +---------------------------------+--------------+ | Master (logging input) | 1066 | +---------------------------------+--------------+ diff --git a/doc/manual/utilities.rst b/doc/manual/utilities.rst index 843f03311..11745dc34 100644 --- a/doc/manual/utilities.rst +++ b/doc/manual/utilities.rst @@ -109,6 +109,14 @@ Core device logging controller :ref: artiq.frontend.aqctl_corelog.get_argparser :prog: aqctl_corelog +Moninj proxy +------------ + +.. argparse:: + :ref: artiq.frontend.aqctl_moninj_proxy.get_argparser + :prog: aqctl_moninj_proxy + + .. _core-device-rtio-analyzer-tool: Core device RTIO analyzer tool diff --git a/flake.nix b/flake.nix index 10d25b15e..134a96551 100644 --- a/flake.nix +++ b/flake.nix @@ -168,7 +168,7 @@ vivado = pkgs.buildFHSUserEnv { name = "vivado"; targetPkgs = vivadoDeps; - profile = "source /opt/Xilinx/Vivado/2021.1/settings64.sh"; + profile = "set -e; source /opt/Xilinx/Vivado/2021.2/settings64.sh"; runScript = "vivado"; }; diff --git a/setup.py b/setup.py index 18fa12710..60304d724 100755 --- a/setup.py +++ b/setup.py @@ -35,6 +35,7 @@ console_scripts = [ "artiq_run = artiq.frontend.artiq_run:main", "artiq_flash = artiq.frontend.artiq_flash:main", "aqctl_corelog = artiq.frontend.aqctl_corelog:main", + "aqctl_moninj_proxy = artiq.frontend.aqctl_moninj_proxy:main", "afws_client = artiq.frontend.afws_client:main", ]