From a4895b591a23661af9226609d25b17105490b96a Mon Sep 17 00:00:00 2001 From: mwojcik Date: Mon, 29 May 2023 13:07:06 +0800 Subject: [PATCH 01/68] analyzer: fix satellite behavior --- artiq/firmware/runtime/analyzer.rs | 3 ++- artiq/firmware/satman/analyzer.rs | 39 ++++++++++++++++++------------ 2 files changed, 25 insertions(+), 17 deletions(-) diff --git a/artiq/firmware/runtime/analyzer.rs b/artiq/firmware/runtime/analyzer.rs index 4b5bd222d..e7c555d76 100644 --- a/artiq/firmware/runtime/analyzer.rs +++ b/artiq/firmware/runtime/analyzer.rs @@ -1,4 +1,6 @@ use io::{Write, Error as IoError}; +#[cfg(has_drtio)] +use alloc::vec::Vec; use board_misoc::{csr, cache}; use sched::{Io, Mutex, TcpListener, TcpStream, Error as SchedError}; use analyzer_proto::*; @@ -42,7 +44,6 @@ fn disarm() { pub mod remote_analyzer { use super::*; use rtio_mgt::drtio; - use alloc::vec::Vec; pub struct RemoteBuffer { pub total_byte_count: u64, diff --git a/artiq/firmware/satman/analyzer.rs b/artiq/firmware/satman/analyzer.rs index 8ad021c2f..e2a43ba22 100644 --- a/artiq/firmware/satman/analyzer.rs +++ b/artiq/firmware/satman/analyzer.rs @@ -1,3 +1,4 @@ +use core::cmp::min; use board_misoc::{csr, cache}; use proto_artiq::drtioaux_proto::ANALYZER_MAX_SIZE; @@ -35,8 +36,9 @@ fn disarm() { pub struct Analyzer { // necessary for keeping track of sent data + data_len: usize, sent_bytes: usize, - data_iter: usize + data_pointer: usize } pub struct Header { @@ -50,48 +52,53 @@ pub struct AnalyzerSliceMeta { pub last: bool } +impl Drop for Analyzer { + fn drop(&mut self) { + disarm(); + } +} + impl Analyzer { pub fn new() -> Analyzer { // create and arm new Analyzer arm(); Analyzer { + data_len: 0, sent_bytes: 0, - data_iter: 0 + data_pointer: 0 } } - fn drop(&mut self) { - disarm(); - } - pub fn get_header(&mut self) -> Header { disarm(); let overflow = unsafe { csr::rtio_analyzer::message_encoder_overflow_read() != 0 }; let total_byte_count = unsafe { csr::rtio_analyzer::dma_byte_count_read() }; let wraparound = total_byte_count >= BUFFER_SIZE as u64; - self.sent_bytes = if wraparound { BUFFER_SIZE } else { total_byte_count as usize }; - self.data_iter = if wraparound { (total_byte_count % BUFFER_SIZE as u64) as usize } else { 0 }; - + self.data_len = if wraparound { BUFFER_SIZE } else { total_byte_count as usize }; + self.data_pointer = if wraparound { (total_byte_count % BUFFER_SIZE as u64) as usize } else { 0 }; + self.sent_bytes = 0; + Header { total_byte_count: total_byte_count, - sent_bytes: self.sent_bytes as u32, + sent_bytes: self.data_len as u32, overflow: overflow } } pub fn get_data(&mut self, data_slice: &mut [u8; ANALYZER_MAX_SIZE]) -> AnalyzerSliceMeta { let data = unsafe { &BUFFER.data[..] }; - let i = self.data_iter; - let len = if i + ANALYZER_MAX_SIZE < self.sent_bytes { ANALYZER_MAX_SIZE } else { self.sent_bytes - i }; - let last = i + len == self.sent_bytes; + let i = (self.data_pointer + self.sent_bytes) % BUFFER_SIZE; + let len = min(ANALYZER_MAX_SIZE, self.data_len - self.sent_bytes); + let last = self.sent_bytes + len == self.data_len; + if i + len >= BUFFER_SIZE { - data_slice[..len].clone_from_slice(&data[i..BUFFER_SIZE]); - data_slice[..len].clone_from_slice(&data[..(i+len) % BUFFER_SIZE]); + data_slice[..(BUFFER_SIZE-i)].clone_from_slice(&data[i..BUFFER_SIZE]); + data_slice[(BUFFER_SIZE-i)..len].clone_from_slice(&data[..(i + len) % BUFFER_SIZE]); } else { data_slice[..len].clone_from_slice(&data[i..i+len]); } - self.data_iter += len; + self.sent_bytes += len; if last { arm(); From 22e2514ce67b785dc2b61b2b70bf61941a46ce5d Mon Sep 17 00:00:00 2001 From: den512 Date: Tue, 30 May 2023 11:13:13 +0800 Subject: [PATCH 02/68] update configuration of IBUFDS_GTE2 Input clock is terminated internally with 50 Ohm on each leg and to 4/5 MGTAVCC. --- artiq/gateware/drtio/transceiver/gtx_7series.py | 6 +++--- artiq/gateware/targets/kasli.py | 15 ++++++++++++--- artiq/gateware/targets/kc705.py | 6 +++--- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/artiq/gateware/drtio/transceiver/gtx_7series.py b/artiq/gateware/drtio/transceiver/gtx_7series.py index fe901d90c..a1872e8ae 100644 --- a/artiq/gateware/drtio/transceiver/gtx_7series.py +++ b/artiq/gateware/drtio/transceiver/gtx_7series.py @@ -288,9 +288,9 @@ class GTX(Module, TransceiverInterface): i_I=clock_pads.p, i_IB=clock_pads.n, o_O=refclk, - p_CLKCM_CFG="0b1", - p_CLKRCV_TRST="0b1", - p_CLKSWING_CFG="0b11" + p_CLKCM_CFG="TRUE", + p_CLKRCV_TRST="TRUE", + p_CLKSWING_CFG=3 ) channel_interfaces = [] diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index c09615e9c..d292d37d9 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -87,7 +87,10 @@ class StandaloneBase(MiniSoC, AMPSoC): Instance("IBUFDS_GTE2", i_CEB=0, i_I=cdr_clk_out.p, i_IB=cdr_clk_out.n, - o_O=cdr_clk), + o_O=cdr_clk, + p_CLKCM_CFG="TRUE", + p_CLKRCV_TRST="TRUE", + p_CLKSWING_CFG=3), Instance("BUFG", i_I=cdr_clk, o_O=cdr_clk_buf) ] @@ -378,7 +381,10 @@ class MasterBase(MiniSoC, AMPSoC): self.specials += Instance("IBUFDS_GTE2", i_CEB=0, i_I=cdr_clk_out.p, i_IB=cdr_clk_out.n, - o_O=cdr_clk) + o_O=cdr_clk, + p_CLKCM_CFG="TRUE", + p_CLKRCV_TRST="TRUE", + p_CLKSWING_CFG=3) # Note precisely the rules Xilinx made up: # refclksel=0b001 GTREFCLK0 selected # refclksel=0b010 GTREFCLK1 selected @@ -440,7 +446,10 @@ class SatelliteBase(BaseSoC): self.specials += Instance("IBUFDS_GTE2", i_CEB=0, i_I=cdr_clk_out.p, i_IB=cdr_clk_out.n, - o_O=cdr_clk) + o_O=cdr_clk, + p_CLKCM_CFG="TRUE", + p_CLKRCV_TRST="TRUE", + p_CLKSWING_CFG=3) qpll_drtio_settings = QPLLSettings( refclksel=0b001, fbdiv=4, diff --git a/artiq/gateware/targets/kc705.py b/artiq/gateware/targets/kc705.py index ed2e70ac4..251b56661 100755 --- a/artiq/gateware/targets/kc705.py +++ b/artiq/gateware/targets/kc705.py @@ -119,9 +119,9 @@ class _StandaloneBase(MiniSoC, AMPSoC): i_CEB=0, i_I=cdr_clk_out.p, i_IB=cdr_clk_out.n, o_O=cdr_clk, - p_CLKCM_CFG=1, - p_CLKRCV_TRST=1, - p_CLKSWING_CFG="2'b11"), + p_CLKCM_CFG="TRUE", + p_CLKRCV_TRST="TRUE", + p_CLKSWING_CFG=3), Instance("BUFG", i_I=cdr_clk, o_O=cdr_clk_buf) ] From 0941d3a29a61d250ff02ddfafefd2c9e8c9350e3 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 30 May 2023 11:50:30 +0800 Subject: [PATCH 03/68] flake: update dependencies --- flake.lock | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/flake.lock b/flake.lock index ce6453721..1467860ca 100644 --- a/flake.lock +++ b/flake.lock @@ -57,11 +57,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1685004253, - "narHash": "sha256-AbVL1nN/TDicUQ5wXZ8xdLERxz/eJr7+o8lqkIOVuaE=", + "lastModified": 1685356226, + "narHash": "sha256-f2clSOdqi0SvY1WSgbnl2YgCZmoCXOxeUjYeXp8p2zI=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "3e01645c40b92d29f3ae76344a6d654986a91a91", + "rev": "0f7f5ca1cdec8dea85bb4fa60378258171d019ad", "type": "github" }, "original": { @@ -121,11 +121,11 @@ "src-misoc": { "flake": false, "locked": { - "lastModified": 1685174995, - "narHash": "sha256-90UwWt9/TAaFAoYDpiIzHXqMWYfftlps8sodv/Gf07c=", + "lastModified": 1685415268, + "narHash": "sha256-g4+yeSV+HtWjcllM5wk4vNBUVCXtDOzUSKhxXPT7Fyc=", "ref": "refs/heads/master", - "rev": "d83499b318e8ef021b12e2df261707a165eb3afa", - "revCount": 2439, + "rev": "6d48ce77b6746d3226a682790fbc95b90340986e", + "revCount": 2440, "submodules": true, "type": "git", "url": "https://github.com/m-labs/misoc.git" From 444bab21863b85c282663c927f9ed9dd4b6d589c Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 30 May 2023 15:44:30 +0800 Subject: [PATCH 04/68] gui: datasets_sub -> dataset_sub (nfc) --- artiq/browser/datasets.py | 4 ++-- artiq/browser/experiments.py | 12 ++++++------ artiq/dashboard/datasets.py | 4 ++-- artiq/frontend/artiq_browser.py | 16 ++++++++-------- artiq/gui/applets.py | 26 +++++++++++++------------- 5 files changed, 31 insertions(+), 31 deletions(-) diff --git a/artiq/browser/datasets.py b/artiq/browser/datasets.py index b66b18216..78bf6e8f7 100644 --- a/artiq/browser/datasets.py +++ b/artiq/browser/datasets.py @@ -24,7 +24,7 @@ class Model(DictSyncTreeSepModel): class DatasetsDock(QtWidgets.QDockWidget): - def __init__(self, datasets_sub, master_host, master_port): + def __init__(self, dataset_sub, master_host, master_port): QtWidgets.QDockWidget.__init__(self, "Datasets") self.setObjectName("Datasets") self.setFeatures(QtWidgets.QDockWidget.DockWidgetMovable | @@ -62,7 +62,7 @@ class DatasetsDock(QtWidgets.QDockWidget): self.table.addAction(upload_action) self.set_model(Model(dict())) - datasets_sub.add_setmodel_callback(self.set_model) + dataset_sub.add_setmodel_callback(self.set_model) self.master_host = master_host self.master_port = master_port diff --git a/artiq/browser/experiments.py b/artiq/browser/experiments.py index a67b93736..23a271eb9 100644 --- a/artiq/browser/experiments.py +++ b/artiq/browser/experiments.py @@ -378,9 +378,9 @@ class _ExperimentDock(QtWidgets.QMdiSubWindow): class LocalDatasetDB: - def __init__(self, datasets_sub): - self.datasets_sub = datasets_sub - datasets_sub.add_setmodel_callback(self.init) + def __init__(self, dataset_sub): + self.dataset_sub = dataset_sub + dataset_sub.add_setmodel_callback(self.init) def init(self, data): self._data = data @@ -389,11 +389,11 @@ class LocalDatasetDB: return self._data.backing_store[key][1] def update(self, mod): - self.datasets_sub.update(mod) + self.dataset_sub.update(mod) class ExperimentsArea(QtWidgets.QMdiArea): - def __init__(self, root, datasets_sub): + def __init__(self, root, dataset_sub): QtWidgets.QMdiArea.__init__(self) self.pixmap = QtGui.QPixmap(os.path.join( artiq_dir, "gui", "logo_ver.svg")) @@ -402,7 +402,7 @@ class ExperimentsArea(QtWidgets.QMdiArea): self.open_experiments = [] - self._ddb = LocalDatasetDB(datasets_sub) + self._ddb = LocalDatasetDB(dataset_sub) self.worker_handlers = { "get_device_db": lambda: {}, diff --git a/artiq/dashboard/datasets.py b/artiq/dashboard/datasets.py index 1052e03d1..f512c3d74 100644 --- a/artiq/dashboard/datasets.py +++ b/artiq/dashboard/datasets.py @@ -106,7 +106,7 @@ class Model(DictSyncTreeSepModel): class DatasetsDock(QtWidgets.QDockWidget): - def __init__(self, datasets_sub, dataset_ctl): + def __init__(self, dataset_sub, dataset_ctl): QtWidgets.QDockWidget.__init__(self, "Datasets") self.setObjectName("Datasets") self.setFeatures(QtWidgets.QDockWidget.DockWidgetMovable | @@ -146,7 +146,7 @@ class DatasetsDock(QtWidgets.QDockWidget): self.table.addAction(delete_action) self.table_model = Model(dict()) - datasets_sub.add_setmodel_callback(self.set_model) + dataset_sub.add_setmodel_callback(self.set_model) def _search_datasets(self): if hasattr(self, "table_model_filter"): diff --git a/artiq/frontend/artiq_browser.py b/artiq/frontend/artiq_browser.py index 398244b0e..af469c05a 100755 --- a/artiq/frontend/artiq_browser.py +++ b/artiq/frontend/artiq_browser.py @@ -48,7 +48,7 @@ def get_argparser(): class Browser(QtWidgets.QMainWindow): - def __init__(self, smgr, datasets_sub, browse_root, + def __init__(self, smgr, dataset_sub, browse_root, master_host, master_port, *, loop=None): QtWidgets.QMainWindow.__init__(self) smgr.register(self) @@ -65,7 +65,7 @@ class Browser(QtWidgets.QMainWindow): self.setUnifiedTitleAndToolBarOnMac(True) self.experiments = experiments.ExperimentsArea( - browse_root, datasets_sub) + browse_root, dataset_sub) smgr.register(self.experiments) self.experiments.setHorizontalScrollBarPolicy( QtCore.Qt.ScrollBarAsNeeded) @@ -73,7 +73,7 @@ class Browser(QtWidgets.QMainWindow): QtCore.Qt.ScrollBarAsNeeded) self.setCentralWidget(self.experiments) - self.files = files.FilesDock(datasets_sub, browse_root) + self.files = files.FilesDock(dataset_sub, browse_root) smgr.register(self.files) self.files.dataset_activated.connect( @@ -81,12 +81,12 @@ class Browser(QtWidgets.QMainWindow): self.files.dataset_changed.connect( self.experiments.dataset_changed) - self.applets = applets.AppletsDock(self, datasets_sub, loop=loop) + self.applets = applets.AppletsDock(self, dataset_sub, loop=loop) smgr.register(self.applets) atexit_register_coroutine(self.applets.stop, loop=loop) self.datasets = datasets.DatasetsDock( - datasets_sub, master_host, master_port) + dataset_sub, master_host, master_port) smgr.register(self.datasets) self.files.metadata_changed.connect(self.datasets.metadata_changed) @@ -146,12 +146,12 @@ def main(): asyncio.set_event_loop(loop) atexit.register(loop.close) - datasets_sub = models.LocalModelManager(datasets.Model) - datasets_sub.init({}) + dataset_sub = models.LocalModelManager(datasets.Model) + dataset_sub.init({}) smgr = state.StateManager(args.db_file) - browser = Browser(smgr, datasets_sub, args.browse_root, + browser = Browser(smgr, dataset_sub, args.browse_root, args.server, args.port, loop=loop) widget_log_handler.callback = browser.log.model.append diff --git a/artiq/gui/applets.py b/artiq/gui/applets.py index 275e61ba7..0e65a2ee3 100644 --- a/artiq/gui/applets.py +++ b/artiq/gui/applets.py @@ -21,9 +21,9 @@ logger = logging.getLogger(__name__) class AppletIPCServer(AsyncioParentComm): - def __init__(self, datasets_sub): + def __init__(self, dataset_sub): AsyncioParentComm.__init__(self) - self.datasets_sub = datasets_sub + self.dataset_sub = dataset_sub self.datasets = set() self.dataset_prefixes = [] @@ -60,7 +60,7 @@ class AppletIPCServer(AsyncioParentComm): self.write_pyon({"action": "mod", "mod": mod}) async def serve(self, embed_cb, fix_initial_size_cb): - self.datasets_sub.notify_cbs.append(self._on_mod) + self.dataset_sub.notify_cbs.append(self._on_mod) try: while True: obj = await self.read_pyon() @@ -74,9 +74,9 @@ class AppletIPCServer(AsyncioParentComm): elif action == "subscribe": self.datasets = obj["datasets"] self.dataset_prefixes = obj["dataset_prefixes"] - if self.datasets_sub.model is not None: + if self.dataset_sub.model is not None: mod = self._synthesize_init( - self.datasets_sub.model.backing_store) + self.dataset_sub.model.backing_store) self.write_pyon({"action": "mod", "mod": mod}) else: raise ValueError("unknown action in applet message") @@ -90,7 +90,7 @@ class AppletIPCServer(AsyncioParentComm): logger.error("error processing data from applet, " "server stopped", exc_info=True) finally: - self.datasets_sub.notify_cbs.remove(self._on_mod) + self.dataset_sub.notify_cbs.remove(self._on_mod) def start_server(self, embed_cb, fix_initial_size_cb, *, loop=None): self.server_task = asyncio.ensure_future( @@ -103,7 +103,7 @@ class AppletIPCServer(AsyncioParentComm): class _AppletDock(QDockWidgetCloseDetect): - def __init__(self, datasets_sub, uid, name, spec, extra_substitutes): + def __init__(self, dataset_sub, uid, name, spec, extra_substitutes): QDockWidgetCloseDetect.__init__(self, "Applet: " + name) self.setObjectName("applet" + str(uid)) @@ -111,7 +111,7 @@ class _AppletDock(QDockWidgetCloseDetect): self.setMinimumSize(20*qfm.averageCharWidth(), 5*qfm.lineSpacing()) self.resize(40*qfm.averageCharWidth(), 10*qfm.lineSpacing()) - self.datasets_sub = datasets_sub + self.dataset_sub = dataset_sub self.applet_name = name self.spec = spec self.extra_substitutes = extra_substitutes @@ -130,7 +130,7 @@ class _AppletDock(QDockWidgetCloseDetect): return self.starting_stopping = True try: - self.ipc = AppletIPCServer(self.datasets_sub) + self.ipc = AppletIPCServer(self.dataset_sub) env = os.environ.copy() env["PYTHONUNBUFFERED"] = "1" env["ARTIQ_APPLET_EMBED"] = self.ipc.get_address() @@ -327,7 +327,7 @@ class _CompleterDelegate(QtWidgets.QStyledItemDelegate): class AppletsDock(QtWidgets.QDockWidget): - def __init__(self, main_window, datasets_sub, extra_substitutes={}, *, loop=None): + def __init__(self, main_window, dataset_sub, extra_substitutes={}, *, loop=None): """ :param extra_substitutes: Map of extra ``${strings}`` to substitute in applet commands to their respective values. @@ -338,7 +338,7 @@ class AppletsDock(QtWidgets.QDockWidget): QtWidgets.QDockWidget.DockWidgetFloatable) self.main_window = main_window - self.datasets_sub = datasets_sub + self.dataset_sub = dataset_sub self.extra_substitutes = extra_substitutes self.applet_uids = set() @@ -364,7 +364,7 @@ class AppletsDock(QtWidgets.QDockWidget): completer_delegate = _CompleterDelegate() self.table.setItemDelegateForColumn(1, completer_delegate) - datasets_sub.add_setmodel_callback(completer_delegate.set_model) + dataset_sub.add_setmodel_callback(completer_delegate.set_model) self.table.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu) new_action = QtWidgets.QAction("New applet", self.table) @@ -440,7 +440,7 @@ class AppletsDock(QtWidgets.QDockWidget): self.table.itemChanged.connect(self.item_changed) def create(self, item, name, spec): - dock = _AppletDock(self.datasets_sub, item.applet_uid, name, spec, self.extra_substitutes) + dock = _AppletDock(self.dataset_sub, item.applet_uid, name, spec, self.extra_substitutes) self.main_window.addDockWidget(QtCore.Qt.RightDockWidgetArea, dock) dock.setFloating(True) asyncio.ensure_future(dock.start(), loop=self._loop) From 953a8a9555d9631991dd7538b75ba095daf31580 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 30 May 2023 15:55:19 +0800 Subject: [PATCH 05/68] master: merge master_config and master_terminate --- artiq/frontend/artiq_client.py | 2 +- artiq/frontend/artiq_dashboard.py | 6 +++--- artiq/frontend/artiq_master.py | 18 +++++------------- 3 files changed, 9 insertions(+), 17 deletions(-) diff --git a/artiq/frontend/artiq_client.py b/artiq/frontend/artiq_client.py index 03eca3887..bdd751e43 100755 --- a/artiq/frontend/artiq_client.py +++ b/artiq/frontend/artiq_client.py @@ -327,7 +327,7 @@ def main(): "scan_devices": "master_device_db", "scan_repository": "master_experiment_db", "ls": "master_experiment_db", - "terminate": "master_terminate", + "terminate": "master_management", }[action] remote = Client(args.server, port, target_name) try: diff --git a/artiq/frontend/artiq_dashboard.py b/artiq/frontend/artiq_dashboard.py index 033d58ee7..bb88f39c7 100755 --- a/artiq/frontend/artiq_dashboard.py +++ b/artiq/frontend/artiq_dashboard.py @@ -125,11 +125,11 @@ def main(): atexit.register(client.close_rpc) rpc_clients[target] = client - config = Client(args.server, args.port_control, "master_config") + master_management = Client(args.server, args.port_control, "master_management") try: - server_name = config.get_name() + server_name = master_management.get_name() finally: - config.close_rpc() + master_management.close_rpc() disconnect_reported = False def report_disconnect(): diff --git a/artiq/frontend/artiq_master.py b/artiq/frontend/artiq_master.py index b5f725b47..f61d6cf52 100755 --- a/artiq/frontend/artiq_master.py +++ b/artiq/frontend/artiq_master.py @@ -65,14 +65,6 @@ def get_argparser(): return parser -class MasterConfig: - def __init__(self, name): - self.name = name - - def get_name(self): - return self.name - - def main(): args = get_argparser().parse_args() log_forwarder = init_log(args) @@ -118,8 +110,6 @@ def main(): scheduler.start(loop=loop) atexit_register_coroutine(scheduler.stop, loop=loop) - config = MasterConfig(args.name) - worker_handlers.update({ "get_device_db": device_db.get_device_db, "get_device": device_db.get, @@ -136,15 +126,17 @@ def main(): experiment_db.scan_repository_async(loop=loop) signal_handler_task = loop.create_task(signal_handler.wait_terminate()) - master_terminate = SimpleNamespace(terminate=lambda: signal_handler_task.cancel()) + master_management = SimpleNamespace( + get_name=lambda: args.name, + terminate=lambda: signal_handler_task.cancel() + ) server_control = RPCServer({ - "master_config": config, + "master_management": master_management, "master_device_db": device_db, "master_dataset_db": dataset_db, "master_schedule": scheduler, "master_experiment_db": experiment_db, - "master_terminate": master_terminate }, allow_parallel=True) loop.run_until_complete(server_control.start( bind, args.port_control)) From 41caec797eb1afbbac6b99122d20b8c20536a786 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 30 May 2023 16:06:00 +0800 Subject: [PATCH 06/68] flake: do not install ARTIQ itself in dev shell, only its dependencies Otherwise, test runs take a long time when entering the shell, and failing tests stop entering the shell which is not what we want. Also make jsonschema a regular dependency of ARTIQ, since users can now retrieve JSONs via AFWS. --- doc/manual/developing.rst | 7 ++----- doc/manual/installing.rst | 1 - flake.nix | 6 +++--- 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/doc/manual/developing.rst b/doc/manual/developing.rst index f2402e789..cea0c3e9b 100644 --- a/doc/manual/developing.rst +++ b/doc/manual/developing.rst @@ -14,12 +14,9 @@ ARTIQ itself does not depend on Nix, and it is also possible to compile everythi * Install the `Nix package manager `_, version 2.4 or later. Prefer a single-user installation for simplicity. * If you did not install Vivado in its default location ``/opt``, clone the ARTIQ Git repository and edit ``flake.nix`` accordingly. * Enable flakes in Nix by e.g. adding ``experimental-features = nix-command flakes`` to ``nix.conf`` (for example ``~/.config/nix/nix.conf``). -* Enter the development shell by running ``nix develop git+https://github.com/m-labs/artiq.git``, or alternatively by cloning the ARTIQ Git repository and running ``nix develop`` at the root (where ``flake.nix`` is). +* Clone the ARTIQ Git repository and run ``nix develop`` at the root (where ``flake.nix`` is). +* Make the current source code of ARTIQ available to the Python interpreter by running ``export PYTHONPATH=`pwd`:$PYTHONPATH``. * You can then build the firmware and gateware with a command such as ``$ python -m artiq.gateware.targets.kasli``. If you are using a JSON system description file, use ``$ python -m artiq.gateware.targets.kasli_generic file.json``. * Flash the binaries into the FPGA board with a command such as ``$ artiq_flash --srcbuild -d artiq_kasli/``. You need to configure OpenOCD as explained :ref:`in the user section `. OpenOCD is already part of the flake's development environment. * Check that the board boots and examine the UART messages by running a serial terminal program, e.g. ``$ flterm /dev/ttyUSB1`` (``flterm`` is part of MiSoC and installed in the flake's development environment). Leave the terminal running while you are flashing the board, so that you see the startup messages when the board boots immediately after flashing. You can also restart the board (without reflashing it) with ``$ artiq_flash start``. * The communication parameters are 115200 8-N-1. Ensure that your user has access to the serial device (e.g. by adding the user account to the ``dialout`` group). - - -.. warning:: - Nix will make a read-only copy of the ARTIQ source to use in the shell environment. Therefore, any modifications that you make to the source after the shell is started will not be taken into account. A solution applicable to ARTIQ (and several other Python packages such as Migen and MiSoC) is to prepend the ARTIQ source directory to the ``PYTHONPATH`` environment variable after entering the shell. If you want this to be done by default, edit the ``devShell`` section of ``flake.nix``. diff --git a/doc/manual/installing.rst b/doc/manual/installing.rst index 75aa31efb..916cfec8c 100644 --- a/doc/manual/installing.rst +++ b/doc/manual/installing.rst @@ -51,7 +51,6 @@ Installing multiple packages and making them visible to the ARTIQ commands requi #ps.scipy #ps.numba #ps.matplotlib - #ps.jsonschema # required by artiq_ddb_template # or if you need Qt (will recompile): #(ps.matplotlib.override { enableQt = true; }) #ps.bokeh diff --git a/flake.nix b/flake.nix index 9d92902f4..1dc522ae5 100644 --- a/flake.nix +++ b/flake.nix @@ -125,7 +125,7 @@ nativeBuildInputs = [ pkgs.qt5.wrapQtAppsHook ]; # keep llvm_x and lld_x in sync with llvmlite propagatedBuildInputs = [ pkgs.llvm_11 pkgs.lld_11 sipyco.packages.x86_64-linux.sipyco pythonparser artiq-comtools.packages.x86_64-linux.artiq-comtools ] - ++ (with pkgs.python3Packages; [ llvmlite pyqtgraph pygit2 numpy dateutil scipy prettytable pyserial levenshtein h5py pyqt5 qasync tqdm lmdb ]); + ++ (with pkgs.python3Packages; [ llvmlite pyqtgraph pygit2 numpy dateutil scipy prettytable pyserial levenshtein h5py pyqt5 qasync tqdm lmdb jsonschema ]); dontWrapQtApps = true; postFixup = '' @@ -224,7 +224,7 @@ }; }; nativeBuildInputs = [ - (pkgs.python3.withPackages(ps: [ ps.jsonschema migen misoc (artiq.withExperimentalFeatures experimentalFeatures) ])) + (pkgs.python3.withPackages(ps: [ migen misoc (artiq.withExperimentalFeatures experimentalFeatures) ])) rust pkgs.cargo-xbuild pkgs.llvmPackages_11.clang-unwrapped @@ -384,7 +384,7 @@ devShell.x86_64-linux = pkgs.mkShell { name = "artiq-dev-shell"; buildInputs = [ - (pkgs.python3.withPackages(ps: with packages.x86_64-linux; [ migen misoc artiq ps.paramiko ps.jsonschema microscope ])) + (pkgs.python3.withPackages(ps: with packages.x86_64-linux; [ migen misoc ps.paramiko microscope ] ++ artiq.propagatedBuildInputs )) rust pkgs.cargo-xbuild pkgs.llvmPackages_11.clang-unwrapped From 75f6bdb6a10accb54b4b3ef1b167f822a8a54caa Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 30 May 2023 16:21:06 +0800 Subject: [PATCH 07/68] flake: add boards dev shell --- flake.nix | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index 1dc522ae5..4e5b15e29 100644 --- a/flake.nix +++ b/flake.nix @@ -381,7 +381,10 @@ defaultPackage.x86_64-linux = pkgs.python3.withPackages(ps: [ packages.x86_64-linux.artiq ]); - devShell.x86_64-linux = pkgs.mkShell { + # Main development shell with everything you need to develop ARTIQ on Linux. + # ARTIQ itself is not included in the environment, you can make Python use the current sources using e.g. + # export PYTHONPATH=`pwd`:$PYTHONPATH + devShells.x86_64-linux.default = pkgs.mkShell { name = "artiq-dev-shell"; buildInputs = [ (pkgs.python3.withPackages(ps: with packages.x86_64-linux; [ migen misoc ps.paramiko microscope ] ++ artiq.propagatedBuildInputs )) @@ -408,6 +411,21 @@ ''; }; + # Lighter development shell optimized for building firmware and flashing boards. + devShells.x86_64-linux.boards = pkgs.mkShell { + name = "artiq-boards-shell"; + buildInputs = [ + (pkgs.python3.withPackages(ps: with packages.x86_64-linux; [ migen misoc artiq ])) + rust + pkgs.cargo-xbuild + pkgs.llvmPackages_11.clang-unwrapped + pkgs.llvm_11 + pkgs.lld_11 + packages.x86_64-linux.vivado + packages.x86_64-linux.openocd-bscanspi + ]; + }; + packages.aarch64-linux = { openocd-bscanspi = openocd-bscanspi-f pkgs-aarch64; }; From 748969c21e71b45654bd3f9896e9f90f9a8dce57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=81=AB=E7=84=9A=20=E5=AF=8C=E8=89=AF?= Date: Tue, 30 May 2023 16:47:59 +0800 Subject: [PATCH 08/68] flake: update to LLVM 14 and llvmlite 40 Signed-off-by: Egor Savkin --- artiq/test/lit/embedding/syscall_arg_attrs.py | 4 +- artiq/test/lit/embedding/syscall_flags.py | 2 +- flake.nix | 56 ++++++++++++++----- 3 files changed, 45 insertions(+), 17 deletions(-) diff --git a/artiq/test/lit/embedding/syscall_arg_attrs.py b/artiq/test/lit/embedding/syscall_arg_attrs.py index 67207dc32..a20d90bed 100644 --- a/artiq/test/lit/embedding/syscall_arg_attrs.py +++ b/artiq/test/lit/embedding/syscall_arg_attrs.py @@ -18,13 +18,13 @@ def entrypoint(): return_str() -# CHECK: declare void @accept_str\({ i8\*, i32 }\* byval\) +# CHECK: declare void @accept_str\({ i8\*, i32 }\* byval\({ i8\*, i32 }\)\) @syscall def accept_str(name: TStr) -> TNone: pass -# CHECK: declare void @return_str\({ i8\*, i32 }\* sret\) +# CHECK: declare void @return_str\({ i8\*, i32 }\* sret\({ i8\*, i32 }\)\) @syscall def return_str() -> TStr: pass diff --git a/artiq/test/lit/embedding/syscall_flags.py b/artiq/test/lit/embedding/syscall_flags.py index cc78f843b..b2e27d6a0 100644 --- a/artiq/test/lit/embedding/syscall_flags.py +++ b/artiq/test/lit/embedding/syscall_flags.py @@ -15,7 +15,7 @@ def foo() -> TNone: # sret nowrite functions shouldn't be marked inaccessiblememonly. # CHECK-L: ; Function Attrs: nounwind -# CHECK-NEXT-L: declare void @bar({ i32, i64 }* sret) +# CHECK-NEXT-L: declare void @bar({ i32, i64 }* sret({ i32, i64 })) @syscall(flags={"nounwind", "nowrite"}) def bar() -> TTuple([TInt32, TInt64]): pass diff --git a/flake.nix b/flake.nix index 4e5b15e29..f2bde2807 100644 --- a/flake.nix +++ b/flake.nix @@ -111,6 +111,34 @@ ''; }; + llvmlite-new = pkgs.python3Packages.buildPythonPackage rec { + pname = "llvmlite"; + version = "0.40.0"; + src = pkgs.fetchFromGitHub { + owner = "numba"; + repo = "llvmlite"; + rev = "f2aa9a7f127d3fcbc2a8e60373ebff2f567ae640"; + sha256 = "sha256-NxDb/cuKKESn3xC6UFun7J70ZK7jgL430ghGa2pwtEk="; + }; + patches = [ + (pkgs.fetchurl { + url = "https://github.com/numba/llvmlite/pull/950.patch"; + sha256 = "sha256-Yet5Z2Lw946EI/rjLHkn+isJe6FeuXvM9b3nOppWaKc="; + }) + ]; + nativeBuildInputs = [ pkgs.llvm_14 ]; + # Disable static linking + # https://github.com/numba/llvmlite/issues/93 + postPatch = '' + substituteInPlace ffi/Makefile.linux --replace "-static-libstdc++" "" + substituteInPlace llvmlite/tests/test_binding.py --replace "test_linux" "nope" + ''; + # Set directory containing llvm-config binary + preConfigure = '' + export LLVM_CONFIG=${pkgs.llvm_14.dev}/bin/llvm-config + ''; + }; + artiq-upstream = pkgs.python3Packages.buildPythonPackage rec { pname = "artiq"; version = artiqVersion; @@ -124,8 +152,8 @@ nativeBuildInputs = [ pkgs.qt5.wrapQtAppsHook ]; # keep llvm_x and lld_x in sync with llvmlite - propagatedBuildInputs = [ pkgs.llvm_11 pkgs.lld_11 sipyco.packages.x86_64-linux.sipyco pythonparser artiq-comtools.packages.x86_64-linux.artiq-comtools ] - ++ (with pkgs.python3Packages; [ llvmlite pyqtgraph pygit2 numpy dateutil scipy prettytable pyserial levenshtein h5py pyqt5 qasync tqdm lmdb jsonschema ]); + propagatedBuildInputs = [ pkgs.llvm_14 pkgs.lld_14 sipyco.packages.x86_64-linux.sipyco pythonparser artiq-comtools.packages.x86_64-linux.artiq-comtools llvmlite-new ] + ++ (with pkgs.python3Packages; [ pyqtgraph pygit2 numpy dateutil scipy prettytable pyserial levenshtein h5py pyqt5 qasync tqdm lmdb jsonschema ]); dontWrapQtApps = true; postFixup = '' @@ -147,10 +175,10 @@ "--set FONTCONFIG_FILE ${pkgs.fontconfig.out}/etc/fonts/fonts.conf" ]; - # FIXME: automatically propagate lld_11 llvm_11 dependencies + # FIXME: automatically propagate lld_14 llvm_14 dependencies # cacert is required in the check stage only, as certificates are to be # obtained from system elsewhere - nativeCheckInputs = [ pkgs.lld_11 pkgs.llvm_11 libartiq-support pkgs.lit outputcheck pkgs.cacert ]; + nativeCheckInputs = [ pkgs.lld_14 pkgs.llvm_14 libartiq-support pkgs.lit outputcheck pkgs.cacert ]; checkPhase = '' python -m unittest discover -v artiq.test @@ -227,9 +255,9 @@ (pkgs.python3.withPackages(ps: [ migen misoc (artiq.withExperimentalFeatures experimentalFeatures) ])) rust pkgs.cargo-xbuild - pkgs.llvmPackages_11.clang-unwrapped - pkgs.llvm_11 - pkgs.lld_11 + pkgs.llvmPackages_14.clang-unwrapped + pkgs.llvm_14 + pkgs.lld_14 vivado rustPlatform.cargoSetupHook ]; @@ -390,9 +418,9 @@ (pkgs.python3.withPackages(ps: with packages.x86_64-linux; [ migen misoc ps.paramiko microscope ] ++ artiq.propagatedBuildInputs )) rust pkgs.cargo-xbuild - pkgs.llvmPackages_11.clang-unwrapped - pkgs.llvm_11 - pkgs.lld_11 + pkgs.llvmPackages_14.clang-unwrapped + pkgs.llvm_14 + pkgs.lld_14 # To manually run compiler tests: pkgs.lit outputcheck @@ -419,8 +447,8 @@ rust pkgs.cargo-xbuild pkgs.llvmPackages_11.clang-unwrapped - pkgs.llvm_11 - pkgs.lld_11 + pkgs.llvm_14 + pkgs.lld_14 packages.x86_64-linux.vivado packages.x86_64-linux.openocd-bscanspi ]; @@ -453,8 +481,8 @@ buildInputs = [ (pkgs.python3.withPackages(ps: with packages.x86_64-linux; [ artiq ps.paramiko ])) - pkgs.llvm_11 - pkgs.lld_11 + pkgs.llvm_14 + pkgs.lld_14 pkgs.openssh packages.x86_64-linux.openocd-bscanspi # for the bscanspi bitstreams ]; From fabe88065b2130ee9b844e01e03586d4d11f28ee Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 30 May 2023 16:54:59 +0800 Subject: [PATCH 09/68] flake: export llvmlite-new --- flake.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index f2bde2807..de66789bf 100644 --- a/flake.nix +++ b/flake.nix @@ -353,7 +353,7 @@ }; in rec { packages.x86_64-linux = { - inherit pythonparser qasync artiq; + inherit pythonparser llvmlite-new qasync artiq; inherit migen misoc asyncserial microscope vivadoEnv vivado; openocd-bscanspi = openocd-bscanspi-f pkgs; artiq-board-kc705-nist_clock = makeArtiqBoardPackage { From 9a6bc6dc7b1bf32339cfa1bf35cf595d8c0075b7 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 31 May 2023 18:59:39 +0800 Subject: [PATCH 10/68] flake: fix clang version in boards shell --- flake.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index de66789bf..5f112e3a2 100644 --- a/flake.nix +++ b/flake.nix @@ -446,7 +446,7 @@ (pkgs.python3.withPackages(ps: with packages.x86_64-linux; [ migen misoc artiq ])) rust pkgs.cargo-xbuild - pkgs.llvmPackages_11.clang-unwrapped + pkgs.llvmPackages_14.clang-unwrapped pkgs.llvm_14 pkgs.lld_14 packages.x86_64-linux.vivado From d103cbea31144fee33d0693279ae94e6dcf9ba5f Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 31 May 2023 18:59:51 +0800 Subject: [PATCH 11/68] libboard_misoc: fix clang STB_WEAK warning --- artiq/firmware/libboard_misoc/riscv32/vectors.S | 2 -- 1 file changed, 2 deletions(-) diff --git a/artiq/firmware/libboard_misoc/riscv32/vectors.S b/artiq/firmware/libboard_misoc/riscv32/vectors.S index 19b6c5c3f..ea83ab53c 100644 --- a/artiq/firmware/libboard_misoc/riscv32/vectors.S +++ b/artiq/firmware/libboard_misoc/riscv32/vectors.S @@ -129,8 +129,6 @@ _abs_start: restores caller saved registers and then returns. */ .global _start_trap -/* Make it .weak so PAC/HAL can provide their own if needed. */ -.weak _start_trap _start_trap: addi sp, sp, -16*REGBYTES From 6276182c96297e479f490bb856e337f33a4fe9cc Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 31 May 2023 19:36:40 +0800 Subject: [PATCH 12/68] Revert "flake: fix clang version in boards shell" This reverts commit 9a6bc6dc7b1bf32339cfa1bf35cf595d8c0075b7. --- flake.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index 5f112e3a2..de66789bf 100644 --- a/flake.nix +++ b/flake.nix @@ -446,7 +446,7 @@ (pkgs.python3.withPackages(ps: with packages.x86_64-linux; [ migen misoc artiq ])) rust pkgs.cargo-xbuild - pkgs.llvmPackages_14.clang-unwrapped + pkgs.llvmPackages_11.clang-unwrapped pkgs.llvm_14 pkgs.lld_14 packages.x86_64-linux.vivado From b20d09aad5499bf228b9f421723e9fed08d43960 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 31 May 2023 19:36:41 +0800 Subject: [PATCH 13/68] Revert "flake: export llvmlite-new" This reverts commit fabe88065b2130ee9b844e01e03586d4d11f28ee. --- flake.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index de66789bf..f2bde2807 100644 --- a/flake.nix +++ b/flake.nix @@ -353,7 +353,7 @@ }; in rec { packages.x86_64-linux = { - inherit pythonparser llvmlite-new qasync artiq; + inherit pythonparser qasync artiq; inherit migen misoc asyncserial microscope vivadoEnv vivado; openocd-bscanspi = openocd-bscanspi-f pkgs; artiq-board-kc705-nist_clock = makeArtiqBoardPackage { From c6b29b30fb58044d82b607cc5901c63338a5a9fa Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 31 May 2023 19:36:43 +0800 Subject: [PATCH 14/68] Revert "flake: update to LLVM 14 and llvmlite 40" This reverts commit 748969c21e71b45654bd3f9896e9f90f9a8dce57. --- artiq/test/lit/embedding/syscall_arg_attrs.py | 4 +- artiq/test/lit/embedding/syscall_flags.py | 2 +- flake.nix | 56 +++++-------------- 3 files changed, 17 insertions(+), 45 deletions(-) diff --git a/artiq/test/lit/embedding/syscall_arg_attrs.py b/artiq/test/lit/embedding/syscall_arg_attrs.py index a20d90bed..67207dc32 100644 --- a/artiq/test/lit/embedding/syscall_arg_attrs.py +++ b/artiq/test/lit/embedding/syscall_arg_attrs.py @@ -18,13 +18,13 @@ def entrypoint(): return_str() -# CHECK: declare void @accept_str\({ i8\*, i32 }\* byval\({ i8\*, i32 }\)\) +# CHECK: declare void @accept_str\({ i8\*, i32 }\* byval\) @syscall def accept_str(name: TStr) -> TNone: pass -# CHECK: declare void @return_str\({ i8\*, i32 }\* sret\({ i8\*, i32 }\)\) +# CHECK: declare void @return_str\({ i8\*, i32 }\* sret\) @syscall def return_str() -> TStr: pass diff --git a/artiq/test/lit/embedding/syscall_flags.py b/artiq/test/lit/embedding/syscall_flags.py index b2e27d6a0..cc78f843b 100644 --- a/artiq/test/lit/embedding/syscall_flags.py +++ b/artiq/test/lit/embedding/syscall_flags.py @@ -15,7 +15,7 @@ def foo() -> TNone: # sret nowrite functions shouldn't be marked inaccessiblememonly. # CHECK-L: ; Function Attrs: nounwind -# CHECK-NEXT-L: declare void @bar({ i32, i64 }* sret({ i32, i64 })) +# CHECK-NEXT-L: declare void @bar({ i32, i64 }* sret) @syscall(flags={"nounwind", "nowrite"}) def bar() -> TTuple([TInt32, TInt64]): pass diff --git a/flake.nix b/flake.nix index f2bde2807..4e5b15e29 100644 --- a/flake.nix +++ b/flake.nix @@ -111,34 +111,6 @@ ''; }; - llvmlite-new = pkgs.python3Packages.buildPythonPackage rec { - pname = "llvmlite"; - version = "0.40.0"; - src = pkgs.fetchFromGitHub { - owner = "numba"; - repo = "llvmlite"; - rev = "f2aa9a7f127d3fcbc2a8e60373ebff2f567ae640"; - sha256 = "sha256-NxDb/cuKKESn3xC6UFun7J70ZK7jgL430ghGa2pwtEk="; - }; - patches = [ - (pkgs.fetchurl { - url = "https://github.com/numba/llvmlite/pull/950.patch"; - sha256 = "sha256-Yet5Z2Lw946EI/rjLHkn+isJe6FeuXvM9b3nOppWaKc="; - }) - ]; - nativeBuildInputs = [ pkgs.llvm_14 ]; - # Disable static linking - # https://github.com/numba/llvmlite/issues/93 - postPatch = '' - substituteInPlace ffi/Makefile.linux --replace "-static-libstdc++" "" - substituteInPlace llvmlite/tests/test_binding.py --replace "test_linux" "nope" - ''; - # Set directory containing llvm-config binary - preConfigure = '' - export LLVM_CONFIG=${pkgs.llvm_14.dev}/bin/llvm-config - ''; - }; - artiq-upstream = pkgs.python3Packages.buildPythonPackage rec { pname = "artiq"; version = artiqVersion; @@ -152,8 +124,8 @@ nativeBuildInputs = [ pkgs.qt5.wrapQtAppsHook ]; # keep llvm_x and lld_x in sync with llvmlite - propagatedBuildInputs = [ pkgs.llvm_14 pkgs.lld_14 sipyco.packages.x86_64-linux.sipyco pythonparser artiq-comtools.packages.x86_64-linux.artiq-comtools llvmlite-new ] - ++ (with pkgs.python3Packages; [ pyqtgraph pygit2 numpy dateutil scipy prettytable pyserial levenshtein h5py pyqt5 qasync tqdm lmdb jsonschema ]); + propagatedBuildInputs = [ pkgs.llvm_11 pkgs.lld_11 sipyco.packages.x86_64-linux.sipyco pythonparser artiq-comtools.packages.x86_64-linux.artiq-comtools ] + ++ (with pkgs.python3Packages; [ llvmlite pyqtgraph pygit2 numpy dateutil scipy prettytable pyserial levenshtein h5py pyqt5 qasync tqdm lmdb jsonschema ]); dontWrapQtApps = true; postFixup = '' @@ -175,10 +147,10 @@ "--set FONTCONFIG_FILE ${pkgs.fontconfig.out}/etc/fonts/fonts.conf" ]; - # FIXME: automatically propagate lld_14 llvm_14 dependencies + # FIXME: automatically propagate lld_11 llvm_11 dependencies # cacert is required in the check stage only, as certificates are to be # obtained from system elsewhere - nativeCheckInputs = [ pkgs.lld_14 pkgs.llvm_14 libartiq-support pkgs.lit outputcheck pkgs.cacert ]; + nativeCheckInputs = [ pkgs.lld_11 pkgs.llvm_11 libartiq-support pkgs.lit outputcheck pkgs.cacert ]; checkPhase = '' python -m unittest discover -v artiq.test @@ -255,9 +227,9 @@ (pkgs.python3.withPackages(ps: [ migen misoc (artiq.withExperimentalFeatures experimentalFeatures) ])) rust pkgs.cargo-xbuild - pkgs.llvmPackages_14.clang-unwrapped - pkgs.llvm_14 - pkgs.lld_14 + pkgs.llvmPackages_11.clang-unwrapped + pkgs.llvm_11 + pkgs.lld_11 vivado rustPlatform.cargoSetupHook ]; @@ -418,9 +390,9 @@ (pkgs.python3.withPackages(ps: with packages.x86_64-linux; [ migen misoc ps.paramiko microscope ] ++ artiq.propagatedBuildInputs )) rust pkgs.cargo-xbuild - pkgs.llvmPackages_14.clang-unwrapped - pkgs.llvm_14 - pkgs.lld_14 + pkgs.llvmPackages_11.clang-unwrapped + pkgs.llvm_11 + pkgs.lld_11 # To manually run compiler tests: pkgs.lit outputcheck @@ -447,8 +419,8 @@ rust pkgs.cargo-xbuild pkgs.llvmPackages_11.clang-unwrapped - pkgs.llvm_14 - pkgs.lld_14 + pkgs.llvm_11 + pkgs.lld_11 packages.x86_64-linux.vivado packages.x86_64-linux.openocd-bscanspi ]; @@ -481,8 +453,8 @@ buildInputs = [ (pkgs.python3.withPackages(ps: with packages.x86_64-linux; [ artiq ps.paramiko ])) - pkgs.llvm_14 - pkgs.lld_14 + pkgs.llvm_11 + pkgs.lld_11 pkgs.openssh packages.x86_64-linux.openocd-bscanspi # for the bscanspi bitstreams ]; From c8dc2cbf094120de4e560a306d8eb1418663c62c Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 31 May 2023 21:57:54 +0800 Subject: [PATCH 15/68] browser: decouple dataset controller from dataset dock --- artiq/browser/datasets.py | 45 ++++++++++++++++++--------------- artiq/frontend/artiq_browser.py | 14 +++++----- 2 files changed, 32 insertions(+), 27 deletions(-) diff --git a/artiq/browser/datasets.py b/artiq/browser/datasets.py index 78bf6e8f7..76da6340e 100644 --- a/artiq/browser/datasets.py +++ b/artiq/browser/datasets.py @@ -23,8 +23,30 @@ class Model(DictSyncTreeSepModel): return short_format(v[1]) +class DatasetCtl: + def __init__(self, master_host, master_port): + self.master_host = master_host + self.master_port = master_port + + async def set(self, key, value, persist=None): + logger.info("Uploading dataset '%s' to master...", key) + try: + remote = RPCClient() + await remote.connect_rpc(self.master_host, self.master_port, + "master_dataset_db") + try: + await remote.set(key, value, persist) + finally: + remote.close_rpc() + except: + logger.error("Failed uploading dataset '%s'", + key, exc_info=True) + else: + logger.info("Finished uploading dataset '%s'", key) + + class DatasetsDock(QtWidgets.QDockWidget): - def __init__(self, dataset_sub, master_host, master_port): + def __init__(self, dataset_sub, dataset_ctl): QtWidgets.QDockWidget.__init__(self, "Datasets") self.setObjectName("Datasets") self.setFeatures(QtWidgets.QDockWidget.DockWidgetMovable | @@ -64,8 +86,7 @@ class DatasetsDock(QtWidgets.QDockWidget): self.set_model(Model(dict())) dataset_sub.add_setmodel_callback(self.set_model) - self.master_host = master_host - self.master_port = master_port + self.dataset_ctl = dataset_ctl def _search_datasets(self): if hasattr(self, "table_model_filter"): @@ -82,22 +103,6 @@ class DatasetsDock(QtWidgets.QDockWidget): self.table_model_filter.setSourceModel(self.table_model) self.table.setModel(self.table_model_filter) - async def _upload_dataset(self, name, value,): - logger.info("Uploading dataset '%s' to master...", name) - try: - remote = RPCClient() - await remote.connect_rpc(self.master_host, self.master_port, - "master_dataset_db") - try: - await remote.set(name, value) - finally: - remote.close_rpc() - except: - logger.error("Failed uploading dataset '%s'", - name, exc_info=True) - else: - logger.info("Finished uploading dataset '%s'", name) - def upload_clicked(self): idx = self.table.selectedIndexes() if idx: @@ -105,7 +110,7 @@ class DatasetsDock(QtWidgets.QDockWidget): key = self.table_model.index_to_key(idx) if key is not None: persist, value = self.table_model.backing_store[key] - asyncio.ensure_future(self._upload_dataset(key, value)) + asyncio.ensure_future(self.dataset_ctl.set(key, value)) def save_state(self): return bytes(self.table.header().saveState()) diff --git a/artiq/frontend/artiq_browser.py b/artiq/frontend/artiq_browser.py index af469c05a..5cb7ef090 100755 --- a/artiq/frontend/artiq_browser.py +++ b/artiq/frontend/artiq_browser.py @@ -48,8 +48,8 @@ def get_argparser(): class Browser(QtWidgets.QMainWindow): - def __init__(self, smgr, dataset_sub, browse_root, - master_host, master_port, *, loop=None): + def __init__(self, smgr, dataset_sub, dataset_ctl, browse_root, + *, loop=None): QtWidgets.QMainWindow.__init__(self) smgr.register(self) @@ -81,12 +81,11 @@ class Browser(QtWidgets.QMainWindow): self.files.dataset_changed.connect( self.experiments.dataset_changed) - self.applets = applets.AppletsDock(self, dataset_sub, loop=loop) + self.applets = applets.AppletsDock(self, dataset_sub, dataset_ctl, loop=loop) smgr.register(self.applets) atexit_register_coroutine(self.applets.stop, loop=loop) - self.datasets = datasets.DatasetsDock( - dataset_sub, master_host, master_port) + self.datasets = datasets.DatasetsDock(dataset_sub, dataset_ctl) smgr.register(self.datasets) self.files.metadata_changed.connect(self.datasets.metadata_changed) @@ -151,8 +150,9 @@ def main(): smgr = state.StateManager(args.db_file) - browser = Browser(smgr, dataset_sub, args.browse_root, - args.server, args.port, loop=loop) + dataset_ctl = datasets.DatasetCtl(args.server, args.port) + browser = Browser(smgr, dataset_sub, dataset_ctl, args.browse_root, + loop=loop) widget_log_handler.callback = browser.log.model.append if os.name == "nt": From ff11b5df713290ff450c28688ec213755a874a60 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 31 May 2023 22:07:05 +0800 Subject: [PATCH 16/68] flake: add qtsvg --- flake.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/flake.nix b/flake.nix index 4e5b15e29..4912a076b 100644 --- a/flake.nix +++ b/flake.nix @@ -124,7 +124,7 @@ nativeBuildInputs = [ pkgs.qt5.wrapQtAppsHook ]; # keep llvm_x and lld_x in sync with llvmlite - propagatedBuildInputs = [ pkgs.llvm_11 pkgs.lld_11 sipyco.packages.x86_64-linux.sipyco pythonparser artiq-comtools.packages.x86_64-linux.artiq-comtools ] + propagatedBuildInputs = [ pkgs.llvm_11 pkgs.lld_11 sipyco.packages.x86_64-linux.sipyco pythonparser pkgs.qt5.qtsvg artiq-comtools.packages.x86_64-linux.artiq-comtools ] ++ (with pkgs.python3Packages; [ llvmlite pyqtgraph pygit2 numpy dateutil scipy prettytable pyserial levenshtein h5py pyqt5 qasync tqdm lmdb jsonschema ]); dontWrapQtApps = true; @@ -406,7 +406,7 @@ ]; shellHook = '' export LIBARTIQ_SUPPORT=`libartiq-support` - export QT_PLUGIN_PATH=${pkgs.qt5.qtbase}/${pkgs.qt5.qtbase.dev.qtPluginPrefix} + export QT_PLUGIN_PATH=${pkgs.qt5.qtbase}/${pkgs.qt5.qtbase.dev.qtPluginPrefix}:${pkgs.qt5.qtsvg.bin}/${pkgs.qt5.qtbase.dev.qtPluginPrefix} export QML2_IMPORT_PATH=${pkgs.qt5.qtbase}/${pkgs.qt5.qtbase.dev.qtQmlPrefix} ''; }; From e12219e8037d5741bff110c8d21f10ea7d48be74 Mon Sep 17 00:00:00 2001 From: Florian Agbuya Date: Wed, 31 May 2023 22:08:14 +0800 Subject: [PATCH 17/68] gui: add handler for applet set_dataset --- artiq/frontend/artiq_dashboard.py | 1 + artiq/gui/applets.py | 15 ++++++++++----- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/artiq/frontend/artiq_dashboard.py b/artiq/frontend/artiq_dashboard.py index bb88f39c7..251c2beb3 100755 --- a/artiq/frontend/artiq_dashboard.py +++ b/artiq/frontend/artiq_dashboard.py @@ -191,6 +191,7 @@ def main(): d_applets = applets_ccb.AppletsCCBDock(main_window, sub_clients["datasets"], + rpc_clients["dataset_db"], extra_substitutes={ "server": args.server, "port_notify": args.port_notify, diff --git a/artiq/gui/applets.py b/artiq/gui/applets.py index 0e65a2ee3..f753b56b1 100644 --- a/artiq/gui/applets.py +++ b/artiq/gui/applets.py @@ -21,9 +21,10 @@ logger = logging.getLogger(__name__) class AppletIPCServer(AsyncioParentComm): - def __init__(self, dataset_sub): + def __init__(self, dataset_sub, dataset_ctl): AsyncioParentComm.__init__(self) self.dataset_sub = dataset_sub + self.dataset_ctl = dataset_ctl self.datasets = set() self.dataset_prefixes = [] @@ -78,6 +79,8 @@ class AppletIPCServer(AsyncioParentComm): mod = self._synthesize_init( self.dataset_sub.model.backing_store) self.write_pyon({"action": "mod", "mod": mod}) + elif action == "set_dataset": + await self.dataset_ctl.set(obj["key"], obj["value"], obj["persist"]) else: raise ValueError("unknown action in applet message") except: @@ -103,7 +106,7 @@ class AppletIPCServer(AsyncioParentComm): class _AppletDock(QDockWidgetCloseDetect): - def __init__(self, dataset_sub, uid, name, spec, extra_substitutes): + def __init__(self, dataset_sub, dataset_ctl, uid, name, spec, extra_substitutes): QDockWidgetCloseDetect.__init__(self, "Applet: " + name) self.setObjectName("applet" + str(uid)) @@ -112,6 +115,7 @@ class _AppletDock(QDockWidgetCloseDetect): self.resize(40*qfm.averageCharWidth(), 10*qfm.lineSpacing()) self.dataset_sub = dataset_sub + self.dataset_ctl = dataset_ctl self.applet_name = name self.spec = spec self.extra_substitutes = extra_substitutes @@ -130,7 +134,7 @@ class _AppletDock(QDockWidgetCloseDetect): return self.starting_stopping = True try: - self.ipc = AppletIPCServer(self.dataset_sub) + self.ipc = AppletIPCServer(self.dataset_sub, self.dataset_ctl) env = os.environ.copy() env["PYTHONUNBUFFERED"] = "1" env["ARTIQ_APPLET_EMBED"] = self.ipc.get_address() @@ -327,7 +331,7 @@ class _CompleterDelegate(QtWidgets.QStyledItemDelegate): class AppletsDock(QtWidgets.QDockWidget): - def __init__(self, main_window, dataset_sub, extra_substitutes={}, *, loop=None): + def __init__(self, main_window, dataset_sub, dataset_ctl, extra_substitutes={}, *, loop=None): """ :param extra_substitutes: Map of extra ``${strings}`` to substitute in applet commands to their respective values. @@ -339,6 +343,7 @@ class AppletsDock(QtWidgets.QDockWidget): self.main_window = main_window self.dataset_sub = dataset_sub + self.dataset_ctl = dataset_ctl self.extra_substitutes = extra_substitutes self.applet_uids = set() @@ -440,7 +445,7 @@ class AppletsDock(QtWidgets.QDockWidget): self.table.itemChanged.connect(self.item_changed) def create(self, item, name, spec): - dock = _AppletDock(self.dataset_sub, item.applet_uid, name, spec, self.extra_substitutes) + dock = _AppletDock(self.dataset_sub, self.dataset_ctl, item.applet_uid, name, spec, self.extra_substitutes) self.main_window.addDockWidget(QtCore.Qt.RightDockWidgetArea, dock) dock.setFloating(True) asyncio.ensure_future(dock.start(), loop=self._loop) From c6ddd3af17e0c443a274b91cd0d7ac11a2b16315 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 31 May 2023 22:51:48 +0800 Subject: [PATCH 18/68] applets: add controller and set_dataset API --- artiq/applets/big_number.py | 2 +- artiq/applets/image.py | 2 +- artiq/applets/plot_hist.py | 2 +- artiq/applets/plot_xy.py | 2 +- artiq/applets/plot_xy_hist.py | 2 +- artiq/applets/progress_bar.py | 2 +- artiq/applets/simple.py | 66 ++++++++++++++++++++++++++++++----- 7 files changed, 64 insertions(+), 14 deletions(-) diff --git a/artiq/applets/big_number.py b/artiq/applets/big_number.py index 62348c8cf..b637847ff 100755 --- a/artiq/applets/big_number.py +++ b/artiq/applets/big_number.py @@ -6,7 +6,7 @@ from artiq.applets.simple import SimpleApplet class NumberWidget(QtWidgets.QLCDNumber): - def __init__(self, args): + def __init__(self, args, ctl): QtWidgets.QLCDNumber.__init__(self) self.setDigitCount(args.digit_count) self.dataset_name = args.dataset diff --git a/artiq/applets/image.py b/artiq/applets/image.py index b7d36c1a1..7a192bcda 100755 --- a/artiq/applets/image.py +++ b/artiq/applets/image.py @@ -7,7 +7,7 @@ from artiq.applets.simple import SimpleApplet class Image(pyqtgraph.ImageView): - def __init__(self, args): + def __init__(self, args, ctl): pyqtgraph.ImageView.__init__(self) self.args = args diff --git a/artiq/applets/plot_hist.py b/artiq/applets/plot_hist.py index b3493c836..9dbebcf4c 100755 --- a/artiq/applets/plot_hist.py +++ b/artiq/applets/plot_hist.py @@ -8,7 +8,7 @@ from artiq.applets.simple import TitleApplet class HistogramPlot(pyqtgraph.PlotWidget): - def __init__(self, args): + def __init__(self, args, ctl): pyqtgraph.PlotWidget.__init__(self) self.args = args self.timer = QTimer() diff --git a/artiq/applets/plot_xy.py b/artiq/applets/plot_xy.py index 8eaf9786a..bb3eab388 100755 --- a/artiq/applets/plot_xy.py +++ b/artiq/applets/plot_xy.py @@ -9,7 +9,7 @@ from artiq.applets.simple import TitleApplet class XYPlot(pyqtgraph.PlotWidget): - def __init__(self, args): + def __init__(self, args, ctl): pyqtgraph.PlotWidget.__init__(self) self.args = args self.timer = QTimer() diff --git a/artiq/applets/plot_xy_hist.py b/artiq/applets/plot_xy_hist.py index 39bd49098..82c06d778 100755 --- a/artiq/applets/plot_xy_hist.py +++ b/artiq/applets/plot_xy_hist.py @@ -22,7 +22,7 @@ def _compute_ys(histogram_bins, histograms_counts): # pyqtgraph.GraphicsWindow fails to behave like a regular Qt widget # and breaks embedding. Do not use as top widget. class XYHistPlot(QtWidgets.QSplitter): - def __init__(self, args): + def __init__(self, args, ctl): QtWidgets.QSplitter.__init__(self) self.resize(1000, 600) self.setWindowTitle("XY/Histogram") diff --git a/artiq/applets/progress_bar.py b/artiq/applets/progress_bar.py index bbded954c..f7eed5c9e 100644 --- a/artiq/applets/progress_bar.py +++ b/artiq/applets/progress_bar.py @@ -6,7 +6,7 @@ from artiq.applets.simple import SimpleApplet class ProgressWidget(QtWidgets.QProgressBar): - def __init__(self, args): + def __init__(self, args, ctl): QtWidgets.QProgressBar.__init__(self) self.setMinimum(args.min) self.setMaximum(args.max) diff --git a/artiq/applets/simple.py b/artiq/applets/simple.py index 196b8f1e3..d06334936 100644 --- a/artiq/applets/simple.py +++ b/artiq/applets/simple.py @@ -7,6 +7,7 @@ import string from qasync import QEventLoop, QtWidgets, QtCore from sipyco.sync_struct import Subscriber, process_mod +from sipyco.pc_rpc import AsyncioClient as RPCClient from sipyco import pyon from sipyco.pipe_ipc import AsyncioChildComm @@ -14,6 +15,29 @@ from sipyco.pipe_ipc import AsyncioChildComm logger = logging.getLogger(__name__) +class AppletControlIPC: + def __init__(self, ipc): + self.ipc = ipc + + def set_dataset(self, key, value, persist=None): + self.ipc.set_dataset(key, value, persist) + + +class AppletControlRPC: + def __init__(self, loop, dataset_ctl): + self.loop = loop + self.dataset_ctl = dataset_ctl + self.background_tasks = set() + + def _background(self, coro, *args): + task = self.loop.create_task(coro(*args)) + self.background_tasks.add(task) + task.add_done_callback(self.background_tasks.discard) + + def set_dataset(self, key, value, persist=None): + self._background(self.dataset_ctl.set, key, value, persist) + + class AppletIPCClient(AsyncioChildComm): def set_close_cb(self, close_cb): self.close_cb = close_cb @@ -72,6 +96,12 @@ class AppletIPCClient(AsyncioChildComm): self.mod_cb = mod_cb asyncio.ensure_future(self.listen()) + def set_dataset(self, key, value, persist=None): + self.write_pyon({"action": "set_dataset", + "key": key, + "value": value, + "persist": persist}) + class SimpleApplet: def __init__(self, main_widget_class, cmd_description=None, @@ -92,8 +122,11 @@ class SimpleApplet: "for dataset notifications " "(ignored in embedded mode)") group.add_argument( - "--port", default=3250, type=int, - help="TCP port to connect to") + "--port-notify", default=3250, type=int, + help="TCP port to connect to for notifications (ignored in embedded mode)") + group.add_argument( + "--port-control", default=3251, type=int, + help="TCP port to connect to for control (ignored in embedded mode)") self._arggroup_datasets = self.argparser.add_argument_group("datasets") @@ -132,8 +165,21 @@ class SimpleApplet: if self.embed is not None: self.ipc.close() + def ctl_init(self): + if self.embed is None: + dataset_ctl = RPCClient() + self.loop.run_until_complete(dataset_ctl.connect_rpc( + self.args.server, self.args.port_control, "master_dataset_db")) + self.ctl = AppletControlRPC(self.loop, dataset_ctl) + else: + self.ctl = AppletControlIPC(self.ipc) + + def ctl_close(self): + if self.embed is None: + self.ctl.dataset_ctl.close_rpc() + def create_main_widget(self): - self.main_widget = self.main_widget_class(self.args) + self.main_widget = self.main_widget_class(self.args, self.ctl) if self.embed is not None: self.ipc.set_close_cb(self.main_widget.close) if os.name == "nt": @@ -214,7 +260,7 @@ class SimpleApplet: self.subscriber = Subscriber("datasets", self.sub_init, self.sub_mod) self.loop.run_until_complete(self.subscriber.connect( - self.args.server, self.args.port)) + self.args.server, self.args.port_notify)) else: self.ipc.subscribe(self.datasets, self.sub_init, self.sub_mod, dataset_prefixes=self.dataset_prefixes) @@ -229,12 +275,16 @@ class SimpleApplet: try: self.ipc_init() try: - self.create_main_widget() - self.subscribe() + self.ctl_init() try: - self.loop.run_forever() + self.create_main_widget() + self.subscribe() + try: + self.loop.run_forever() + finally: + self.unsubscribe() finally: - self.unsubscribe() + self.ctl_close() finally: self.ipc_close() finally: From e0ebc1b21dcbb250435c3e36dc4026f0b7d607aa Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 31 May 2023 22:56:48 +0800 Subject: [PATCH 19/68] applets: fix some asyncio problems --- artiq/applets/simple.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/artiq/applets/simple.py b/artiq/applets/simple.py index d06334936..c9b512a56 100644 --- a/artiq/applets/simple.py +++ b/artiq/applets/simple.py @@ -88,13 +88,13 @@ class AppletIPCClient(AsyncioChildComm): exc_info=True) self.close_cb() - def subscribe(self, datasets, init_cb, mod_cb, dataset_prefixes=[]): + def subscribe(self, datasets, init_cb, mod_cb, dataset_prefixes=[], *, loop): self.write_pyon({"action": "subscribe", "datasets": datasets, "dataset_prefixes": dataset_prefixes}) self.init_cb = init_cb self.mod_cb = mod_cb - asyncio.ensure_future(self.listen()) + self.listen_task = loop.create_task(self.listen()) def set_dataset(self, key, value, persist=None): self.write_pyon({"action": "set_dataset", @@ -250,8 +250,8 @@ class SimpleApplet: self.mod_buffer.append(mod) else: self.mod_buffer = [mod] - asyncio.get_event_loop().call_later(self.args.update_delay, - self.flush_mod_buffer) + self.loop.call_later(self.args.update_delay, + self.flush_mod_buffer) else: self.emit_data_changed(self.data, [mod]) @@ -263,7 +263,8 @@ class SimpleApplet: self.args.server, self.args.port_notify)) else: self.ipc.subscribe(self.datasets, self.sub_init, self.sub_mod, - dataset_prefixes=self.dataset_prefixes) + dataset_prefixes=self.dataset_prefixes, + loop=self.loop) def unsubscribe(self): if self.embed is None: From b97f6a9e44438c58993b4bde84d65dbe778c0dfc Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 2 Jun 2023 10:48:41 +0800 Subject: [PATCH 20/68] bootloader: fix compilation warning without Ethernet --- artiq/firmware/bootloader/main.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/artiq/firmware/bootloader/main.rs b/artiq/firmware/bootloader/main.rs index 355b94076..50772d8f7 100644 --- a/artiq/firmware/bootloader/main.rs +++ b/artiq/firmware/bootloader/main.rs @@ -18,7 +18,9 @@ use board_misoc::slave_fpga; use board_misoc::{clock, ethmac, net_settings}; use board_misoc::uart_console::Console; use riscv::register::{mcause, mepc, mtval}; +#[cfg(has_ethmac)] use smoltcp::iface::{Routes, SocketStorage}; +#[cfg(has_ethmac)] use smoltcp::wire::{HardwareAddress, IpAddress, Ipv4Address, Ipv6Address}; fn check_integrity() -> bool { From 29cb7e785d94cbb6f0633f9195560b92c0eed335 Mon Sep 17 00:00:00 2001 From: mwojcik Date: Fri, 2 Jun 2023 16:49:30 +0800 Subject: [PATCH 21/68] fix missing DIFF_TERM for Sampler and Mirny inputs --- artiq/gateware/eem.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/artiq/gateware/eem.py b/artiq/gateware/eem.py index 3cc55e3f0..bcb3db7be 100644 --- a/artiq/gateware/eem.py +++ b/artiq/gateware/eem.py @@ -259,25 +259,25 @@ class Sampler(_EEM): ios = [ ("sampler{}_adc_spi_p".format(eem), 0, Subsignal("clk", Pins(_eem_pin(eem, 0, "p"))), - Subsignal("miso", Pins(_eem_pin(eem, 1, "p"))), + Subsignal("miso", Pins(_eem_pin(eem, 1, "p")), Misc("DIFF_TERM=TRUE")), iostandard(eem), ), ("sampler{}_adc_spi_n".format(eem), 0, Subsignal("clk", Pins(_eem_pin(eem, 0, "n"))), - Subsignal("miso", Pins(_eem_pin(eem, 1, "n"))), + Subsignal("miso", Pins(_eem_pin(eem, 1, "n")), Misc("DIFF_TERM=TRUE")), iostandard(eem), ), ("sampler{}_pgia_spi_p".format(eem), 0, Subsignal("clk", Pins(_eem_pin(eem, 4, "p"))), Subsignal("mosi", Pins(_eem_pin(eem, 5, "p"))), - Subsignal("miso", Pins(_eem_pin(eem, 6, "p"))), + Subsignal("miso", Pins(_eem_pin(eem, 6, "p")), Misc("DIFF_TERM=TRUE")), Subsignal("cs_n", Pins(_eem_pin(eem, 7, "p"))), iostandard(eem), ), ("sampler{}_pgia_spi_n".format(eem), 0, Subsignal("clk", Pins(_eem_pin(eem, 4, "n"))), Subsignal("mosi", Pins(_eem_pin(eem, 5, "n"))), - Subsignal("miso", Pins(_eem_pin(eem, 6, "n"))), + Subsignal("miso", Pins(_eem_pin(eem, 6, "n")), Misc("DIFF_TERM=TRUE")), Subsignal("cs_n", Pins(_eem_pin(eem, 7, "n"))), iostandard(eem), ), @@ -633,14 +633,14 @@ class Mirny(_EEM): ("mirny{}_spi_p".format(eem), 0, Subsignal("clk", Pins(_eem_pin(eem, 0, "p"))), Subsignal("mosi", Pins(_eem_pin(eem, 1, "p"))), - Subsignal("miso", Pins(_eem_pin(eem, 2, "p"))), + Subsignal("miso", Pins(_eem_pin(eem, 2, "p")), Misc("DIFF_TERM=TRUE")), Subsignal("cs_n", Pins(_eem_pin(eem, 3, "p"))), iostandard(eem), ), ("mirny{}_spi_n".format(eem), 0, Subsignal("clk", Pins(_eem_pin(eem, 0, "n"))), Subsignal("mosi", Pins(_eem_pin(eem, 1, "n"))), - Subsignal("miso", Pins(_eem_pin(eem, 2, "n"))), + Subsignal("miso", Pins(_eem_pin(eem, 2, "n")), Misc("DIFF_TERM=TRUE")), Subsignal("cs_n", Pins(_eem_pin(eem, 3, "n"))), iostandard(eem), ), From 69bf2dfb810a5fafb36e0b0fe7e41ebec6a913ec Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 2 Jun 2023 17:41:15 +0800 Subject: [PATCH 22/68] flake: sleep longer before running HITL tests to allow for clock switch and reboot --- flake.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index 4912a076b..fd11e0422 100644 --- a/flake.nix +++ b/flake.nix @@ -486,7 +486,7 @@ read LOCK_OK artiq_flash -t kc705 -H rpi-1 -d ${packages.x86_64-linux.artiq-board-kc705-nist_clock} - sleep 15 + sleep 30 export ARTIQ_ROOT=`python -c "import artiq; print(artiq.__path__[0])"`/examples/kc705_nist_clock export ARTIQ_LOW_LATENCY=1 From c298ec4c2e264e88fefdf79d0f0d201092ddf94e Mon Sep 17 00:00:00 2001 From: Florian Agbuya Date: Fri, 2 Jun 2023 18:14:57 +0800 Subject: [PATCH 23/68] applets: add update_dataset for dataset mods --- artiq/gui/applets.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/artiq/gui/applets.py b/artiq/gui/applets.py index f753b56b1..4b4bccce3 100644 --- a/artiq/gui/applets.py +++ b/artiq/gui/applets.py @@ -81,6 +81,8 @@ class AppletIPCServer(AsyncioParentComm): self.write_pyon({"action": "mod", "mod": mod}) elif action == "set_dataset": await self.dataset_ctl.set(obj["key"], obj["value"], obj["persist"]) + elif action == "update_dataset": + await self.dataset_ctl.update(obj["mod"]) else: raise ValueError("unknown action in applet message") except: From 150d325fc19c38b6abb1e90f6c29841561833c3d Mon Sep 17 00:00:00 2001 From: Florian Agbuya Date: Fri, 2 Jun 2023 18:15:59 +0800 Subject: [PATCH 24/68] applets.simple: add append_to_dataset feature --- artiq/applets/simple.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/artiq/applets/simple.py b/artiq/applets/simple.py index c9b512a56..80cab97f6 100644 --- a/artiq/applets/simple.py +++ b/artiq/applets/simple.py @@ -22,6 +22,10 @@ class AppletControlIPC: def set_dataset(self, key, value, persist=None): self.ipc.set_dataset(key, value, persist) + def append_to_dataset(self, key, value): + mod = {"action": "append", "path": [key, 1], "x": value} + self.ipc.update_dataset(mod) + class AppletControlRPC: def __init__(self, loop, dataset_ctl): @@ -37,6 +41,10 @@ class AppletControlRPC: def set_dataset(self, key, value, persist=None): self._background(self.dataset_ctl.set, key, value, persist) + def append_to_dataset(self, key, value): + mod = {"action": "append", "path": [key, 1], "x": value} + self._background(self.dataset_ctl.update, mod) + class AppletIPCClient(AsyncioChildComm): def set_close_cb(self, close_cb): @@ -102,6 +110,10 @@ class AppletIPCClient(AsyncioChildComm): "value": value, "persist": persist}) + def update_dataset(self, mod): + self.write_pyon({"action": "update_dataset", + "mod": mod}) + class SimpleApplet: def __init__(self, main_widget_class, cmd_description=None, From 1f306a2859b30cc2709db1e9f6720a7f65e1cf32 Mon Sep 17 00:00:00 2001 From: den512is <64661654+den512is@users.noreply.github.com> Date: Mon, 5 Jun 2023 08:17:47 +0300 Subject: [PATCH 25/68] flake: add packaging dependency Needed for building Kasli firmware --- flake.nix | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/flake.nix b/flake.nix index fd11e0422..33b5df443 100644 --- a/flake.nix +++ b/flake.nix @@ -224,7 +224,7 @@ }; }; nativeBuildInputs = [ - (pkgs.python3.withPackages(ps: [ migen misoc (artiq.withExperimentalFeatures experimentalFeatures) ])) + (pkgs.python3.withPackages(ps: [ migen misoc (artiq.withExperimentalFeatures experimentalFeatures) ps.packaging ])) rust pkgs.cargo-xbuild pkgs.llvmPackages_11.clang-unwrapped @@ -387,7 +387,7 @@ devShells.x86_64-linux.default = pkgs.mkShell { name = "artiq-dev-shell"; buildInputs = [ - (pkgs.python3.withPackages(ps: with packages.x86_64-linux; [ migen misoc ps.paramiko microscope ] ++ artiq.propagatedBuildInputs )) + (pkgs.python3.withPackages(ps: with packages.x86_64-linux; [ migen misoc ps.paramiko microscope ps.packaging ] ++ artiq.propagatedBuildInputs )) rust pkgs.cargo-xbuild pkgs.llvmPackages_11.clang-unwrapped @@ -415,7 +415,7 @@ devShells.x86_64-linux.boards = pkgs.mkShell { name = "artiq-boards-shell"; buildInputs = [ - (pkgs.python3.withPackages(ps: with packages.x86_64-linux; [ migen misoc artiq ])) + (pkgs.python3.withPackages(ps: with packages.x86_64-linux; [ migen misoc artiq ps.packaging ])) rust pkgs.cargo-xbuild pkgs.llvmPackages_11.clang-unwrapped From bf46ce4a923f16927e2e40bdc5980fd342157a47 Mon Sep 17 00:00:00 2001 From: Florian Agbuya Date: Mon, 5 Jun 2023 20:19:12 +0800 Subject: [PATCH 26/68] applets.simple: add mutate_dataset feature --- artiq/applets/simple.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/artiq/applets/simple.py b/artiq/applets/simple.py index 80cab97f6..8adb064d2 100644 --- a/artiq/applets/simple.py +++ b/artiq/applets/simple.py @@ -22,6 +22,10 @@ class AppletControlIPC: def set_dataset(self, key, value, persist=None): self.ipc.set_dataset(key, value, persist) + def mutate_dataset(self, key, index, value): + mod = {"action": "setitem", "path": [key, 1], "key": index, "value": value} + self.ipc.update_dataset(mod) + def append_to_dataset(self, key, value): mod = {"action": "append", "path": [key, 1], "x": value} self.ipc.update_dataset(mod) @@ -41,6 +45,10 @@ class AppletControlRPC: def set_dataset(self, key, value, persist=None): self._background(self.dataset_ctl.set, key, value, persist) + def mutate_dataset(self, key, index, value): + mod = {"action": "setitem", "path": [key, 1], "key": index, "value": value} + self._background(self.dataset_ctl.update, mod) + def append_to_dataset(self, key, value): mod = {"action": "append", "path": [key, 1], "x": value} self._background(self.dataset_ctl.update, mod) From 7ad32d903a42ce4687eaf4c4f18c5e6c4a6747ea Mon Sep 17 00:00:00 2001 From: Florian Agbuya Date: Tue, 6 Jun 2023 18:59:01 +0800 Subject: [PATCH 27/68] browser: add update method to dataset controller --- artiq/browser/datasets.py | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/artiq/browser/datasets.py b/artiq/browser/datasets.py index 76da6340e..2e4ed3884 100644 --- a/artiq/browser/datasets.py +++ b/artiq/browser/datasets.py @@ -28,21 +28,34 @@ class DatasetCtl: self.master_host = master_host self.master_port = master_port - async def set(self, key, value, persist=None): - logger.info("Uploading dataset '%s' to master...", key) + async def _execute_rpc(self, op_name, key_or_mod, value=None, persist=None): + logger.info("Starting %s operation on %s", op_name, key_or_mod) try: remote = RPCClient() await remote.connect_rpc(self.master_host, self.master_port, "master_dataset_db") try: - await remote.set(key, value, persist) + if op_name == "set": + await remote.set(key_or_mod, value, persist) + elif op_name == "update": + await remote.update(key_or_mod) + else: + logger.error("Invalid operation: %s", op_name) + return finally: remote.close_rpc() except: - logger.error("Failed uploading dataset '%s'", - key, exc_info=True) + logger.error("Failed %s operation on %s", op_name, + key_or_mod, exc_info=True) else: - logger.info("Finished uploading dataset '%s'", key) + logger.info("Finished %s operation on %s", op_name, + key_or_mod) + + async def set(self, key, value, persist=None): + await self._execute_rpc("set", key, value, persist) + + async def update(self, mod): + await self._execute_rpc("update", mod) class DatasetsDock(QtWidgets.QDockWidget): From 30ef8d8cb462a9bb8f6d9d377618d80698f009fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=81=AB=E7=84=9A=20=E5=AF=8C=E8=89=AF?= Date: Fri, 9 Jun 2023 13:24:10 +0800 Subject: [PATCH 28/68] compiler: skip demangling list of empty names --- artiq/compiler/targets.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/artiq/compiler/targets.py b/artiq/compiler/targets.py index df55e6bd8..0dd835a0a 100644 --- a/artiq/compiler/targets.py +++ b/artiq/compiler/targets.py @@ -256,6 +256,8 @@ class Target: return backtrace def demangle(self, names): + if not any(names): + return names with RunTool([self.tool_cxxfilt] + names) as results: return results["__stdout__"].read().rstrip().split("\n") From c25c0bd55a257be5f89eae2c2a3e8f0f98c9192b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=81=AB=E7=84=9A=20=E5=AF=8C=E8=89=AF?= Date: Fri, 9 Jun 2023 13:25:08 +0800 Subject: [PATCH 29/68] flake: update to LLVM 14 and llvmlite 0.40.0+master --- artiq/test/lit/embedding/syscall_arg_attrs.py | 4 +- artiq/test/lit/embedding/syscall_flags.py | 2 +- flake.nix | 46 ++++++++++++++----- 3 files changed, 37 insertions(+), 15 deletions(-) diff --git a/artiq/test/lit/embedding/syscall_arg_attrs.py b/artiq/test/lit/embedding/syscall_arg_attrs.py index 67207dc32..a20d90bed 100644 --- a/artiq/test/lit/embedding/syscall_arg_attrs.py +++ b/artiq/test/lit/embedding/syscall_arg_attrs.py @@ -18,13 +18,13 @@ def entrypoint(): return_str() -# CHECK: declare void @accept_str\({ i8\*, i32 }\* byval\) +# CHECK: declare void @accept_str\({ i8\*, i32 }\* byval\({ i8\*, i32 }\)\) @syscall def accept_str(name: TStr) -> TNone: pass -# CHECK: declare void @return_str\({ i8\*, i32 }\* sret\) +# CHECK: declare void @return_str\({ i8\*, i32 }\* sret\({ i8\*, i32 }\)\) @syscall def return_str() -> TStr: pass diff --git a/artiq/test/lit/embedding/syscall_flags.py b/artiq/test/lit/embedding/syscall_flags.py index cc78f843b..b2e27d6a0 100644 --- a/artiq/test/lit/embedding/syscall_flags.py +++ b/artiq/test/lit/embedding/syscall_flags.py @@ -15,7 +15,7 @@ def foo() -> TNone: # sret nowrite functions shouldn't be marked inaccessiblememonly. # CHECK-L: ; Function Attrs: nounwind -# CHECK-NEXT-L: declare void @bar({ i32, i64 }* sret) +# CHECK-NEXT-L: declare void @bar({ i32, i64 }* sret({ i32, i64 })) @syscall(flags={"nounwind", "nowrite"}) def bar() -> TTuple([TInt32, TInt64]): pass diff --git a/flake.nix b/flake.nix index 33b5df443..bf0ffa68c 100644 --- a/flake.nix +++ b/flake.nix @@ -111,6 +111,28 @@ ''; }; + llvmlite-new = pkgs.python3Packages.buildPythonPackage rec { + pname = "llvmlite"; + version = "0.40.0"; + src = pkgs.fetchFromGitHub { + owner = "numba"; + repo = "llvmlite"; + rev = "70f057b59a9d11de1c4d1792aabe6d5bf24eacc3"; + sha256 = "sha256-8t8fg8LnNC4wRPBcP0Il1ibHTBTqEd4mkis/CjsAO5c="; + }; + nativeBuildInputs = [ pkgs.llvm_14 ]; + # Disable static linking + # https://github.com/numba/llvmlite/issues/93 + postPatch = '' + substituteInPlace ffi/Makefile.linux --replace "-static-libstdc++" "" + substituteInPlace llvmlite/tests/test_binding.py --replace "test_linux" "nope" + ''; + # Set directory containing llvm-config binary + preConfigure = '' + export LLVM_CONFIG=${pkgs.llvm_14.dev}/bin/llvm-config + ''; + }; + artiq-upstream = pkgs.python3Packages.buildPythonPackage rec { pname = "artiq"; version = artiqVersion; @@ -124,8 +146,8 @@ nativeBuildInputs = [ pkgs.qt5.wrapQtAppsHook ]; # keep llvm_x and lld_x in sync with llvmlite - propagatedBuildInputs = [ pkgs.llvm_11 pkgs.lld_11 sipyco.packages.x86_64-linux.sipyco pythonparser pkgs.qt5.qtsvg artiq-comtools.packages.x86_64-linux.artiq-comtools ] - ++ (with pkgs.python3Packages; [ llvmlite pyqtgraph pygit2 numpy dateutil scipy prettytable pyserial levenshtein h5py pyqt5 qasync tqdm lmdb jsonschema ]); + propagatedBuildInputs = [ pkgs.llvm_14 pkgs.lld_11 sipyco.packages.x86_64-linux.sipyco pythonparser artiq-comtools.packages.x86_64-linux.artiq-comtools llvmlite-new ] + ++ (with pkgs.python3Packages; [ pyqtgraph pygit2 numpy dateutil scipy prettytable pyserial levenshtein h5py pyqt5 qasync tqdm lmdb jsonschema ]); dontWrapQtApps = true; postFixup = '' @@ -147,10 +169,10 @@ "--set FONTCONFIG_FILE ${pkgs.fontconfig.out}/etc/fonts/fonts.conf" ]; - # FIXME: automatically propagate lld_11 llvm_11 dependencies + # FIXME: automatically propagate lld_11 llvm_14 dependencies # cacert is required in the check stage only, as certificates are to be # obtained from system elsewhere - nativeCheckInputs = [ pkgs.lld_11 pkgs.llvm_11 libartiq-support pkgs.lit outputcheck pkgs.cacert ]; + nativeCheckInputs = [ pkgs.lld_11 pkgs.llvm_14 libartiq-support pkgs.lit outputcheck pkgs.cacert ]; checkPhase = '' python -m unittest discover -v artiq.test @@ -227,8 +249,8 @@ (pkgs.python3.withPackages(ps: [ migen misoc (artiq.withExperimentalFeatures experimentalFeatures) ps.packaging ])) rust pkgs.cargo-xbuild - pkgs.llvmPackages_11.clang-unwrapped - pkgs.llvm_11 + pkgs.llvmPackages_14.clang-unwrapped + pkgs.llvm_14 pkgs.lld_11 vivado rustPlatform.cargoSetupHook @@ -325,7 +347,7 @@ }; in rec { packages.x86_64-linux = { - inherit pythonparser qasync artiq; + inherit pythonparser llvmlite-new qasync artiq; inherit migen misoc asyncserial microscope vivadoEnv vivado; openocd-bscanspi = openocd-bscanspi-f pkgs; artiq-board-kc705-nist_clock = makeArtiqBoardPackage { @@ -390,8 +412,8 @@ (pkgs.python3.withPackages(ps: with packages.x86_64-linux; [ migen misoc ps.paramiko microscope ps.packaging ] ++ artiq.propagatedBuildInputs )) rust pkgs.cargo-xbuild - pkgs.llvmPackages_11.clang-unwrapped - pkgs.llvm_11 + pkgs.llvmPackages_14.clang-unwrapped + pkgs.llvm_14 pkgs.lld_11 # To manually run compiler tests: pkgs.lit @@ -418,8 +440,8 @@ (pkgs.python3.withPackages(ps: with packages.x86_64-linux; [ migen misoc artiq ps.packaging ])) rust pkgs.cargo-xbuild - pkgs.llvmPackages_11.clang-unwrapped - pkgs.llvm_11 + pkgs.llvmPackages_14.clang-unwrapped + pkgs.llvm_14 pkgs.lld_11 packages.x86_64-linux.vivado packages.x86_64-linux.openocd-bscanspi @@ -453,7 +475,7 @@ buildInputs = [ (pkgs.python3.withPackages(ps: with packages.x86_64-linux; [ artiq ps.paramiko ])) - pkgs.llvm_11 + pkgs.llvm_14 pkgs.lld_11 pkgs.openssh packages.x86_64-linux.openocd-bscanspi # for the bscanspi bitstreams From d140c960bb7005489730ce054aa9a90f3ced3c9f Mon Sep 17 00:00:00 2001 From: Florian Agbuya Date: Mon, 12 Jun 2023 17:52:46 +0800 Subject: [PATCH 30/68] applets: implement dataset modification feature in big number applet --- artiq/applets/big_number.py | 62 +++++++++++++++++++++++++++++++++---- 1 file changed, 56 insertions(+), 6 deletions(-) diff --git a/artiq/applets/big_number.py b/artiq/applets/big_number.py index b637847ff..d18b4f601 100755 --- a/artiq/applets/big_number.py +++ b/artiq/applets/big_number.py @@ -1,22 +1,72 @@ #!/usr/bin/env python3 -from PyQt5 import QtWidgets - +from PyQt5 import QtWidgets, QtCore, QtGui from artiq.applets.simple import SimpleApplet -class NumberWidget(QtWidgets.QLCDNumber): +class QResponsiveLCDNumber(QtWidgets.QLCDNumber): + doubleClicked = QtCore.pyqtSignal() + + def mouseDoubleClickEvent(self, event): + self.doubleClicked.emit() + + +class QCancellableLineEdit(QtWidgets.QLineEdit): + editCancelled = QtCore.pyqtSignal() + + def keyPressEvent(self, event): + if event.key() == QtCore.Qt.Key_Escape: + self.editCancelled.emit() + else: + super().keyPressEvent(event) + + +class NumberWidget(QtWidgets.QStackedWidget): def __init__(self, args, ctl): - QtWidgets.QLCDNumber.__init__(self) - self.setDigitCount(args.digit_count) + QtWidgets.QStackedWidget.__init__(self) self.dataset_name = args.dataset + self.ctl = ctl + + self.lcd_widget = QResponsiveLCDNumber() + self.lcd_widget.setDigitCount(args.digit_count) + self.lcd_widget.doubleClicked.connect(self.start_edit) + self.addWidget(self.lcd_widget) + + self.edit_widget = QCancellableLineEdit() + self.edit_widget.setValidator(QtGui.QDoubleValidator()) + self.edit_widget.setAlignment(QtCore.Qt.AlignRight) + self.edit_widget.editCancelled.connect(self.cancel_edit) + self.edit_widget.returnPressed.connect(self.confirm_edit) + self.addWidget(self.edit_widget) + + font = QtGui.QFont() + font.setPointSize(60) + self.edit_widget.setFont(font) + + self.setCurrentWidget(self.lcd_widget) + + def start_edit(self): + # QLCDNumber value property contains the value of zero + # if the displayed value is not a number. + self.edit_widget.setText(str(self.lcd_widget.value())) + self.edit_widget.selectAll() + self.edit_widget.setFocus() + self.setCurrentWidget(self.edit_widget) + + def confirm_edit(self): + value = float(self.edit_widget.text()) + self.ctl.set_dataset(self.dataset_name, value) + self.setCurrentWidget(self.lcd_widget) + + def cancel_edit(self): + self.setCurrentWidget(self.lcd_widget) def data_changed(self, data, mods): try: n = float(data[self.dataset_name][1]) except (KeyError, ValueError, TypeError): n = "---" - self.display(n) + self.lcd_widget.display(n) def main(): From 115415d1204a2c69f41aa4c35e187f8a30855b1d Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 14 Jun 2023 18:54:33 +0800 Subject: [PATCH 31/68] Revert "flake: update to LLVM 14 and llvmlite 0.40.0+master" This reverts commit c25c0bd55a257be5f89eae2c2a3e8f0f98c9192b. --- artiq/test/lit/embedding/syscall_arg_attrs.py | 4 +- artiq/test/lit/embedding/syscall_flags.py | 2 +- flake.nix | 46 +++++-------------- 3 files changed, 15 insertions(+), 37 deletions(-) diff --git a/artiq/test/lit/embedding/syscall_arg_attrs.py b/artiq/test/lit/embedding/syscall_arg_attrs.py index a20d90bed..67207dc32 100644 --- a/artiq/test/lit/embedding/syscall_arg_attrs.py +++ b/artiq/test/lit/embedding/syscall_arg_attrs.py @@ -18,13 +18,13 @@ def entrypoint(): return_str() -# CHECK: declare void @accept_str\({ i8\*, i32 }\* byval\({ i8\*, i32 }\)\) +# CHECK: declare void @accept_str\({ i8\*, i32 }\* byval\) @syscall def accept_str(name: TStr) -> TNone: pass -# CHECK: declare void @return_str\({ i8\*, i32 }\* sret\({ i8\*, i32 }\)\) +# CHECK: declare void @return_str\({ i8\*, i32 }\* sret\) @syscall def return_str() -> TStr: pass diff --git a/artiq/test/lit/embedding/syscall_flags.py b/artiq/test/lit/embedding/syscall_flags.py index b2e27d6a0..cc78f843b 100644 --- a/artiq/test/lit/embedding/syscall_flags.py +++ b/artiq/test/lit/embedding/syscall_flags.py @@ -15,7 +15,7 @@ def foo() -> TNone: # sret nowrite functions shouldn't be marked inaccessiblememonly. # CHECK-L: ; Function Attrs: nounwind -# CHECK-NEXT-L: declare void @bar({ i32, i64 }* sret({ i32, i64 })) +# CHECK-NEXT-L: declare void @bar({ i32, i64 }* sret) @syscall(flags={"nounwind", "nowrite"}) def bar() -> TTuple([TInt32, TInt64]): pass diff --git a/flake.nix b/flake.nix index bf0ffa68c..33b5df443 100644 --- a/flake.nix +++ b/flake.nix @@ -111,28 +111,6 @@ ''; }; - llvmlite-new = pkgs.python3Packages.buildPythonPackage rec { - pname = "llvmlite"; - version = "0.40.0"; - src = pkgs.fetchFromGitHub { - owner = "numba"; - repo = "llvmlite"; - rev = "70f057b59a9d11de1c4d1792aabe6d5bf24eacc3"; - sha256 = "sha256-8t8fg8LnNC4wRPBcP0Il1ibHTBTqEd4mkis/CjsAO5c="; - }; - nativeBuildInputs = [ pkgs.llvm_14 ]; - # Disable static linking - # https://github.com/numba/llvmlite/issues/93 - postPatch = '' - substituteInPlace ffi/Makefile.linux --replace "-static-libstdc++" "" - substituteInPlace llvmlite/tests/test_binding.py --replace "test_linux" "nope" - ''; - # Set directory containing llvm-config binary - preConfigure = '' - export LLVM_CONFIG=${pkgs.llvm_14.dev}/bin/llvm-config - ''; - }; - artiq-upstream = pkgs.python3Packages.buildPythonPackage rec { pname = "artiq"; version = artiqVersion; @@ -146,8 +124,8 @@ nativeBuildInputs = [ pkgs.qt5.wrapQtAppsHook ]; # keep llvm_x and lld_x in sync with llvmlite - propagatedBuildInputs = [ pkgs.llvm_14 pkgs.lld_11 sipyco.packages.x86_64-linux.sipyco pythonparser artiq-comtools.packages.x86_64-linux.artiq-comtools llvmlite-new ] - ++ (with pkgs.python3Packages; [ pyqtgraph pygit2 numpy dateutil scipy prettytable pyserial levenshtein h5py pyqt5 qasync tqdm lmdb jsonschema ]); + propagatedBuildInputs = [ pkgs.llvm_11 pkgs.lld_11 sipyco.packages.x86_64-linux.sipyco pythonparser pkgs.qt5.qtsvg artiq-comtools.packages.x86_64-linux.artiq-comtools ] + ++ (with pkgs.python3Packages; [ llvmlite pyqtgraph pygit2 numpy dateutil scipy prettytable pyserial levenshtein h5py pyqt5 qasync tqdm lmdb jsonschema ]); dontWrapQtApps = true; postFixup = '' @@ -169,10 +147,10 @@ "--set FONTCONFIG_FILE ${pkgs.fontconfig.out}/etc/fonts/fonts.conf" ]; - # FIXME: automatically propagate lld_11 llvm_14 dependencies + # FIXME: automatically propagate lld_11 llvm_11 dependencies # cacert is required in the check stage only, as certificates are to be # obtained from system elsewhere - nativeCheckInputs = [ pkgs.lld_11 pkgs.llvm_14 libartiq-support pkgs.lit outputcheck pkgs.cacert ]; + nativeCheckInputs = [ pkgs.lld_11 pkgs.llvm_11 libartiq-support pkgs.lit outputcheck pkgs.cacert ]; checkPhase = '' python -m unittest discover -v artiq.test @@ -249,8 +227,8 @@ (pkgs.python3.withPackages(ps: [ migen misoc (artiq.withExperimentalFeatures experimentalFeatures) ps.packaging ])) rust pkgs.cargo-xbuild - pkgs.llvmPackages_14.clang-unwrapped - pkgs.llvm_14 + pkgs.llvmPackages_11.clang-unwrapped + pkgs.llvm_11 pkgs.lld_11 vivado rustPlatform.cargoSetupHook @@ -347,7 +325,7 @@ }; in rec { packages.x86_64-linux = { - inherit pythonparser llvmlite-new qasync artiq; + inherit pythonparser qasync artiq; inherit migen misoc asyncserial microscope vivadoEnv vivado; openocd-bscanspi = openocd-bscanspi-f pkgs; artiq-board-kc705-nist_clock = makeArtiqBoardPackage { @@ -412,8 +390,8 @@ (pkgs.python3.withPackages(ps: with packages.x86_64-linux; [ migen misoc ps.paramiko microscope ps.packaging ] ++ artiq.propagatedBuildInputs )) rust pkgs.cargo-xbuild - pkgs.llvmPackages_14.clang-unwrapped - pkgs.llvm_14 + pkgs.llvmPackages_11.clang-unwrapped + pkgs.llvm_11 pkgs.lld_11 # To manually run compiler tests: pkgs.lit @@ -440,8 +418,8 @@ (pkgs.python3.withPackages(ps: with packages.x86_64-linux; [ migen misoc artiq ps.packaging ])) rust pkgs.cargo-xbuild - pkgs.llvmPackages_14.clang-unwrapped - pkgs.llvm_14 + pkgs.llvmPackages_11.clang-unwrapped + pkgs.llvm_11 pkgs.lld_11 packages.x86_64-linux.vivado packages.x86_64-linux.openocd-bscanspi @@ -475,7 +453,7 @@ buildInputs = [ (pkgs.python3.withPackages(ps: with packages.x86_64-linux; [ artiq ps.paramiko ])) - pkgs.llvm_14 + pkgs.llvm_11 pkgs.lld_11 pkgs.openssh packages.x86_64-linux.openocd-bscanspi # for the bscanspi bitstreams From 82bd913f63e3b756c128656946315061195d552a Mon Sep 17 00:00:00 2001 From: Spaqin Date: Fri, 16 Jun 2023 15:44:31 +0800 Subject: [PATCH 32/68] satellites: add kernel cpu --- artiq/build_soc.py | 20 ++++++++++---------- artiq/gateware/amp/soc.py | 1 + artiq/gateware/targets/kasli.py | 18 ++++++++++++++---- artiq/gateware/targets/kasli_generic.py | 4 +++- artiq/gateware/targets/kc705.py | 19 +++++++++++++++++-- 5 files changed, 45 insertions(+), 17 deletions(-) diff --git a/artiq/build_soc.py b/artiq/build_soc.py index bdf652948..f51c8885a 100644 --- a/artiq/build_soc.py +++ b/artiq/build_soc.py @@ -59,16 +59,16 @@ def build_artiq_soc(soc, argdict): builder.software_packages = [] builder.add_software_package("bootloader", os.path.join(firmware_dir, "bootloader")) is_kasli_v1 = isinstance(soc.platform, kasli.Platform) and soc.platform.hw_rev in ("v1.0", "v1.1") - if isinstance(soc, AMPSoC): - kernel_cpu_type = "vexriscv" if is_kasli_v1 else "vexriscv-g" - builder.add_software_package("libm", cpu_type=kernel_cpu_type) - builder.add_software_package("libprintf", cpu_type=kernel_cpu_type) - builder.add_software_package("libunwind", cpu_type=kernel_cpu_type) - builder.add_software_package("ksupport", os.path.join(firmware_dir, "ksupport"), cpu_type=kernel_cpu_type) - # Generate unwinder for soft float target (ARTIQ runtime) - # If the kernel lacks FPU, then the runtime unwinder is already generated - if not is_kasli_v1: - builder.add_software_package("libunwind") + kernel_cpu_type = "vexriscv" if is_kasli_v1 else "vexriscv-g" + builder.add_software_package("libm", cpu_type=kernel_cpu_type) + builder.add_software_package("libprintf", cpu_type=kernel_cpu_type) + builder.add_software_package("libunwind", cpu_type=kernel_cpu_type) + builder.add_software_package("ksupport", os.path.join(firmware_dir, "ksupport"), cpu_type=kernel_cpu_type) + # Generate unwinder for soft float target (ARTIQ runtime) + # If the kernel lacks FPU, then the runtime unwinder is already generated + if not is_kasli_v1: + builder.add_software_package("libunwind") + if not soc.config["DRTIO_ROLE"] == "satellite": builder.add_software_package("runtime", os.path.join(firmware_dir, "runtime")) else: # Assume DRTIO satellite. diff --git a/artiq/gateware/amp/soc.py b/artiq/gateware/amp/soc.py index 91b75ca3a..baba52151 100644 --- a/artiq/gateware/amp/soc.py +++ b/artiq/gateware/amp/soc.py @@ -36,6 +36,7 @@ class AMPSoC: csrs = getattr(self, name).get_csrs() csr_bus = wishbone.Interface(data_width=32, adr_width=32-log2_int(self.csr_separation)) bank = wishbone.CSRBank(csrs, bus=csr_bus) + self.config["kernel_has_"+name] = None self.submodules += bank self.kernel_cpu.add_wb_slave(self.mem_map[name], self.csr_separation*2**bank.decode_bits, bank.bus) self.add_csr_region(name, diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index d292d37d9..55baa6a03 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -406,9 +406,11 @@ class MasterBase(MiniSoC, AMPSoC): self.drtio_qpll_channel, self.ethphy_qpll_channel = qpll.channels -class SatelliteBase(BaseSoC): +class SatelliteBase(BaseSoC, AMPSoC): mem_map = { - "drtioaux": 0x50000000, + "rtio": 0x20000000, + "drtioaux": 0x50000000, + "mailbox": 0x70000000 } mem_map.update(BaseSoC.mem_map) @@ -417,6 +419,7 @@ class SatelliteBase(BaseSoC): cpu_bus_width = 32 else: cpu_bus_width = 64 + BaseSoC.__init__(self, cpu_type="vexriscv", hw_rev=hw_rev, @@ -426,6 +429,7 @@ class SatelliteBase(BaseSoC): clk_freq=rtio_clk_freq, rtio_sys_merge=True, **kwargs) + AMPSoC.__init__(self) add_identifier(self, gateware_identifier_str=gateware_identifier_str) platform = self.platform @@ -439,7 +443,7 @@ class SatelliteBase(BaseSoC): cdr_clk_out = self.platform.request("cdr_clk_clean") else: cdr_clk_out = self.platform.request("si5324_clkout") - + cdr_clk = Signal() self.platform.add_period_constraint(cdr_clk_out, 8.) @@ -574,12 +578,18 @@ class SatelliteBase(BaseSoC): self.submodules.rtio_moninj = rtio.MonInj(rtio_channels) self.csr_devices.append("rtio_moninj") + # satellite (master-controlled) RTIO self.submodules.local_io = SyncRTIO(self.rtio_tsc, rtio_channels, lane_count=sed_lanes) self.comb += self.drtiosat.async_errors.eq(self.local_io.async_errors) + + # subkernel RTIO + self.submodules.rtio = rtio.KernelInitiator(self.rtio_tsc) + self.register_kernel_cpu_csrdevice("rtio") + self.submodules.rtio_dma = rtio.DMA(self.get_native_sdram_if(), self.cpu_dw) self.csr_devices.append("rtio_dma") self.submodules.cri_con = rtio.CRIInterconnectShared( - [self.drtiosat.cri, self.rtio_dma.cri], + [self.drtiosat.cri, self.rtio_dma.cri, self.rtio.cri], [self.local_io.cri] + self.drtio_cri, enable_routing=True) self.csr_devices.append("cri_con") diff --git a/artiq/gateware/targets/kasli_generic.py b/artiq/gateware/targets/kasli_generic.py index 3fc50b661..ad07a9e7a 100755 --- a/artiq/gateware/targets/kasli_generic.py +++ b/artiq/gateware/targets/kasli_generic.py @@ -22,7 +22,7 @@ class GenericStandalone(StandaloneBase): hw_rev = description["hw_rev"] self.class_name_override = description["variant"] StandaloneBase.__init__(self, hw_rev=hw_rev, **kwargs) - + self.config["DRTIO_ROLE"] = description["base"] self.config["RTIO_FREQUENCY"] = "{:.1f}".format(description["rtio_frequency"]/1e6) if "ext_ref_frequency" in description: self.config["SI5324_EXT_REF"] = None @@ -76,6 +76,7 @@ class GenericMaster(MasterBase): rtio_clk_freq=description["rtio_frequency"], enable_sata=description["enable_sata_drtio"], **kwargs) + self.config["DRTIO_ROLE"] = description["base"] if "ext_ref_frequency" in description: self.config["SI5324_EXT_REF"] = None self.config["EXT_REF_FREQUENCY"] = "{:.1f}".format( @@ -113,6 +114,7 @@ class GenericSatellite(SatelliteBase): rtio_clk_freq=description["rtio_frequency"], enable_sata=description["enable_sata_drtio"], **kwargs) + self.config["DRTIO_ROLE"] = description["base"] if hw_rev == "v1.0": # EEM clock fan-out from Si5324, not MMCX self.comb += self.platform.request("clk_sel").eq(1) diff --git a/artiq/gateware/targets/kc705.py b/artiq/gateware/targets/kc705.py index 251b56661..884586f07 100755 --- a/artiq/gateware/targets/kc705.py +++ b/artiq/gateware/targets/kc705.py @@ -98,6 +98,8 @@ class _StandaloneBase(MiniSoC, AMPSoC): AMPSoC.__init__(self) add_identifier(self, gateware_identifier_str=gateware_identifier_str) + self.config["DRTIO_ROLE"] = "standalone" + if isinstance(self.platform.toolchain, XilinxVivadoToolchain): self.platform.toolchain.bitstream_commands.extend([ "set_property BITSTREAM.GENERAL.COMPRESS True [current_design]", @@ -194,6 +196,8 @@ class _MasterBase(MiniSoC, AMPSoC): AMPSoC.__init__(self) add_identifier(self, gateware_identifier_str=gateware_identifier_str) + self.config["DRTIO_ROLE"] = "master" + if isinstance(self.platform.toolchain, XilinxVivadoToolchain): self.platform.toolchain.bitstream_commands.extend([ "set_property BITSTREAM.GENERAL.COMPRESS True [current_design]", @@ -314,9 +318,11 @@ class _MasterBase(MiniSoC, AMPSoC): -class _SatelliteBase(BaseSoC): +class _SatelliteBase(BaseSoC, AMPSoC): mem_map = { + "rtio": 0x20000000, "drtioaux": 0x50000000, + "mailbox": 0x70000000 } mem_map.update(BaseSoC.mem_map) @@ -331,8 +337,11 @@ class _SatelliteBase(BaseSoC): clk_freq=clk_freq, rtio_sys_merge=True, **kwargs) + AMPSoC.__init__(self) add_identifier(self, gateware_identifier_str=gateware_identifier_str) + self.config["DRTIO_ROLE"] = "satellite" + if isinstance(self.platform.toolchain, XilinxVivadoToolchain): self.platform.toolchain.bitstream_commands.extend([ "set_property BITSTREAM.GENERAL.COMPRESS True [current_design]", @@ -453,12 +462,18 @@ class _SatelliteBase(BaseSoC): self.submodules.rtio_moninj = rtio.MonInj(rtio_channels) self.csr_devices.append("rtio_moninj") + # DRTIO self.submodules.local_io = SyncRTIO(self.rtio_tsc, rtio_channels) self.comb += self.drtiosat.async_errors.eq(self.local_io.async_errors) + + # subkernel RTIO + self.submodules.rtio = rtio.KernelInitiator(self.rtio_tsc) + self.register_kernel_cpu_csrdevice("rtio") + self.submodules.rtio_dma = rtio.DMA(self.get_native_sdram_if(), self.cpu_dw) self.csr_devices.append("rtio_dma") self.submodules.cri_con = rtio.CRIInterconnectShared( - [self.drtiosat.cri, self.rtio_dma.cri], + [self.drtiosat.cri, self.rtio_dma.cri, self.rtio.cri], [self.local_io.cri] + self.drtio_cri, enable_routing=True) self.csr_devices.append("cri_con") From 20d4712815377d153ceaaf9dae918d5113769c2a Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 16 Jun 2023 16:17:31 +0800 Subject: [PATCH 33/68] json: base -> drtio_role --- .../coredevice/coredevice_generic.schema.json | 9 +++- artiq/frontend/artiq_ddb_template.py | 46 ++++++++++--------- artiq/gateware/targets/kasli_generic.py | 16 ++++--- 3 files changed, 42 insertions(+), 29 deletions(-) diff --git a/artiq/coredevice/coredevice_generic.schema.json b/artiq/coredevice/coredevice_generic.schema.json index 3224d947f..d555b5fbd 100644 --- a/artiq/coredevice/coredevice_generic.schema.json +++ b/artiq/coredevice/coredevice_generic.schema.json @@ -26,9 +26,16 @@ "description": "Hardware revision" }, "base": { + "type": "string", + "enum": ["use_drtio_role", "standalone", "master", "satellite"], + "description": "Deprecated, use drtio_role instead", + "default": "use_drtio_role" + }, + "drtio_role": { "type": "string", "enum": ["standalone", "master", "satellite"], - "description": "SoC base; value depends on intended system topology" + "description": "Role that this device takes in a DRTIO network; 'standalone' means no DRTIO", + "default": "standalone" }, "ext_ref_frequency": { "type": "number", diff --git a/artiq/frontend/artiq_ddb_template.py b/artiq/frontend/artiq_ddb_template.py index b79d8f140..9e5ea1364 100755 --- a/artiq/frontend/artiq_ddb_template.py +++ b/artiq/frontend/artiq_ddb_template.py @@ -79,10 +79,10 @@ def process_header(output, description): class PeripheralManager: - def __init__(self, output, master_description): + def __init__(self, output, primary_description): self.counts = defaultdict(int) self.output = output - self.master_description = master_description + self.primary_description = primary_description def get_name(self, ty): count = self.counts[ty] @@ -237,7 +237,7 @@ class PeripheralManager: }}""", name=urukul_name, sync_device="\"ttl_{name}_sync\"".format(name=urukul_name) if synchronization else "None", - refclk=peripheral.get("refclk", self.master_description["rtio_frequency"]), + refclk=peripheral.get("refclk", self.primary_description["rtio_frequency"]), clk_sel=peripheral["clk_sel"]) dds = peripheral["dds"] pll_vco = peripheral.get("pll_vco") @@ -514,7 +514,7 @@ class PeripheralManager: }}""", urukul_name=urukul_name, urukul_channel=rtio_offset+next(channel), - refclk=peripheral.get("refclk", self.master_description["rtio_frequency"]), + refclk=peripheral.get("refclk", self.primary_description["rtio_frequency"]), clk_sel=peripheral["clk_sel"], pll_vco=",\n \"pll_vco\": {}".format(pll_vco) if pll_vco is not None else "", pll_n=peripheral["pll_n"], pll_en=peripheral.get("pll_en", 1)) @@ -637,30 +637,30 @@ class PeripheralManager: return 2 -def process(output, master_description, satellites): - base = master_description["base"] - if base not in ("standalone", "master"): - raise ValueError("Invalid master base") +def process(output, primary_description, satellites): + drtio_role = primary_description["drtio_role"] + if drtio_role not in ("standalone", "master"): + raise ValueError("Invalid primary node DRTIO role") - if base == "standalone" and satellites: + if drtio_role == "standalone" and satellites: raise ValueError("A standalone system cannot have satellites") - process_header(output, master_description) + process_header(output, primary_description) - pm = PeripheralManager(output, master_description) + pm = PeripheralManager(output, primary_description) - print("# {} peripherals".format(base), file=output) + print("# {} peripherals".format(drtio_role), file=output) rtio_offset = 0 - for peripheral in master_description["peripherals"]: + for peripheral in primary_description["peripherals"]: n_channels = pm.process(rtio_offset, peripheral) rtio_offset += n_channels - if base == "standalone": + if drtio_role == "standalone": n_channels = pm.add_board_leds(rtio_offset) rtio_offset += n_channels for destination, description in satellites: - if description["base"] != "satellite": - raise ValueError("Invalid base for satellite at destination {}".format(destination)) + if description["drtio_role"] != "satellite": + raise ValueError("Invalid DRTIO role for satellite at destination {}".format(destination)) print("# DEST#{} peripherals".format(destination), file=output) rtio_offset = destination << 16 @@ -675,8 +675,8 @@ def main(): parser.add_argument("--version", action="version", version="ARTIQ v{}".format(artiq_version), help="print the ARTIQ version number") - parser.add_argument("master_description", metavar="MASTER_DESCRIPTION", - help="JSON system description file for the standalone or master node") + parser.add_argument("primary_description", metavar="PRIMARY_DESCRIPTION", + help="JSON system description file for the primary (standalone or master) node") parser.add_argument("-o", "--output", help="output file, defaults to standard output if omitted") parser.add_argument("-s", "--satellite", nargs=2, action="append", @@ -686,18 +686,22 @@ def main(): args = parser.parse_args() - master_description = jsondesc.load(args.master_description) + primary_description = jsondesc.load(args.primary_description) + if primary_description["base"] != "use_drtio_role": + primary_description["drtio_role"] = primary_description["base"] satellites = [] for destination, description_path in args.satellite: satellite_description = jsondesc.load(description_path) + if satellite_description["base"] != "use_drtio_role": + satellite_description["drtio_role"] = satellite_description["base"] satellites.append((int(destination, 0), satellite_description)) if args.output is not None: with open(args.output, "w") as f: - process(f, master_description, satellites) + process(f, primary_description, satellites) else: - process(sys.stdout, master_description, satellites) + process(sys.stdout, primary_description, satellites) if __name__ == "__main__": diff --git a/artiq/gateware/targets/kasli_generic.py b/artiq/gateware/targets/kasli_generic.py index ad07a9e7a..62a56b9dd 100755 --- a/artiq/gateware/targets/kasli_generic.py +++ b/artiq/gateware/targets/kasli_generic.py @@ -22,7 +22,7 @@ class GenericStandalone(StandaloneBase): hw_rev = description["hw_rev"] self.class_name_override = description["variant"] StandaloneBase.__init__(self, hw_rev=hw_rev, **kwargs) - self.config["DRTIO_ROLE"] = description["base"] + self.config["DRTIO_ROLE"] = description["drtio_role"] self.config["RTIO_FREQUENCY"] = "{:.1f}".format(description["rtio_frequency"]/1e6) if "ext_ref_frequency" in description: self.config["SI5324_EXT_REF"] = None @@ -76,7 +76,7 @@ class GenericMaster(MasterBase): rtio_clk_freq=description["rtio_frequency"], enable_sata=description["enable_sata_drtio"], **kwargs) - self.config["DRTIO_ROLE"] = description["base"] + self.config["DRTIO_ROLE"] = description["drtio_role"] if "ext_ref_frequency" in description: self.config["SI5324_EXT_REF"] = None self.config["EXT_REF_FREQUENCY"] = "{:.1f}".format( @@ -114,7 +114,7 @@ class GenericSatellite(SatelliteBase): rtio_clk_freq=description["rtio_frequency"], enable_sata=description["enable_sata_drtio"], **kwargs) - self.config["DRTIO_ROLE"] = description["base"] + self.config["DRTIO_ROLE"] = description["drtio_role"] if hw_rev == "v1.0": # EEM clock fan-out from Si5324, not MMCX self.comb += self.platform.request("clk_sel").eq(1) @@ -150,6 +150,8 @@ def main(): help="Override ROM identifier") args = parser.parse_args() description = jsondesc.load(args.description) + if description["base"] != "use_drtio_role": + description["drtio_role"] = description["base"] min_artiq_version = description.get("min_artiq_version", "0") if Version(artiq_version) < Version(min_artiq_version): @@ -159,14 +161,14 @@ def main(): if description["target"] != "kasli": raise ValueError("Description is for a different target") - if description["base"] == "standalone": + if description["drtio_role"] == "standalone": cls = GenericStandalone - elif description["base"] == "master": + elif description["drtio_role"] == "master": cls = GenericMaster - elif description["base"] == "satellite": + elif description["drtio_role"] == "satellite": cls = GenericSatellite else: - raise ValueError("Invalid base") + raise ValueError("Invalid DRTIO role") soc = cls(description, gateware_identifier_str=args.gateware_identifier_str, **soc_kasli_argdict(args)) args.variant = description["variant"] From a792bc5456d944f2a54eec551a8844daccf1ad5d Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 16 Jun 2023 16:32:42 +0800 Subject: [PATCH 34/68] json: factor handling of deprecated 'base' --- artiq/coredevice/jsondesc.py | 3 +++ artiq/frontend/artiq_ddb_template.py | 4 ---- artiq/gateware/targets/kasli_generic.py | 2 -- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/artiq/coredevice/jsondesc.py b/artiq/coredevice/jsondesc.py index 58f14d8b0..f59fbf886 100644 --- a/artiq/coredevice/jsondesc.py +++ b/artiq/coredevice/jsondesc.py @@ -32,4 +32,7 @@ def load(description_path): global validator validator.validate(result) + if result["base"] != "use_drtio_role": + result["drtio_role"] = result["base"] + return result diff --git a/artiq/frontend/artiq_ddb_template.py b/artiq/frontend/artiq_ddb_template.py index 9e5ea1364..b0000e839 100755 --- a/artiq/frontend/artiq_ddb_template.py +++ b/artiq/frontend/artiq_ddb_template.py @@ -687,14 +687,10 @@ def main(): args = parser.parse_args() primary_description = jsondesc.load(args.primary_description) - if primary_description["base"] != "use_drtio_role": - primary_description["drtio_role"] = primary_description["base"] satellites = [] for destination, description_path in args.satellite: satellite_description = jsondesc.load(description_path) - if satellite_description["base"] != "use_drtio_role": - satellite_description["drtio_role"] = satellite_description["base"] satellites.append((int(destination, 0), satellite_description)) if args.output is not None: diff --git a/artiq/gateware/targets/kasli_generic.py b/artiq/gateware/targets/kasli_generic.py index 62a56b9dd..310cc1039 100755 --- a/artiq/gateware/targets/kasli_generic.py +++ b/artiq/gateware/targets/kasli_generic.py @@ -150,8 +150,6 @@ def main(): help="Override ROM identifier") args = parser.parse_args() description = jsondesc.load(args.description) - if description["base"] != "use_drtio_role": - description["drtio_role"] = description["base"] min_artiq_version = description.get("min_artiq_version", "0") if Version(artiq_version) < Version(min_artiq_version): From 77293d53e3c4c13ce68f459ddf9d3f7a78456630 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 16 Jun 2023 16:59:08 +0800 Subject: [PATCH 35/68] json: use schema defaults when applicable --- .../coredevice/coredevice_generic.schema.json | 20 ++++++++++++++----- artiq/frontend/artiq_ddb_template.py | 20 +++++++++---------- artiq/gateware/eem_7series.py | 4 ++-- artiq/gateware/targets/kasli_generic.py | 2 +- 4 files changed, 28 insertions(+), 18 deletions(-) diff --git a/artiq/coredevice/coredevice_generic.schema.json b/artiq/coredevice/coredevice_generic.schema.json index d555b5fbd..66b54d5fc 100644 --- a/artiq/coredevice/coredevice_generic.schema.json +++ b/artiq/coredevice/coredevice_generic.schema.json @@ -19,7 +19,8 @@ }, "min_artiq_version": { "type": "string", - "description": "Minimum required ARTIQ version" + "description": "Minimum required ARTIQ version", + "default": "0" }, "hw_rev": { "type": "string", @@ -211,7 +212,8 @@ "type": "object", "properties": { "name": { - "type": "string" + "type": "string", + "default": "dio_spi" }, "clk": { "type": "integer", @@ -247,7 +249,8 @@ "type": "object", "properties": { "name": { - "type": "string" + "type": "string", + "default": "ttl" }, "pin": { "type": "integer", @@ -264,7 +267,8 @@ } }, "required": ["pin", "direction"] - } + }, + "default": [] } }, "required": ["ports", "spi"] @@ -391,7 +395,8 @@ }, "sampler_hw_rev": { "type": "string", - "pattern": "^v[0-9]+\\.[0-9]+" + "pattern": "^v[0-9]+\\.[0-9]+", + "default": "v2.2" }, "urukul0_ports": { "type": "array", @@ -573,6 +578,11 @@ }, "minItems": 1, "maxItems": 1 + }, + "mode": { + "type": "string", + "enum": ["base", "miqro"], + "default": "base" } }, "required": ["ports"] diff --git a/artiq/frontend/artiq_ddb_template.py b/artiq/frontend/artiq_ddb_template.py index b0000e839..40e193e8f 100755 --- a/artiq/frontend/artiq_ddb_template.py +++ b/artiq/frontend/artiq_ddb_template.py @@ -115,7 +115,7 @@ class PeripheralManager: name=name[i], class_name=classes[i // 4], channel=rtio_offset + next(channel)) - if peripheral.get("edge_counter", False): + if peripheral["edge_counter"]: for i in range(num_channels): class_name = classes[i // 4] if class_name == "TTLInOut": @@ -140,14 +140,14 @@ class PeripheralManager: "class": "SPIMaster", "arguments": {{"channel": 0x{channel:06x}}} }}""", - name=self.get_name(spi.get("name", "dio_spi")), + name=self.get_name(spi["name"]), channel=rtio_offset + next(channel)) - for ttl in peripheral.get("ttl", []): + for ttl in peripheral["ttl"]: ttl_class_names = { "input": "TTLInOut", "output": "TTLOut" } - name = self.get_name(ttl.get("name", "ttl")) + name = self.get_name(ttl["name"]) self.gen(""" device_db["{name}"] = {{ "type": "local", @@ -158,7 +158,7 @@ class PeripheralManager: name=name, class_name=ttl_class_names[ttl["direction"]], channel=rtio_offset + next(channel)) - if ttl.get("edge_counter", False): + if ttl["edge_counter"]: self.gen(""" device_db["{name}_counter"] = {{ "type": "local", @@ -260,7 +260,7 @@ class PeripheralManager: uchn=i, sw=",\n \"sw_device\": \"ttl_{name}_sw{uchn}\"".format(name=urukul_name, uchn=i) if len(peripheral["ports"]) > 1 else "", pll_vco=",\n \"pll_vco\": {}".format(pll_vco) if pll_vco is not None else "", - pll_n=peripheral.get("pll_n", 32), pll_en=peripheral.get("pll_en", 1), + pll_n=peripheral.get("pll_n", 32), pll_en=peripheral["pll_en"], sync_delay_seed=",\n \"sync_delay_seed\": \"eeprom_{}:{}\"".format(urukul_name, 64 + 4*i) if synchronization else "", io_update_delay=",\n \"io_update_delay\": \"eeprom_{}:{}\"".format(urukul_name, 64 + 4*i) if synchronization else "") elif dds == "ad9912": @@ -281,7 +281,7 @@ class PeripheralManager: uchn=i, sw=",\n \"sw_device\": \"ttl_{name}_sw{uchn}\"".format(name=urukul_name, uchn=i) if len(peripheral["ports"]) > 1 else "", pll_vco=",\n \"pll_vco\": {}".format(pll_vco) if pll_vco is not None else "", - pll_n=peripheral.get("pll_n", 8), pll_en=peripheral.get("pll_en", 1)) + pll_n=peripheral.get("pll_n", 8), pll_en=peripheral["pll_en"]) else: raise ValueError return next(channel) @@ -469,7 +469,7 @@ class PeripheralManager: }}""", suservo_name=suservo_name, sampler_name=sampler_name, - sampler_hw_rev=peripheral.get("sampler_hw_rev", "v2.2"), + sampler_hw_rev=peripheral["sampler_hw_rev"], cpld_names_list=[urukul_name + "_cpld" for urukul_name in urukul_names], dds_names_list=[urukul_name + "_dds" for urukul_name in urukul_names], suservo_channel=rtio_offset+next(channel)) @@ -517,7 +517,7 @@ class PeripheralManager: refclk=peripheral.get("refclk", self.primary_description["rtio_frequency"]), clk_sel=peripheral["clk_sel"], pll_vco=",\n \"pll_vco\": {}".format(pll_vco) if pll_vco is not None else "", - pll_n=peripheral["pll_n"], pll_en=peripheral.get("pll_en", 1)) + pll_n=peripheral["pll_n"], pll_en=peripheral["pll_en"]) return next(channel) def process_zotino(self, rtio_offset, peripheral): @@ -582,7 +582,7 @@ class PeripheralManager: return 1 def process_phaser(self, rtio_offset, peripheral): - mode = peripheral.get("mode", "base") + mode = peripheral["mode"] if mode == "miqro": dac = f', "dac": {{"pll_m": 16, "pll_n": 3, "interpolation": 2}}, "gw_rev": {PHASER_GW_MIQRO}' n_channels = 3 diff --git a/artiq/gateware/eem_7series.py b/artiq/gateware/eem_7series.py index e5980b980..18cb12791 100644 --- a/artiq/gateware/eem_7series.py +++ b/artiq/gateware/eem_7series.py @@ -31,7 +31,7 @@ def peripheral_dio_spi(module, peripheral, **kwargs): for s in peripheral["spi"]] ttl = [(t["pin"], ttl_classes[t["direction"]], edge_counter.SimpleEdgeCounter if t.get("edge_counter") else None) - for t in peripheral.get("ttl", [])] + for t in peripheral["ttl"]] eem.DIO_SPI.add_std(module, peripheral["ports"][0], spi, ttl, **kwargs) @@ -124,7 +124,7 @@ def peripheral_phaser(module, peripheral, **kwargs): if len(peripheral["ports"]) != 1: raise ValueError("wrong number of ports") eem.Phaser.add_std(module, peripheral["ports"][0], - peripheral.get("mode", "base"), **kwargs) + peripheral["base"], **kwargs) def peripheral_hvamp(module, peripheral, **kwargs): diff --git a/artiq/gateware/targets/kasli_generic.py b/artiq/gateware/targets/kasli_generic.py index 310cc1039..e6df0b293 100755 --- a/artiq/gateware/targets/kasli_generic.py +++ b/artiq/gateware/targets/kasli_generic.py @@ -151,7 +151,7 @@ def main(): args = parser.parse_args() description = jsondesc.load(args.description) - min_artiq_version = description.get("min_artiq_version", "0") + min_artiq_version = description["min_artiq_version"] if Version(artiq_version) < Version(min_artiq_version): logger.warning("ARTIQ version mismatch: current %s < %s minimum", artiq_version, min_artiq_version) From 454597915af820c94f8828a9e6cbcba03a03e600 Mon Sep 17 00:00:00 2001 From: Florian Agbuya Date: Tue, 13 Jun 2023 10:24:12 +0800 Subject: [PATCH 36/68] RELEASE_NOTES: update --- RELEASE_NOTES.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/RELEASE_NOTES.rst b/RELEASE_NOTES.rst index 13f378a81..9bc85f9bd 100644 --- a/RELEASE_NOTES.rst +++ b/RELEASE_NOTES.rst @@ -27,6 +27,7 @@ Highlights: * Full Python 3.10 support. * Distributed DMA is now supported, allowing DMA to be run directly on satellites for corresponding RTIO events, increasing bandwidth in scenarios with heavy satellite usage. +* API extensions have been implemented, enabling applets to directly modify datasets. * Persistent datasets are now stored in a LMDB database for improved performance. PYON databases can be converted with the script below. @@ -42,6 +43,11 @@ Highlights: txn.put(key.encode(), pyon.encode(value).encode()) new.close() +Breaking changes: + +* ``SimpleApplet`` now calls widget constructors with an additional ``ctl`` parameter for control + operations, which includes dataset operations. It can be ignored if not needed. For an example usage, + refer to the ``big_number.py`` applet. ARTIQ-7 From 833fd8760e316ddd93f1202501994b872b4def3c Mon Sep 17 00:00:00 2001 From: Leon Riesebos <28567817+lriesebos@users.noreply.github.com> Date: Mon, 26 Jun 2023 12:59:20 -0400 Subject: [PATCH 37/68] artiq_ddb_template: use the clk_div field this field exists in the json schema but was not used. Signed-off-by: Leon Riesebos <28567817+lriesebos@users.noreply.github.com> --- artiq/coredevice/coredevice_generic.schema.json | 3 ++- artiq/frontend/artiq_ddb_template.py | 6 ++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/artiq/coredevice/coredevice_generic.schema.json b/artiq/coredevice/coredevice_generic.schema.json index 66b54d5fc..a695c3850 100644 --- a/artiq/coredevice/coredevice_generic.schema.json +++ b/artiq/coredevice/coredevice_generic.schema.json @@ -308,7 +308,8 @@ "clk_div": { "type": "integer", "minimum": 0, - "maximum": 3 + "maximum": 3, + "default": 0 }, "pll_n": { "type": "integer" diff --git a/artiq/frontend/artiq_ddb_template.py b/artiq/frontend/artiq_ddb_template.py index 40e193e8f..15dcbf642 100755 --- a/artiq/frontend/artiq_ddb_template.py +++ b/artiq/frontend/artiq_ddb_template.py @@ -232,13 +232,15 @@ class PeripheralManager: "sync_device": {sync_device}, "io_update_device": "ttl_{name}_io_update", "refclk": {refclk}, - "clk_sel": {clk_sel} + "clk_sel": {clk_sel}, + "clk_div": {clk_div} }} }}""", name=urukul_name, sync_device="\"ttl_{name}_sync\"".format(name=urukul_name) if synchronization else "None", refclk=peripheral.get("refclk", self.primary_description["rtio_frequency"]), - clk_sel=peripheral["clk_sel"]) + clk_sel=peripheral["clk_sel"], + clk_div=peripheral["clk_div"]) dds = peripheral["dds"] pll_vco = peripheral.get("pll_vco") for i in range(4): From 748707e1579282a6d756344371f3131c4226e356 Mon Sep 17 00:00:00 2001 From: Simon Renblad Date: Tue, 13 Jun 2023 11:46:49 +0800 Subject: [PATCH 38/68] environment: add unit feature --- artiq/language/environment.py | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/artiq/language/environment.py b/artiq/language/environment.py index d3ccaf77d..bc5761feb 100644 --- a/artiq/language/environment.py +++ b/artiq/language/environment.py @@ -337,13 +337,21 @@ class HasEnvironment: self.kernel_invariants = kernel_invariants | {key} @rpc(flags={"async"}) - def set_dataset(self, key, value, + def set_dataset(self, key, value, *, + unit=None, scale=None, precision=None, broadcast=False, persist=False, archive=True): """Sets the contents and handling modes of a dataset. Datasets must be scalars (``bool``, ``int``, ``float`` or NumPy scalar) or NumPy arrays. + :param unit: A string representing the unit of the value. + :param scale: A numerical factor that is used to adjust the value of + the dataset to match the scale or units of the experiment's + reference frame when the value is displayed. + :param precision: The maximum number of digits to print after the + decimal point. Set ``precision=None`` to print as many digits as + necessary to uniquely specify the value. Uses IEEE unbiased rounding. :param broadcast: the data is sent in real-time to the master, which dispatches it. :param persist: the master should store the data on-disk. Implies @@ -351,7 +359,14 @@ class HasEnvironment: :param archive: the data is saved into the local storage of the current run (archived as a HDF5 file). """ - self.__dataset_mgr.set(key, value, broadcast, persist, archive) + metadata = {} + if unit is not None: + metadata["unit"] = unit + if scale is not None: + metadata["scale"] = scale + if precision is not None: + metadata["precision"] = precision + self.__dataset_mgr.set(key, value, metadata, broadcast, persist, archive) @rpc(flags={"async"}) def mutate_dataset(self, key, index, value): From 337273acb6a9a0c73b43d54e6c83aedf60341c7c Mon Sep 17 00:00:00 2001 From: Simon Renblad Date: Mon, 19 Jun 2023 12:40:45 +0800 Subject: [PATCH 39/68] environment: add get_dataset_metadata --- artiq/language/environment.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/artiq/language/environment.py b/artiq/language/environment.py index bc5761feb..bc0229998 100644 --- a/artiq/language/environment.py +++ b/artiq/language/environment.py @@ -420,6 +420,24 @@ class HasEnvironment: else: return default + def get_dataset_metadata(self, key, default=NoDefault): + """Returns the metadata of a dataset. + + Returns dictionary with items describing the dataset, including the units, + scale and precision. + + This function is used to get additional information for displaying the dataset. + + See ``set_dataset`` for documentation of metadata items. + """ + try: + return self.__dataset_mgr.get_metadata(key) + except KeyError: + if default is NoDefault: + raise + else: + return default + def setattr_dataset(self, key, default=NoDefault, archive=True): """Sets the contents of a dataset as attribute. The names of the dataset and of the attribute are the same.""" From bf38fc8b0fc475c51164368728396ff45b012b30 Mon Sep 17 00:00:00 2001 From: Simon Renblad Date: Mon, 3 Jul 2023 11:36:44 +0800 Subject: [PATCH 40/68] tools: refactor short_format with metadata --- artiq/tools.py | 39 ++++++++++++++++++++++++++++++--------- 1 file changed, 30 insertions(+), 9 deletions(-) diff --git a/artiq/tools.py b/artiq/tools.py index 1c4949a23..c0c49620e 100644 --- a/artiq/tools.py +++ b/artiq/tools.py @@ -15,6 +15,7 @@ from sipyco import pyon from artiq import __version__ as artiq_version from artiq.appdirs import user_config_dir from artiq.language.environment import is_public_experiment +from artiq.language import units __all__ = ["parse_arguments", "elide", "short_format", "file_import", @@ -54,20 +55,40 @@ def elide(s, maxlen): return s -def short_format(v): +def short_format(v, metadata={}): + m = metadata + unit = m.get("unit", "") + default_scale = getattr(units, unit, 1) + scale = m.get("scale", default_scale) + precision = m.get("precision", None) if v is None: return "None" t = type(v) - if np.issubdtype(t, np.number) or np.issubdtype(t, np.bool_): - return str(v) + if np.issubdtype(t, np.number): + v_t = np.divide(v, scale) + v_str = np.format_float_positional(v_t, + precision=precision, + unique=True) + v_str += " " + unit if unit else "" + return v_str + elif np.issubdtype(t, np.bool_): + return str(v) elif np.issubdtype(t, np.unicode_): return "\"" + elide(v, 50) + "\"" - else: - r = t.__name__ - if t is list or t is dict or t is set: - r += " ({})".format(len(v)) - if t is np.ndarray: - r += " " + str(np.shape(v)) + elif t is np.ndarray: + v_t = np.divide(v, scale) + v_str = np.array2string(v_t, + max_line_width=1000, + precision=precision, + suppress_small=True, + separator=', ', + threshold=4, + edgeitems=2, + floatmode='maxprec') + v_str += " " + unit if unit else "" + return v_str + elif isinstance(v, (dict, list)): + r = t.__name__ + " ({})".format(len(v)) return r From bfbe13e51b8c188416ba76e1bb3ade2f5910f63a Mon Sep 17 00:00:00 2001 From: Simon Renblad Date: Fri, 30 Jun 2023 16:54:39 +0800 Subject: [PATCH 41/68] worker_db: write hdf5 dataset metadata --- artiq/master/worker_db.py | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/artiq/master/worker_db.py b/artiq/master/worker_db.py index 015a125fa..5da202b2f 100644 --- a/artiq/master/worker_db.py +++ b/artiq/master/worker_db.py @@ -111,11 +111,12 @@ class DatasetManager: self._broadcaster = Notifier(dict()) self.local = dict() self.archive = dict() + self.metadata = dict() self.ddb = ddb self._broadcaster.publish = ddb.update - def set(self, key, value, broadcast=False, persist=False, archive=True): + def set(self, key, value, metadata, broadcast, persist, archive): if persist: broadcast = True @@ -123,7 +124,7 @@ class DatasetManager: logger.warning(f"Dataset '{key}' will not be stored. Both 'broadcast' and 'archive' are set to False.") if broadcast: - self._broadcaster[key] = persist, value + self._broadcaster[key] = persist, value, metadata elif key in self._broadcaster.raw_view: del self._broadcaster[key] @@ -131,6 +132,8 @@ class DatasetManager: self.local[key] = value elif key in self.local: del self.local[key] + + self.metadata[key] = metadata def _get_mutation_target(self, key): target = self.local.get(key, None) @@ -166,21 +169,30 @@ class DatasetManager: self.archive[key] = data return data + def get_metadata(self, key): + if key in self.metadata: + return self.metadata[key] + return self.ddb.get_metadata(key) + def write_hdf5(self, f): datasets_group = f.create_group("datasets") for k, v in self.local.items(): - _write(datasets_group, k, v) + m = self.metadata.get(k, {}) + _write(datasets_group, k, v, m) archive_group = f.create_group("archive") for k, v in self.archive.items(): - _write(archive_group, k, v) + m = self.metadata.get(k, {}) + _write(archive_group, k, v, m) -def _write(group, k, v): +def _write(group, k, v, m): # Add context to exception message when the user writes a dataset that is # not representable in HDF5. try: group[k] = v + for key, val in m.items(): + group[k].attrs[key] = val except TypeError as e: raise TypeError("Error writing dataset '{}' of type '{}': {}".format( k, type(v), e)) From e710d4baddafa87aec6b5c2c04c8586ed6dd7678 Mon Sep 17 00:00:00 2001 From: Simon Renblad Date: Tue, 4 Jul 2023 17:45:03 +0800 Subject: [PATCH 42/68] databases: read and save metadata in lmdb --- artiq/master/databases.py | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/artiq/master/databases.py b/artiq/master/databases.py index 68b494f76..db5760d31 100644 --- a/artiq/master/databases.py +++ b/artiq/master/databases.py @@ -45,8 +45,9 @@ class DatasetDB(TaskObject): self.lmdb = lmdb.open(persist_file, subdir=False, map_size=2**30) data = dict() with self.lmdb.begin() as txn: - for key, value in txn.cursor(): - data[key.decode()] = (True, pyon.decode(value.decode())) + for key, value_and_metadata in txn.cursor(): + value, metadata = pyon.decode(value_and_metadata.decode()) + data[key.decode()] = (True, value, metadata) self.data = Notifier(data) self.pending_keys = set() @@ -59,7 +60,10 @@ class DatasetDB(TaskObject): if key not in self.data.raw_view or not self.data.raw_view[key][0]: txn.delete(key.encode()) else: - txn.put(key.encode(), pyon.encode(self.data.raw_view[key][1]).encode()) + value_and_metadata = (self.data.raw_view[key][1], + self.data.raw_view[key][2]) + txn.put(key.encode(), + pyon.encode(value_and_metadata).encode()) self.pending_keys.clear() async def _do(self): @@ -73,6 +77,9 @@ class DatasetDB(TaskObject): def get(self, key): return self.data.raw_view[key][1] + def get_metadata(self, key): + return self.data.raw_view[key][2] + def update(self, mod): if mod["path"]: key = mod["path"][0] @@ -83,13 +90,18 @@ class DatasetDB(TaskObject): process_mod(self.data, mod) # convenience functions (update() can be used instead) - def set(self, key, value, persist=None): + def set(self, key, value, persist=None, metadata=None): if persist is None: if key in self.data.raw_view: persist = self.data.raw_view[key][0] else: persist = False - self.data[key] = (persist, value) + if metadata is None: + if key in self.data.raw_view: + metadata = self.data.raw_view[key][2] + else: + metadata = {} + self.data[key] = (persist, value, metadata) self.pending_keys.add(key) def delete(self, key): From 376f36c965f62d7ff01b89ade6a7f98152680187 Mon Sep 17 00:00:00 2001 From: Simon Renblad Date: Mon, 3 Jul 2023 12:27:47 +0800 Subject: [PATCH 43/68] datasets: add metadata format param --- artiq/dashboard/datasets.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/dashboard/datasets.py b/artiq/dashboard/datasets.py index f512c3d74..253d21495 100644 --- a/artiq/dashboard/datasets.py +++ b/artiq/dashboard/datasets.py @@ -100,7 +100,7 @@ class Model(DictSyncTreeSepModel): if column == 1: return "Y" if v[0] else "N" elif column == 2: - return short_format(v[1]) + return short_format(v[1], v[2]) else: raise ValueError From 1af98727b7e7dc7cbdc12a4d99de389ceb2faea1 Mon Sep 17 00:00:00 2001 From: Simon Renblad Date: Fri, 30 Jun 2023 13:44:19 +0800 Subject: [PATCH 44/68] test_scheduler: refactor dataset metadata support --- artiq/test/test_scheduler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/test/test_scheduler.py b/artiq/test/test_scheduler.py index 9726190ed..cc913c658 100644 --- a/artiq/test/test_scheduler.py +++ b/artiq/test/test_scheduler.py @@ -288,7 +288,7 @@ class SchedulerCase(unittest.TestCase): self.assertEqual( mod, {"action": "setitem", "key": "termination_ok", - "value": (False, True), "path": []}) + "value": (False, True, {}), "path": []}) termination_ok = True handlers = { "update_dataset": check_termination From 373fe3dbe7e3363e292ab2e914e0e0461e04ffb5 Mon Sep 17 00:00:00 2001 From: Simon Renblad Date: Fri, 30 Jun 2023 13:47:11 +0800 Subject: [PATCH 45/68] test_datasets: add metadata tests --- artiq/test/test_datasets.py | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/artiq/test/test_datasets.py b/artiq/test/test_datasets.py index 871568a2a..74e658323 100644 --- a/artiq/test/test_datasets.py +++ b/artiq/test/test_datasets.py @@ -16,6 +16,9 @@ class MockDatasetDB: def get(self, key): return self.data[key][1] + def get_metadata(self, key): + return self.data[key][2] + def update(self, mod): # Copy mod before applying to avoid sharing references to objects # between this and the DatasetManager, which would lead to mods being @@ -30,6 +33,9 @@ class TestExperiment(EnvExperiment): def get(self, key): return self.get_dataset(key) + def get_metadata(self, key): + return self.get_dataset_metadata(key) + def set(self, key, value, **kwargs): self.set_dataset(key, value, **kwargs) @@ -82,9 +88,9 @@ class ExperimentDatasetCase(unittest.TestCase): def test_append_broadcast(self): self.exp.set(KEY, [], broadcast=True) self.exp.append(KEY, 0) - self.assertEqual(self.dataset_db.data[KEY][1], [0]) + self.assertEqual(self.dataset_db.get(KEY), [0]) self.exp.append(KEY, 1) - self.assertEqual(self.dataset_db.data[KEY][1], [0, 1]) + self.assertEqual(self.dataset_db.get(KEY), [0, 1]) def test_append_array(self): for broadcast in (True, False): @@ -103,3 +109,26 @@ class ExperimentDatasetCase(unittest.TestCase): with self.assertRaises(KeyError): self.exp.append(KEY, 0) + def test_set_dataset_metadata(self): + self.exp.set(KEY, 0, unit="kV", precision=2) + md = {"unit": "kV", "precision": 2} + self.assertEqual(self.exp.get_metadata(KEY), md) + + def test_metadata_default(self): + self.exp.set(KEY, 0) + self.assertEqual(self.exp.get_metadata(KEY), {}) + + def test_metadata_scale(self): + self.exp.set(KEY, 0, scale=1000) + self.assertEqual(self.exp.get_metadata(KEY), {"scale": 1000}) + + def test_metadata_broadcast(self): + self.exp.set(KEY, 0, unit="kV", precision=2, broadcast=True) + md = {"unit": "kV", "precision": 2} + self.assertEqual(self.dataset_db.get_metadata(KEY), md) + + def test_metadata_broadcast_default(self): + self.exp.set(KEY, 0, broadcast=True) + self.assertEqual(self.dataset_db.get_metadata(KEY), {}) + + From 7ca02a119dd70f14dd6f134ad8765da05f74992a Mon Sep 17 00:00:00 2001 From: Simon Renblad Date: Thu, 6 Jul 2023 11:19:06 +0800 Subject: [PATCH 46/68] RELEASE_NOTES: update lmdb migrate script --- RELEASE_NOTES.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASE_NOTES.rst b/RELEASE_NOTES.rst index 9bc85f9bd..93a36612a 100644 --- a/RELEASE_NOTES.rst +++ b/RELEASE_NOTES.rst @@ -40,7 +40,7 @@ Highlights: new = lmdb.open("dataset_db.mdb", subdir=False, map_size=2**30) with new.begin(write=True) as txn: for key, value in old.items(): - txn.put(key.encode(), pyon.encode(value).encode()) + txn.put(key.encode(), pyon.encode((value, {})).encode()) new.close() Breaking changes: From 93882eb3cefc42fb02d8b91594e56db2a1531a9e Mon Sep 17 00:00:00 2001 From: den512 Date: Tue, 27 Jun 2023 13:10:33 +0800 Subject: [PATCH 47/68] kasli-soc: fix of SYS CLK switch failure Change initialization behaviour of GTX transceivers -- Modify the config parms CPLL of GTX transceiver for PLL to lock correctly Modify the enabling requirement of GTX input clock buffer IBUFDS_GTE2 so that it depends on GTX PLL locked signal instead of TX Init Done Modify the GTX Init FSM so that BruteForceClock Aligner can reset GTX transceiver without resetting the GTX transceiver PLL kasli-soc: fix of SYS CLK switch failure Changed initialization of GTX transceivers. Successful SYS CLK switching requires IBUFDS_GTE2 to be properly enabled and not disabled during GTX transceiver initialization. For this reason, CPLL is not reset during GTX initialization and clock alignment. kasli-soc: refractor fix of SYS CLK switch failure Remove gtXxreset & cpllreset assertion and deassertion The removed code does not affect the fix --- artiq/gateware/drtio/transceiver/gtx_7series.py | 4 +++- .../gateware/drtio/transceiver/gtx_7series_init.py | 13 +++++++++---- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/artiq/gateware/drtio/transceiver/gtx_7series.py b/artiq/gateware/drtio/transceiver/gtx_7series.py index a1872e8ae..f62663895 100644 --- a/artiq/gateware/drtio/transceiver/gtx_7series.py +++ b/artiq/gateware/drtio/transceiver/gtx_7series.py @@ -74,6 +74,8 @@ class GTX_20X(Module): p_CPLL_REFCLK_DIV=1, p_RXOUT_DIV=2, p_TXOUT_DIV=2, + p_CPLL_INIT_CFG=0x00001E, + p_CPLL_LOCK_CFG=0x01C0, i_CPLLRESET=cpllreset, i_CPLLPD=cpllreset, o_CPLLLOCK=cplllock, @@ -320,7 +322,7 @@ class GTX(Module, TransceiverInterface): # stable_clkin resets after reboot since it's in SYS domain # still need to keep clk_enable high after this - self.sync.bootstrap += clk_enable.eq(self.stable_clkin.storage | self.gtxs[0].tx_init.done) + self.sync.bootstrap += clk_enable.eq(self.stable_clkin.storage | self.gtxs[0].tx_init.cplllock) # Connect slave i's `rtio_rx` clock to `rtio_rxi` clock for i in range(nchannels): diff --git a/artiq/gateware/drtio/transceiver/gtx_7series_init.py b/artiq/gateware/drtio/transceiver/gtx_7series_init.py index 5552c308f..0e30ee27c 100644 --- a/artiq/gateware/drtio/transceiver/gtx_7series_init.py +++ b/artiq/gateware/drtio/transceiver/gtx_7series_init.py @@ -110,9 +110,9 @@ class GTXInit(Module): startup_fsm.act("INITIAL", startup_timer.wait.eq(1), - If(startup_timer.done & self.stable_clkin, NextState("RESET_ALL")) + If(startup_timer.done & self.stable_clkin, NextState("RESET_PLL")) ) - startup_fsm.act("RESET_ALL", + startup_fsm.act("RESET_PLL", gtXxreset.eq(1), self.cpllreset.eq(1), pll_reset_timer.wait.eq(1), @@ -120,7 +120,12 @@ class GTXInit(Module): ) startup_fsm.act("RELEASE_PLL_RESET", gtXxreset.eq(1), - If(cplllock, NextState("RELEASE_GTH_RESET")) + If(cplllock, NextState("RESET_GTH")) + ) + startup_fsm.act("RESET_GTH", + gtXxreset.eq(1), + pll_reset_timer.wait.eq(1), + If(pll_reset_timer.done, NextState("RELEASE_GTH_RESET")) ) # Release GTX reset and wait for GTX resetdone # (from UG476, GTX is reset on falling edge @@ -229,7 +234,7 @@ class GTXInit(Module): startup_fsm.act("READY", Xxuserrdy.eq(1), self.done.eq(1), - If(self.restart, NextState("RESET_ALL")) + If(self.restart, NextState("RESET_GTH")) ) From 48bc8a2eccd20138c2e902443fe6a60a89ab2dc9 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 10 Jul 2023 11:26:07 +0800 Subject: [PATCH 48/68] gtx_7series_init: GTH -> GTX (NFC) --- artiq/gateware/drtio/transceiver/gtx_7series_init.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/artiq/gateware/drtio/transceiver/gtx_7series_init.py b/artiq/gateware/drtio/transceiver/gtx_7series_init.py index 0e30ee27c..6f1bff15e 100644 --- a/artiq/gateware/drtio/transceiver/gtx_7series_init.py +++ b/artiq/gateware/drtio/transceiver/gtx_7series_init.py @@ -120,24 +120,24 @@ class GTXInit(Module): ) startup_fsm.act("RELEASE_PLL_RESET", gtXxreset.eq(1), - If(cplllock, NextState("RESET_GTH")) + If(cplllock, NextState("RESET_GTX")) ) - startup_fsm.act("RESET_GTH", + startup_fsm.act("RESET_GTX", gtXxreset.eq(1), pll_reset_timer.wait.eq(1), - If(pll_reset_timer.done, NextState("RELEASE_GTH_RESET")) + If(pll_reset_timer.done, NextState("RELEASE_GTX_RESET")) ) # Release GTX reset and wait for GTX resetdone # (from UG476, GTX is reset on falling edge # of gttxreset) if rx: - startup_fsm.act("RELEASE_GTH_RESET", + startup_fsm.act("RELEASE_GTX_RESET", Xxuserrdy.eq(1), cdr_stable_timer.wait.eq(1), If(Xxresetdone & cdr_stable_timer.done, NextState("DELAY_ALIGN")) ) else: - startup_fsm.act("RELEASE_GTH_RESET", + startup_fsm.act("RELEASE_GTX_RESET", Xxuserrdy.eq(1), If(Xxresetdone, NextState("DELAY_ALIGN")) ) @@ -234,7 +234,7 @@ class GTXInit(Module): startup_fsm.act("READY", Xxuserrdy.eq(1), self.done.eq(1), - If(self.restart, NextState("RESET_GTH")) + If(self.restart, NextState("RESET_GTX")) ) From 7791f85a1a3b98a6e3e6a01963dfab84d3b2dfe1 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 10 Jul 2023 11:29:59 +0800 Subject: [PATCH 49/68] flake: update dependencies --- flake.lock | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/flake.lock b/flake.lock index 1467860ca..e64b7c60a 100644 --- a/flake.lock +++ b/flake.lock @@ -42,11 +42,11 @@ "mozilla-overlay": { "flake": false, "locked": { - "lastModified": 1684487559, - "narHash": "sha256-SZcJEM+NnLr8ctzeQf1BGAqBHzJ3jn+tdSeO7lszIJc=", + "lastModified": 1687771476, + "narHash": "sha256-TSpqz6qYVRoqkEdOCawEQ4/cWt/4pracmvw17HK1tgE=", "owner": "mozilla", "repo": "nixpkgs-mozilla", - "rev": "e6ca26fe8b9df914d4567604e426fbc185d9ef3e", + "rev": "3a44b8783514e7d6db4b63df96071b6c2b014b07", "type": "github" }, "original": { @@ -57,11 +57,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1685356226, - "narHash": "sha256-f2clSOdqi0SvY1WSgbnl2YgCZmoCXOxeUjYeXp8p2zI=", + "lastModified": 1688868408, + "narHash": "sha256-RR9N5XTAxSBhK8MCvLq9uxfdkd7etC//seVXldy0k48=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "0f7f5ca1cdec8dea85bb4fa60378258171d019ad", + "rev": "510d721ce097150ae3b80f84b04b13b039186571", "type": "github" }, "original": { @@ -89,11 +89,11 @@ ] }, "locked": { - "lastModified": 1685094262, - "narHash": "sha256-7DvbdTUYP7PbhZClT/tob66iMV95v7124RynMpPc5VA=", + "lastModified": 1685540542, + "narHash": "sha256-wQJwL3xc6QVQbiJrt71/Z9tp4Eq1yqdGddcEiv7sPCw=", "owner": "m-labs", "repo": "sipyco", - "rev": "f1f0fc1d3071c5a6ba6dd613b54bb4176ad1e8dc", + "rev": "f5bf2ba875340a31a135aea14ad184575ca800ac", "type": "github" }, "original": { From 5292a8de82f678962d1a1993bbbcd0cde0a5b1c1 Mon Sep 17 00:00:00 2001 From: Simon Renblad Date: Mon, 10 Jul 2023 10:48:06 +0800 Subject: [PATCH 50/68] browser: add metadata param to short_format --- artiq/browser/datasets.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/browser/datasets.py b/artiq/browser/datasets.py index 2e4ed3884..cbeb6afec 100644 --- a/artiq/browser/datasets.py +++ b/artiq/browser/datasets.py @@ -20,7 +20,7 @@ class Model(DictSyncTreeSepModel): DictSyncTreeSepModel.__init__(self, ".", ["Dataset", "Value"], init) def convert(self, k, v, column): - return short_format(v[1]) + return short_format(v[1], v[2]) class DatasetCtl: From 50a6dac178716ee7850ba4745a7b32e28a3ca02d Mon Sep 17 00:00:00 2001 From: Simon Renblad Date: Mon, 10 Jul 2023 10:52:47 +0800 Subject: [PATCH 51/68] files: read dataset metadata from HDF5 --- artiq/browser/files.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/artiq/browser/files.py b/artiq/browser/files.py index a714cb696..d155ca5dc 100644 --- a/artiq/browser/files.py +++ b/artiq/browser/files.py @@ -194,7 +194,9 @@ class FilesDock(QtWidgets.QDockWidget): if "archive" in f: def visitor(k, v): if isinstance(v, h5py.Dataset): - rd[k] = (True, v[()]) + # v.attrs is a non-serializable h5py.AttributeManager, need to convert to dict + # See https://docs.h5py.org/en/stable/high/attr.html#h5py.AttributeManager + rd[k] = (True, v[()], dict(v.attrs)) f["archive"].visititems(visitor) @@ -204,7 +206,9 @@ class FilesDock(QtWidgets.QDockWidget): if k in rd: logger.warning("dataset '%s' is both in archive " "and outputs", k) - rd[k] = (True, v[()]) + # v.attrs is a non-serializable h5py.AttributeManager, need to convert to dict + # See https://docs.h5py.org/en/stable/high/attr.html#h5py.AttributeManager + rd[k] = (True, v[()], dict(v.attrs)) f["datasets"].visititems(visitor) From 91442e2914ac259f0a9083eb2dbf90bc228855a3 Mon Sep 17 00:00:00 2001 From: Simon Renblad Date: Mon, 10 Jul 2023 11:02:21 +0800 Subject: [PATCH 52/68] browser: refactor upload_clicked for dataset metadata --- artiq/browser/datasets.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/artiq/browser/datasets.py b/artiq/browser/datasets.py index cbeb6afec..815f7acbf 100644 --- a/artiq/browser/datasets.py +++ b/artiq/browser/datasets.py @@ -28,7 +28,7 @@ class DatasetCtl: self.master_host = master_host self.master_port = master_port - async def _execute_rpc(self, op_name, key_or_mod, value=None, persist=None): + async def _execute_rpc(self, op_name, key_or_mod, value=None, persist=None, metadata=None): logger.info("Starting %s operation on %s", op_name, key_or_mod) try: remote = RPCClient() @@ -36,7 +36,7 @@ class DatasetCtl: "master_dataset_db") try: if op_name == "set": - await remote.set(key_or_mod, value, persist) + await remote.set(key_or_mod, value, persist, metadata) elif op_name == "update": await remote.update(key_or_mod) else: @@ -51,8 +51,8 @@ class DatasetCtl: logger.info("Finished %s operation on %s", op_name, key_or_mod) - async def set(self, key, value, persist=None): - await self._execute_rpc("set", key, value, persist) + async def set(self, key, value, persist=None, metadata=None): + await self._execute_rpc("set", key, value, persist, metadata) async def update(self, mod): await self._execute_rpc("update", mod) @@ -122,8 +122,8 @@ class DatasetsDock(QtWidgets.QDockWidget): idx = self.table_model_filter.mapToSource(idx[0]) key = self.table_model.index_to_key(idx) if key is not None: - persist, value = self.table_model.backing_store[key] - asyncio.ensure_future(self.dataset_ctl.set(key, value)) + persist, value, metadata = self.table_model.backing_store[key] + asyncio.ensure_future(self.dataset_ctl.set(key, value, metadata=metadata)) def save_state(self): return bytes(self.table.header().saveState()) From 3663a6b8e84a9b58563c28d1ec7f932aa7419a82 Mon Sep 17 00:00:00 2001 From: Simon Renblad Date: Mon, 10 Jul 2023 11:47:27 +0800 Subject: [PATCH 53/68] artiq_client: refactor set_dataset, show_datasets --- artiq/frontend/artiq_client.py | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/artiq/frontend/artiq_client.py b/artiq/frontend/artiq_client.py index bdd751e43..b3eb6438d 100755 --- a/artiq/frontend/artiq_client.py +++ b/artiq/frontend/artiq_client.py @@ -91,6 +91,12 @@ def get_argparser(): help="name of the dataset") parser_set_dataset.add_argument("value", metavar="VALUE", help="value in PYON format") + parser_set_dataset.add_argument("--unit", default=None, type=str, + help="physical unit of the dataset") + parser_set_dataset.add_argument("--scale", default=None, type=float, + help="factor to multiply value of dataset in displays") + parser_set_dataset.add_argument("--precision", default=None, type=int, + help="maximum number of decimals to print in displays") persist_group = parser_set_dataset.add_mutually_exclusive_group() persist_group.add_argument("-p", "--persist", action="store_true", @@ -174,7 +180,14 @@ def _action_set_dataset(remote, args): persist = True if args.no_persist: persist = False - remote.set(args.name, pyon.decode(args.value), persist) + metadata = {} + if args.unit is not None: + metadata["unit"] = args.unit + if args.scale is not None: + metadata["scale"] = args.scale + if args.precision is not None: + metadata["precision"] = args.precision + remote.set(args.name, pyon.decode(args.value), persist, metadata) def _action_del_dataset(remote, args): @@ -246,8 +259,8 @@ def _show_devices(devices): def _show_datasets(datasets): clear_screen() table = PrettyTable(["Dataset", "Persistent", "Value"]) - for k, (persist, value) in sorted(datasets.items(), key=itemgetter(0)): - table.add_row([k, "Y" if persist else "N", short_format(value)]) + for k, (persist, value, metadata) in sorted(datasets.items(), key=itemgetter(0)): + table.add_row([k, "Y" if persist else "N", short_format(value, metadata)]) print(table) From faf85e815a8a8d5fd4cac467bd0b7d0784ea15a5 Mon Sep 17 00:00:00 2001 From: Simon Renblad Date: Mon, 10 Jul 2023 13:13:34 +0800 Subject: [PATCH 54/68] datasets: add metadata to CreateEditDialog --- artiq/dashboard/datasets.py | 50 +++++++++++++++++++++++++++++-------- 1 file changed, 39 insertions(+), 11 deletions(-) diff --git a/artiq/dashboard/datasets.py b/artiq/dashboard/datasets.py index 253d21495..2d08ce39c 100644 --- a/artiq/dashboard/datasets.py +++ b/artiq/dashboard/datasets.py @@ -14,14 +14,14 @@ from artiq.gui.scientific_spinbox import ScientificSpinBox logger = logging.getLogger(__name__) -async def rename(key, new_key, value, persist, dataset_ctl): +async def rename(key, new_key, value, metadata, persist, dataset_ctl): if key != new_key: await dataset_ctl.delete(key) - await dataset_ctl.set(new_key, value, persist) + await dataset_ctl.set(new_key, value, metadata=metadata, persist=persist) class CreateEditDialog(QtWidgets.QDialog): - def __init__(self, parent, dataset_ctl, key=None, value=None, persist=False): + def __init__(self, parent, dataset_ctl, key=None, value=None, metadata=None, persist=False): QtWidgets.QDialog.__init__(self, parent=parent) self.dataset_ctl = dataset_ctl @@ -43,9 +43,21 @@ class CreateEditDialog(QtWidgets.QDialog): grid.addWidget(self.data_type, 1, 2) self.value_widget.textChanged.connect(self.dtype) - grid.addWidget(QtWidgets.QLabel("Persist:"), 2, 0) + grid.addWidget(QtWidgets.QLabel("Unit:"), 2, 0) + self.unit_widget = QtWidgets.QLineEdit() + grid.addWidget(self.unit_widget, 2, 1) + + grid.addWidget(QtWidgets.QLabel("Scale:"), 3, 0) + self.scale_widget = QtWidgets.QLineEdit() + grid.addWidget(self.scale_widget, 3, 1) + + grid.addWidget(QtWidgets.QLabel("Precision:"), 4, 0) + self.precision_widget = QtWidgets.QLineEdit() + grid.addWidget(self.precision_widget, 4, 1) + + grid.addWidget(QtWidgets.QLabel("Persist:"), 5, 0) self.box_widget = QtWidgets.QCheckBox() - grid.addWidget(self.box_widget, 2, 1) + grid.addWidget(self.box_widget, 5, 1) self.ok = QtWidgets.QPushButton('&Ok') self.ok.setEnabled(False) @@ -55,24 +67,40 @@ class CreateEditDialog(QtWidgets.QDialog): self.ok, QtWidgets.QDialogButtonBox.AcceptRole) self.buttons.addButton( self.cancel, QtWidgets.QDialogButtonBox.RejectRole) - grid.setRowStretch(3, 1) - grid.addWidget(self.buttons, 4, 0, 1, 3, alignment=QtCore.Qt.AlignHCenter) + grid.setRowStretch(6, 1) + grid.addWidget(self.buttons, 7, 0, 1, 3, alignment=QtCore.Qt.AlignHCenter) self.buttons.accepted.connect(self.accept) self.buttons.rejected.connect(self.reject) self.key = key self.name_widget.setText(key) self.value_widget.setText(value) + + if metadata is not None: + self.unit_widget.setText(metadata.get('unit', '')) + self.scale_widget.setText(str(metadata.get('scale', ''))) + self.precision_widget.setText(str(metadata.get('precision', ''))) + self.box_widget.setChecked(persist) def accept(self): key = self.name_widget.text() value = self.value_widget.text() persist = self.box_widget.isChecked() + unit = self.unit_widget.text() + scale = self.scale_widget.text() + precision = self.precision_widget.text() + metadata = {} + if unit != "": + metadata['unit'] = unit + if scale != "": + metadata['scale'] = float(scale) + if precision != "": + metadata['precision'] = int(precision) if self.key and self.key != key: - asyncio.ensure_future(exc_to_warning(rename(self.key, key, pyon.decode(value), persist, self.dataset_ctl))) + asyncio.ensure_future(exc_to_warning(rename(self.key, key, pyon.decode(value), metadata, persist, self.dataset_ctl))) else: - asyncio.ensure_future(exc_to_warning(self.dataset_ctl.set(key, pyon.decode(value), persist))) + asyncio.ensure_future(exc_to_warning(self.dataset_ctl.set(key, pyon.decode(value), metadata=metadata, persist=persist))) self.key = key QtWidgets.QDialog.accept(self) @@ -168,7 +196,7 @@ class DatasetsDock(QtWidgets.QDockWidget): idx = self.table_model_filter.mapToSource(idx[0]) key = self.table_model.index_to_key(idx) if key is not None: - persist, value = self.table_model.backing_store[key] + persist, value, metadata = self.table_model.backing_store[key] t = type(value) if np.issubdtype(t, np.number) or np.issubdtype(t, np.bool_): value = str(value) @@ -176,7 +204,7 @@ class DatasetsDock(QtWidgets.QDockWidget): value = '"{}"'.format(str(value)) else: value = pyon.encode(value) - CreateEditDialog(self, self.dataset_ctl, key, value, persist).open() + CreateEditDialog(self, self.dataset_ctl, key, value, metadata, persist).open() def delete_clicked(self): idx = self.table.selectedIndexes() From 9a84575649735b3fb2f1f100f349a3e06c657955 Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Wed, 12 Jul 2023 00:09:15 +0100 Subject: [PATCH 55/68] eem_7series: fix typo in 77293d5 Signed-off-by: Jonathan Coates --- artiq/gateware/eem_7series.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/eem_7series.py b/artiq/gateware/eem_7series.py index 18cb12791..84276ad79 100644 --- a/artiq/gateware/eem_7series.py +++ b/artiq/gateware/eem_7series.py @@ -124,7 +124,7 @@ def peripheral_phaser(module, peripheral, **kwargs): if len(peripheral["ports"]) != 1: raise ValueError("wrong number of ports") eem.Phaser.add_std(module, peripheral["ports"][0], - peripheral["base"], **kwargs) + peripheral["mode"], **kwargs) def peripheral_hvamp(module, peripheral, **kwargs): From af7622d7abd8e37b42bca056a499a69189c524f3 Mon Sep 17 00:00:00 2001 From: Simon Renblad Date: Wed, 12 Jul 2023 10:20:00 +0800 Subject: [PATCH 56/68] simple: refactor IPC set_dataset --- artiq/applets/simple.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/artiq/applets/simple.py b/artiq/applets/simple.py index 8adb064d2..7aab32b05 100644 --- a/artiq/applets/simple.py +++ b/artiq/applets/simple.py @@ -19,8 +19,15 @@ class AppletControlIPC: def __init__(self, ipc): self.ipc = ipc - def set_dataset(self, key, value, persist=None): - self.ipc.set_dataset(key, value, persist) + def set_dataset(self, key, value, unit=None, scale=None, precision=None, persist=None): + metadata = {} + if unit is not None: + metadata["unit"] = unit + if scale is not None: + metadata["scale"] = scale + if precision is not None: + metadata["precision"] = precision + self.ipc.set_dataset(key, value, metadata, persist) def mutate_dataset(self, key, index, value): mod = {"action": "setitem", "path": [key, 1], "key": index, "value": value} @@ -112,10 +119,11 @@ class AppletIPCClient(AsyncioChildComm): self.mod_cb = mod_cb self.listen_task = loop.create_task(self.listen()) - def set_dataset(self, key, value, persist=None): + def set_dataset(self, key, value, metadata, persist=None): self.write_pyon({"action": "set_dataset", "key": key, "value": value, + "metadata": metadata, "persist": persist}) def update_dataset(self, mod): From 16a3ce274f5ae5e9509c78388ab5c23873aa8548 Mon Sep 17 00:00:00 2001 From: Simon Renblad Date: Wed, 12 Jul 2023 10:32:14 +0800 Subject: [PATCH 57/68] applets: add metadata param to set_dataset --- artiq/gui/applets.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gui/applets.py b/artiq/gui/applets.py index 4b4bccce3..a9e22b420 100644 --- a/artiq/gui/applets.py +++ b/artiq/gui/applets.py @@ -80,7 +80,7 @@ class AppletIPCServer(AsyncioParentComm): self.dataset_sub.model.backing_store) self.write_pyon({"action": "mod", "mod": mod}) elif action == "set_dataset": - await self.dataset_ctl.set(obj["key"], obj["value"], obj["persist"]) + await self.dataset_ctl.set(obj["key"], obj["value"], metadata=obj["metadata"], persist=obj["persist"]) elif action == "update_dataset": await self.dataset_ctl.update(obj["mod"]) else: From d1f2727126b64fe8eb983ec9b70b6480bbcdd87a Mon Sep 17 00:00:00 2001 From: Simon Renblad Date: Wed, 12 Jul 2023 10:33:22 +0800 Subject: [PATCH 58/68] simple: refactor RPC client set_dataset --- artiq/applets/simple.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/artiq/applets/simple.py b/artiq/applets/simple.py index 7aab32b05..c04abeb87 100644 --- a/artiq/applets/simple.py +++ b/artiq/applets/simple.py @@ -49,8 +49,15 @@ class AppletControlRPC: self.background_tasks.add(task) task.add_done_callback(self.background_tasks.discard) - def set_dataset(self, key, value, persist=None): - self._background(self.dataset_ctl.set, key, value, persist) + def set_dataset(self, key, value, unit=None, scale=None, precision=None, persist=None): + metadata = {} + if unit is not None: + metadata["unit"] = unit + if scale is not None: + metadata["scale"] = scale + if precision is not None: + metadata["precision"] = precision + self._background(self.dataset_ctl.set, key, value, metadata=metadata, persist=persist) def mutate_dataset(self, key, index, value): mod = {"action": "setitem", "path": [key, 1], "key": index, "value": value} From fe0f6d8a2c0d71bd7c7be8e559eef620e6f308d8 Mon Sep 17 00:00:00 2001 From: Simon Renblad Date: Wed, 12 Jul 2023 11:34:55 +0800 Subject: [PATCH 59/68] simple: refactor SimpleApplet data_changed signature --- artiq/applets/simple.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/artiq/applets/simple.py b/artiq/applets/simple.py index c04abeb87..eb03766dc 100644 --- a/artiq/applets/simple.py +++ b/artiq/applets/simple.py @@ -270,7 +270,12 @@ class SimpleApplet: return False def emit_data_changed(self, data, mod_buffer): - self.main_widget.data_changed(data, mod_buffer) + persist = dict() + value = dict() + metadata = dict() + for k, d in data.items(): + persist[k], value[k], metadata[k] = d + self.main_widget.data_changed(value, metadata, persist, mod_buffer) def flush_mod_buffer(self): self.emit_data_changed(self.data, self.mod_buffer) From 5695e9f77e1bdd29a5e9d50bbdaabdf35d9a2c13 Mon Sep 17 00:00:00 2001 From: Simon Renblad Date: Wed, 12 Jul 2023 11:35:18 +0800 Subject: [PATCH 60/68] simple: refactor TitleApplet data_changed signature --- artiq/applets/simple.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/artiq/applets/simple.py b/artiq/applets/simple.py index eb03766dc..c7c7c81df 100644 --- a/artiq/applets/simple.py +++ b/artiq/applets/simple.py @@ -364,4 +364,9 @@ class TitleApplet(SimpleApplet): title = self.args.title else: title = None - self.main_widget.data_changed(data, mod_buffer, title) + persist = dict() + value = dict() + metadata = dict() + for k, d in data.items(): + persist[k], value[k], metadata[k] = d + self.main_widget.data_changed(value, metadata, persist, mod_buffer, title) From 25959d0cd6fc01536064af48822207ffad3e8684 Mon Sep 17 00:00:00 2001 From: Simon Renblad Date: Wed, 12 Jul 2023 12:03:29 +0800 Subject: [PATCH 61/68] big_number: refactor data_changed --- artiq/applets/big_number.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/applets/big_number.py b/artiq/applets/big_number.py index d18b4f601..a085ce8e4 100755 --- a/artiq/applets/big_number.py +++ b/artiq/applets/big_number.py @@ -61,9 +61,9 @@ class NumberWidget(QtWidgets.QStackedWidget): def cancel_edit(self): self.setCurrentWidget(self.lcd_widget) - def data_changed(self, data, mods): + def data_changed(self, value, metadata, persist, mods): try: - n = float(data[self.dataset_name][1]) + n = float(value[self.dataset_name]) except (KeyError, ValueError, TypeError): n = "---" self.lcd_widget.display(n) From b6a83904b5bc67c57d3f5eb57d0431e52a46667e Mon Sep 17 00:00:00 2001 From: Simon Renblad Date: Wed, 12 Jul 2023 12:03:54 +0800 Subject: [PATCH 62/68] image: refactor data_changed --- artiq/applets/image.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/applets/image.py b/artiq/applets/image.py index 7a192bcda..36af01cab 100755 --- a/artiq/applets/image.py +++ b/artiq/applets/image.py @@ -11,9 +11,9 @@ class Image(pyqtgraph.ImageView): pyqtgraph.ImageView.__init__(self) self.args = args - def data_changed(self, data, mods): + def data_changed(self, value, metadata, persist, mods): try: - img = data[self.args.img][1] + img = value[self.args.img] except KeyError: return self.setImage(img) From ac504069d226f1fcd20cc23abe1dce04723d20f4 Mon Sep 17 00:00:00 2001 From: Simon Renblad Date: Wed, 12 Jul 2023 12:04:22 +0800 Subject: [PATCH 63/68] plot_hist: refactor data_changed --- artiq/applets/plot_hist.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/artiq/applets/plot_hist.py b/artiq/applets/plot_hist.py index 9dbebcf4c..3be604930 100755 --- a/artiq/applets/plot_hist.py +++ b/artiq/applets/plot_hist.py @@ -15,13 +15,13 @@ class HistogramPlot(pyqtgraph.PlotWidget): self.timer.setSingleShot(True) self.timer.timeout.connect(self.length_warning) - def data_changed(self, data, mods, title): + def data_changed(self, value, metadata, persist, mods, title): try: - y = data[self.args.y][1] + y = value[self.args.y] if self.args.x is None: x = None else: - x = data[self.args.x][1] + x = value[self.args.x] except KeyError: return if x is None: From c17f69a51b78dea681bfeeca3b47d06d3357b79b Mon Sep 17 00:00:00 2001 From: Simon Renblad Date: Wed, 12 Jul 2023 12:04:50 +0800 Subject: [PATCH 64/68] plot_xy: refactor data_changed --- artiq/applets/plot_xy.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/artiq/applets/plot_xy.py b/artiq/applets/plot_xy.py index bb3eab388..3838ce345 100755 --- a/artiq/applets/plot_xy.py +++ b/artiq/applets/plot_xy.py @@ -19,16 +19,16 @@ class XYPlot(pyqtgraph.PlotWidget): 'Error bars': False, 'Fit values': False} - def data_changed(self, data, mods, title): + def data_changed(self, value, metadata, persist, mods, title): try: - y = data[self.args.y][1] + y = value[self.args.y] except KeyError: return - x = data.get(self.args.x, (False, None))[1] + x = value.get(self.args.x, (False, None)) if x is None: x = np.arange(len(y)) - error = data.get(self.args.error, (False, None))[1] - fit = data.get(self.args.fit, (False, None))[1] + error = value.get(self.args.error, (False, None)) + fit = value.get(self.args.fit, (False, None)) if not len(y) or len(y) != len(x): self.mismatch['X values'] = True From 6c588b83d78c53318eff7b26f18f8e6ca0d0009e Mon Sep 17 00:00:00 2001 From: Simon Renblad Date: Wed, 12 Jul 2023 12:05:16 +0800 Subject: [PATCH 65/68] plot_xy_hist: refactor data_changed --- artiq/applets/plot_xy_hist.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/artiq/applets/plot_xy_hist.py b/artiq/applets/plot_xy_hist.py index 82c06d778..7d42aeacc 100755 --- a/artiq/applets/plot_xy_hist.py +++ b/artiq/applets/plot_xy_hist.py @@ -124,11 +124,11 @@ class XYHistPlot(QtWidgets.QSplitter): return False return True - def data_changed(self, data, mods): + def data_changed(self, value, metadata, persist, mods): try: - xs = data[self.args.xs][1] - histogram_bins = data[self.args.histogram_bins][1] - histograms_counts = data[self.args.histograms_counts][1] + xs = value[self.args.xs] + histogram_bins = value[self.args.histogram_bins] + histograms_counts = value[self.args.histograms_counts] except KeyError: return if len(xs) != histograms_counts.shape[0]: From 068a2d1663645a1d34bac8c317eda8b87fbea9db Mon Sep 17 00:00:00 2001 From: Simon Renblad Date: Wed, 12 Jul 2023 12:06:29 +0800 Subject: [PATCH 66/68] progress_bar: refactor data_changed --- artiq/applets/progress_bar.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/artiq/applets/progress_bar.py b/artiq/applets/progress_bar.py index f7eed5c9e..b25d380d8 100644 --- a/artiq/applets/progress_bar.py +++ b/artiq/applets/progress_bar.py @@ -12,12 +12,12 @@ class ProgressWidget(QtWidgets.QProgressBar): self.setMaximum(args.max) self.dataset_value = args.value - def data_changed(self, data, mods): + def data_changed(self, value, metadata, persist, mods): try: - value = round(data[self.dataset_value][1]) + val = round(value[self.dataset_value]) except (KeyError, ValueError, TypeError): - value = 0 - self.setValue(value) + val = 0 + self.setValue(val) From 9f8bb6445ff1956f5605bff42ef59dcd2baf8b89 Mon Sep 17 00:00:00 2001 From: Simon Renblad Date: Wed, 12 Jul 2023 12:31:03 +0800 Subject: [PATCH 67/68] RELEASE_NOTES: add breaking change data_changed signature --- RELEASE_NOTES.rst | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/RELEASE_NOTES.rst b/RELEASE_NOTES.rst index 93a36612a..242a917fa 100644 --- a/RELEASE_NOTES.rst +++ b/RELEASE_NOTES.rst @@ -48,6 +48,26 @@ Breaking changes: * ``SimpleApplet`` now calls widget constructors with an additional ``ctl`` parameter for control operations, which includes dataset operations. It can be ignored if not needed. For an example usage, refer to the ``big_number.py`` applet. +* ``SimpleApplet`` and ``TitleApplet`` now call ``data_changed`` with additional parameters. Wrapped widgets + should refactor the function signature as seen below: +:: + + # SimpleApplet + def data_changed(self, value, metadata, persist, mods) + # SimpleApplet (old version) + def data_changed(self, data, mods) + # TitleApplet + def data_changed(self, value, metadata, persist, mods, title) + # TitleApplet (old version) + def data_changed(self, data, mods, title) + +Old syntax should be replaced with the form shown on the right. +:: + + data[key][0] ==> persist[key] + data[key][1] ==> value[key] + data[key][2] ==> metadata[key] + ARTIQ-7 From d73889fb27d9bfcfa1c9bc07e39f6dc12c470234 Mon Sep 17 00:00:00 2001 From: Florian Agbuya Date: Fri, 14 Jul 2023 15:12:43 +0800 Subject: [PATCH 68/68] gui/experiments: cast Qt timestamp to int preventing float type error --- artiq/dashboard/experiments.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/dashboard/experiments.py b/artiq/dashboard/experiments.py index 3c9d5edac..8a0da9fd0 100644 --- a/artiq/dashboard/experiments.py +++ b/artiq/dashboard/experiments.py @@ -268,7 +268,7 @@ class _ExperimentDock(QtWidgets.QMdiSubWindow): datetime.setDate(QtCore.QDate.currentDate()) else: datetime.setDateTime(QtCore.QDateTime.fromMSecsSinceEpoch( - scheduling["due_date"]*1000)) + int(scheduling["due_date"]*1000))) datetime_en.setChecked(scheduling["due_date"] is not None) def update_datetime(dt):